sedが出力ファイルによって異なる動作をするのはなぜですか?

sedが出力ファイルによって異なる動作をするのはなぜですか?

私が実行した場合:

cat messages.txt | sed -e 's/a/a/g' > messages.txt

大きなファイル(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

答え1

ベルシュミットの答えsed を使用する場合に最適です。しかし、より一般的な意味では、次のようなアンチパターンがあります。

cat infile | filter > infile

多くの問題が発生する可能性があります。たとえば、次のファイルがあるとしますinfile

Hello
World

そして、次のコマンドを実行してください。

cat infile | tr "[:upper:]" "[:lower:]"

わかりました。

hello
world

ただし、実行すると空のcat infile | tr "[:upper:]" "[:lower:]" > infileファイルが表示されます。なぜ?

まあ、出力リダイレクト演算子を使用すると、>「私の標準出力をこのファイルに入れ、ファイルが存在する場合は上書きされます」と言うことです。これでフィルタリングのためにこれがうまくいくはずだと思うかもしれません。コンパイラは元のすべての行を返します。ファイル。しかし、しばしば起こるのは、シェルが行を読み取る前にファイルを破損することです。その後、フィルタコマンドは空のファイルから行を読み込み、何も見つからないため、なしを返します。いくつかの場所では、ファイルが破損する前にいくつかの行を読むのに十分な「幸運」があるかもしれませんが、このパターンを完全に避けるのが最善です。

この特定の問題を解決するには、いくつかのオプションがあります。一つは、単に以下を行うことです。

cat infile | filter > tmpfile; mv tmpfile infile

一時ファイルが他のファイルを破損させたり、他の不快なことをしないようにする必要がある場合は、確認してください(およびmktemp参照)。man mktempinfo coreutils mktemp

もう1つのオプションは、以下spongeで使用することです。その他のユーティリティ

さらに、これらの例の多くは猫に役に立たない用途

答え2

ただ書くのはどうですか?

sed -i -e 's/a/a/g' messages.txt

-i は「所定の位置に」を意味します。

答え3

ファイルを適切に編集するもう1つの(移植可能な)方法はを使用することです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

答え4

ExモードでVimを使用できます。

ex -sc '%s/OLD/NEW/g|x' messages.txt
  1. %すべての行を選択

  2. s変える

  3. gグローバル交換

  4. x保存して閉じる

関連情報