web-dev-qa-db-ja.com

sed-iが/ proc / PID / fd / FDで機能しないのはなぜですか

私はこのファイルと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空になる

5
Bob Johnson

_sed -i_は、実際にはファイルを「インプレース」で編集しません。出力を一時ファイルにリダイレクトしてから、一時ファイルの名前を変更するか、一時ファイルを元のファイルに移動します。

これにより、途中で問題が発生した場合に元のファイルが失われることがなくなります。

さらに悪いことに、sedvimと同様)は、元のファイルと同じディレクトリに一時ファイルを作成しようとします。

_/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ファイルは切り捨てられます。

6
mosvy

実際のファイルがまだ存在していると仮定すると、これはより適切に機能する可能性があります(ただし、実際のファイルを変更するため、注意して使用してください)。

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
1
agc