私はこのファイルとfdを持っています:exec 88<>abc
なぜ
$ sed -i "s/cd/II/g" /proc/$$/fd/88
sed: couldn't open temporary file /proc/26194/fd/sedS1D1FT: No such file or directory
しかし、この作品:
$ cat /proc/self/fd/88 | sed "s/cd/II/g"
abIIefg
そして、これは機能しません:
$ (cat /proc/self/fd/88 | sed "s/cd/II/g") > /proc/self/fd/88
これは〜をひき起こす /proc/self/fd/88
空になる
_sed -i
_は、実際にはファイルを「インプレース」で編集しません。出力を一時ファイルにリダイレクトしてから、一時ファイルの名前を変更するか、一時ファイルを元のファイルに移動します。
これにより、途中で問題が発生した場合に元のファイルが失われることがなくなります。
さらに悪いことに、sed
(vim
と同様)は、元のファイルと同じディレクトリに一時ファイルを作成しようとします。
_/proc
_ファイルシステムはsyntheticです。ファイルを作成したり移動したりすることはできません。そのため、エラーが発生します。ただし、sed
が_/tmp
_で一時ファイルを作成していたとしても、最後の操作(一時ファイルの元のファイルへの名前変更)は失敗します。
_sed -i
_が行うことをラウンドアバウトで行うことができます。
_$ ised(){ for a; do :; done; t=`mktemp` && sed "$@" > "$t" && cat "$t" > "$a" && rm "$t"; }
$ ised s/cd/II/g /proc/$$/fd/88
_
ファイル名は常にised
の最後の引数である必要があります。
これにより、_sed -i
_の整合性保証が破られます。 _cat in > out
_操作は、rename("in", "out")
とは異なり、アトミックではありません。途中で停止した場合、out
ファイルは切り捨てられます。
実際のファイルがまだ存在していると仮定すると、これはより適切に機能する可能性があります(ただし、実際のファイルを変更するため、注意して使用してください)。
sed -i s/cd/II/g "$(realpath "/proc/$$/fd/88")"
mosvynotes として、realpath /proc/$$/fd/88
の結果がすでに削除されている場合は機能しません。例:
exec 7>/tmp/junk; echo yes >&7; rm /tmp/junk;
cat /proc/$$/fd/7; cat "$(realpath "/proc/$$/fd/7")"
出力(/ tmp/junkが存在しない場合でも)、[〜#〜] stdoutへの1行目[〜#〜]、2行目から[〜#〜] stderr [〜#〜]:
yes
cat: '/tmp/junk (deleted)': No such file or directory