awk for ループを使用して特定の行の値を変更する

awk for ループを使用して特定の行の値を変更する

次のデータセットが終了するまで、1行、3行、5行などのすべてのフィールドで、値3と4をそれぞれ0と1に置き換えたいと思います。

 2 4 3 0
 2 4 3 0
 3 0 4 4
 3 0 4 4
 4 2 4 3
 4 2 4 3
 2 3 4 2
 2 3 4 2

したがって、望ましい結果は次のとおりです。

 2 1 0 0
 2 4 3 0
 0 0 1 1
 3 0 4 4
 1 2 1 0
 4 2 4 3
 2 0 1 2
 2 3 4 2

これを行うには、次のコードを使用しています。

awk '{for (i = 1; i <= NR; i=(i+2)) 
    if($i == 3) {$i = 0}
    if($i == 4) {$i = 1} 
}
END {print $0}' b.temp

ただし、このコードの出力は、b.tempファイルの最後の行(2 3 4 2)の値のみです。

どうすればいいですか?コードは行数とフィールド数に制限がないはずです。解決策は、awk、sed、またはシェルスクリプトの他の代替方法です。

事前にありがとう

答え1

sedを使用してください:

sed 'y/34/01/;n' file

意味は次のとおりです

  • この行の3と4を0と1に置き換えて印刷します。
  • 次の行をインポートして印刷します。
  • 次の行を取得してループを繰り返します。

ただし、データに(たとえば14)が含まれている場合、11に変換すると失敗します。この問題を解決するには、次を選択してください。

sed 's/\<4\>/1/g;s/\<3\>/0/g;n' file

これらの\<andは\>単語の始まりと終わりに一致します。

答え2

アプローチの問題は、ブロックprintに文が1つしかないことですEND。このブロックの値は$0ファイルの最後の行の内容です。したがって、awkコードはファイルの最後の行だけを印刷します。

また、awkタスクを次に適用することに注意してください。各ラインブロックの前に条件がない場合{ ... }(たとえば、ENDファイルの終わりにのみ適用されます)、したがってコードは最初、3番目などを確認しようとします。大地~の各ラインまたはなら、3それぞれまたはに置き換えてください4。ただし、結果は印刷しないでください。01

すべての奇数行にルールを適用するには、その行がNR%21であるか(単にゼロではない)かを確認できます。

awk 'NR%2{for (i=1;i<=NF;i++) if ($i==3 || $i==4) $i-=3}1' b.temp

1ルールの外側に表示されると、awk「実行されたすべての変換の結果行を印刷します」を減らして表示します。

答え3

私が試したより最適化されたコマンドは次のとおりです。

注文する

awk 'NR==1||NR==3||NR==5||NR==7{gsub("3","0",$0)}1' file | awk 'NR==1||NR==3||NR==5||NR==7{gsub("4","1",$0)}1'

出力

 2 1 0 0
 2 4 3 0
 0 0 1 1
 3 0 4 4
 1 2 1 0
 4 2 4 3
 2 0 1 2
 2 3 4 2

関連情報