次のデータセットが終了するまで、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
答え2
アプローチの問題は、ブロックprint
に文が1つしかないことですEND
。このブロックの値は$0
ファイルの最後の行の内容です。したがって、awk
コードはファイルの最後の行だけを印刷します。
また、awk
タスクを次に適用することに注意してください。各ラインブロックの前に条件がない場合{ ... }
(たとえば、END
ファイルの終わりにのみ適用されます)、したがってコードは最初、3番目などを確認しようとします。大地~の各ラインまたはなら、3
それぞれまたはに置き換えてください4
。ただし、結果は印刷しないでください。0
1
すべての奇数行にルールを適用するには、その行がNR%2
1であるか(単にゼロではない)かを確認できます。
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