コンマで区切られた 4 列のテキスト ファイルがあります。ループで各レコードを読み込んでいるので、条件によっては5列目に値を追加したい。行番号と列番号がわかっている場合、awk/sedコマンドを使用して、一時ファイルを使用せずにその特定のフィールドの値を置換/設定するにはどうすればよいですか? 読み込んでいるファイルを(直接)更新したい
inp.txt
a,b,c,d
e,f,g,h
i,j,k,l
ありがとう、-sri
awk
またはを使用してファイルを直接編集することはできませんsed
。一部のバージョンにsed
は、一時ファイルを処理して元のファイルを上書きするオプション(-i
)がありますが、実際にはその場でファイルを編集しません。これは大したことではありません。ただ行う:
$ awk 'NR==5{ $(NF+1) = "new value"}1' OFS=, FS=, input-file > tmp.$$
$ mv tmp.$$ input-file
の行5に新しい列を追加しますinput-file
。必要に応じて、を使用ed
してファイルを編集できますが、一時ファイルを使用する方が理にかなっています。一時ファイルを使用していないふりをしたい場合で、sedがをサポートしている-i
場合は、次の方法で同じことを行うことができます。
sed -i '5s/$/,new value/' input-file
ほとんどのユーティリティではファイルのインプレース変更は許可されていませんが、次のsh
関数のいずれかを使用して、一時ファイルを使用してその動作をエミュレートするのは簡単です。
edit() { local f=$1; shift; "$@" < $f > $f.$$ && mv $f.$$ $f; } # Break hard links
edit() { local f=$1; shift; "$@" < $f > $f.$$ && cat $f.$$ > $f && rm $f.$$; }
これらのいずれかを使用すると、を使用awk
してファイルをインプレースで編集しているように見せることができますedit filename awk awk-cmds
。最初のバージョンはハードリンクを切断しますが、使用するIOはわずかに少なくなります。
sed について話すことはできませんが、awk の目的はファイルをその場で編集することではなく、stdout に書き込むことです。
とにかく、これはループを必要としない解決策です。条件は、列 4 のエントリが h であるというふりをしています。
awk -F ',' '{ if ($4 == "h") print $0",z"; else print $0","}' inp.txt > out.txt
出力:
a,b,c,d,
e,f,g,h,z
i,j,k,l,
perl -i -F, -lane 'if($.==<row number>){$F[<column_number>-1]+=<add your stuff here>}print join(",",@F)' your_file
以下でテスト済み:
>cat temp
b,c,d,g
r,g,d,s
2行目の3列目を変更するために実行します。
>perl -i -F, -lane 'if($.==2){$F[2]=10}print join(",",@F)' temp
> cat temp
b,c,d,g
r,g,10,s
こんな感じですか?これは、一時ファイルを使用しないバージョンです。
[a@b ~]$ cat tmp | sed 's_^\(.*\),\(.*\),\(.*\),\(.*\)_\1,\2,\3,\4_g'
inp.txt
a,b,c,d
e,f,g,h
i,j,k,l
[a@b ~]$ cat tmp | sed 's_^\(.*\),\(.*\),\(.*\),\(.*\)_\1,sth,\3,\4_g'
inp.txt
a,sth,c,d
e,sth,g,h
i,sth,k,l
[a@b ~]$ sed -ie 's_^\(.*\),\(.*\),\(.*\),\(.*\)_\1,sth,\3,\4_g' tmp
[a@b ~]$ cat tmp
inp.txt
a,sth,c,d
e,sth,g,h
i,sth,k,l
乾杯、