私が実行した場合:
cat messages.txt | sed -e 's/a/a/g' > messages.txt
1つの大きなファイル(2500行以上)で、結果のファイルはcygwinのコマンドの後に約900行しかなく、gentooの行はありません。しかし、私が実行した場合
cat messages.txt | sed -e 's/a/a/g' > other_messages.txt
すべての行を適切に保持します。
私の質問はなぜですか、それ以外の方法はありますか
cat messages.txt | sed -e 's/a/a/g' > other_messages.txt
rm messages.txt
mv other_messages.txt messages.txt
書いてみませんか
sed -i -e 's/a/a/g' messages.txt
-iは「インプレース」を意味します
fschmittの答え sedを使用する場合に最適です。ただし、より一般的な意味では、このアンチパターンは次のとおりです。
cat infile | filter > infile
かなりの数の問題を引き起こす可能性があります。たとえば、次のようなinfile
というファイルがある場合:
Hello
World
次のコマンドを実行します。
cat infile | tr "[:upper:]" "[:lower:]"
私は得る
hello
world
しかし、私が実行した場合cat infile | tr "[:upper:]" "[:lower:]" > infile
空のファイルを取得します。どうして?
さて、あなたが出力リダイレクト演算子を使用するとき>
「標準出力をこのファイルに入れ、そのファイルが存在する場合は上書きしてください」と言っています。フィルタは元のファイルのすべての行を返すので、これでうまくいくと思うかもしれません。ただし、多くの場合、最終的に発生するのは、行が読み取られる前にシェルがファイルを上書きすることです。次に、filterコマンドは、空のファイルから行を読み取り、何も検出しないため、何も返しません。いくつかの場所では、ファイルが壊れる前にいくつかの行を読み取らせるのに十分な「幸運」になるかもしれませんが、このパターンを完全に回避するのが最善です。
この特定の問題を回避するには、いくつかのオプションがあります。 1つは、次のようなことを行うだけです。
cat infile | filter > tmpfile; mv tmpfile infile
一時ファイルが他のファイルを壊したり、他の厄介なことが起こったりしないことを確認する必要がある場合は、mktemp
を調べる必要があります。 (見る man mktemp
およびinfo coreutils mktemp
)
別のオプションは、 moreutils からsponge
を使用することです。
また、これらの例の多くは catの無用な使用 の例です。
ファイルをインプレースで編集するさらに別の(ポータブルな)方法は、ed
を使用することです。
# cf. http://wiki.bash-hackers.org/howto/edit-ed
cat <<-'EOF' | ed -s messages.txt
H
,g/a/s//b/g
wq
EOF
# ... or read the file contents into a variable, modify it and write it back to file
file_contents="$(cat messages.txt)"
printf '%s' "$file_contents" | sed -e 's/a/b/g' > messages.txt
# ... and, if you want to play around with a file descriptor hack, ...
# (As long as there's a fd associated with a file, the file can be accessed via the fd.)
exec 3<messages.txt # open file on fd 3 for reading
rm -f messages.txt
sed -e 's/a/b/g' <&3 > messages.txt
ExモードでVimを使用できます:
ex -sc '%s/OLD/NEW/g|x' messages.txt
%
すべての行を選択
s
代替
g
グローバル置換
x
保存して閉じる