2

次の awk 行を使用して、テキスト ファイル内のすべての偶数行を削除 (および奇数行を保持) したいと考えています。

awk 'NR%2==1' filename.txt > output

問題は、awk で適切にループするか、シェル スクリプトを作成してこれをフォルダー内のすべての *.txt ファイルに適用するのに苦労していることです。このワンライナーを使ってみました

gawk 'FNR==1{if(o)close(o);o=FILENAME;
sub(/\.txt/,"_oddlines.txt",o)}{NR%2==1; print>o}'  

しかし、それは偶数行を削除しませんでした。また、シェル スクリプトについてもあまり詳しくありません。私はgawkwin7またはcygwin一緒に使用しbashます。あらゆる種類のアイデアに感謝します。

4

5 に答える 5

3

既存の gawk ワンライナーは本当に近いです。ここでは、より読みやすいスクリプトとしてフォーマットされています。

FNR == 1 {
    if (o)
        close(o)
    o = FILENAME
    sub(/\.txt/, "_oddlines.txt", o)
}
{
    NR % 2 == 1
    print > o
}

これにより、エラーが明らかになるはずです1。したがって、そのエラーを削除します。

FNR == 1 {
    if (o)
        close(o)
    o = FILENAME
    sub(/\.txt/, "_oddlines.txt", o)
}
NR % 2 == 1 {
    print > o
}

$ awk -f foo.awk *.txt

そしてそれは機能します(もちろん、これを再1行化できます)。

(通常、私はfor他の回答と同じようにこれを行いますが、あなたがどれだけ近いかを見せたかったのです!)


1コメントごとに、あまり明白ではないかもしれません?

Awk の基本的な言語構造は、「パターン アクション」ステートメントです。awkプログラムは、そのようなステートメントの単なるリストです。「パターン」の名前は、もともとほとんどが grep のような正規表現パターンだったためです。

$ awk '/^be.*st$/' < /usr/share/dict/web2
beanfeast
beast
[snip]

(スラッシュを除いて、これは基本的に単に runningです。grepこれは、デフォルトのアクション を使用するためですprint。)

パターンには実際には 2 つのアドレスを含めることができますが、これらの場合のように 1 つを使用する方が一般的です。スラッシュで囲まれていないパターンでは、 FNR == 1(ファイルF固有NのこのRレコードの数が等しい1) またはNR % 2 == 1(NこのRレコードの数 - すべてのファイルで累積! - mod2が等しい1) のようなテストが可能です。

ただし、開き括弧を押すと、「アクション」部分に入ります。NR % 2 == 1単純に結果 (true または false) を計算し、それを破棄します。「パターン」部分を完全に省略すると、「アクション」部分がすべての入力行で実行されます。したがって、これはすべての行を出力します。

NR % 2 == 1テストは累積レコード番号をテストしていることに注意してください。したがって、あるファイルの行数 (「レコード」) が奇数の場合、次のファイルは偶数行ごとに出力されます (これは、行数が奇数の別のファイルにヒットするまで持続します)。

たとえば、2 つの入力ファイルがA.txtと であるとしB.txtます。awk は読み取りを開始し、最初の行で と のA.txt両方FNRを1 に設定します。最初の「アクション」が行われるので、設定. 次に、awk は 2 番目のパターンをテストします。 は 1 です。したがって、2 番目の「アクション」が実行され、その行が に出力されます。NRfile A, line 1FNR == 1oNRNR % 2A_oddlines.txt

ここで、ファイルA.txtにその 1 行だけが含まれているとします。awk は file に進みB.txt、リセットしますが、累積的なFNRままになります。NRの最初の行Bfile B, line 1. Awk は最初の「パターン」を試行します。実際、FNR == 1これにより古いパターンが閉じoられ、新しいパターンが設定されます。

しかし、NRすべての入力ファイルにわたって累積さ2れるためです。そのため、2 番目のパターン ( )は (どちらが であるか) を計算し、どちらが false であるかを比較するため、awk は file の 1 行目の 2 番目の「アクション」をスキップします。行 2 が存在する場合は、andがあるため、その行がコピーされます。NRNR % 2 == 12 % 20== 1B.txtFNR == 2NR == 3

(私は当初、あなたのスクリプトがほぼ機能していたので、これを意図していて、構文に少し固執しているだけだと思っていました。)

于 2013-09-21T23:50:43.437 に答える
1

for ループを試すことができます:

#!/bin/bash

for file in dir/*.txt
do    
   oddfile=$(echo "$file" | sed -e 's|\.txt|_odd\.txt|g')  #This will create file_odd.txt
   awk 'NR%2==1' "$file" > "$oddfile"  # This will output it in the same dir.
done
于 2013-09-21T23:46:03.040 に答える
1

個人的には、私は使うだろう

for filename in *.txt; do
    awk 'NR%2==1' "$filename" > "oddlines-$filename"
done

編集:ファイル名を引用

于 2013-09-21T23:46:34.767 に答える
1

あなたの問題は、それNR%2==1{NR%2==1; print>o}「アクションブロック」内にあり、「条件」として開始されていないことです。代わりにこれを使用してください:

gawk 'FNR==1{if(o)close(o);o=FILENAME;sub(/\.txt/,"_oddlines.txt",o)};
     FNR%2==1{print > o}' *.txt
于 2013-09-21T23:47:45.420 に答える