为什么 sed -i 不能与 /proc/PID/fd/FD 一起使用

Bob*_*son 5 linux shell sed io-redirection file-descriptors

我有这个文件和 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
Run Code Online (Sandbox Code Playgroud)

但这项工作:

$ cat /proc/self/fd/88 | sed  "s/cd/II/g" 
abIIefg
Run Code Online (Sandbox Code Playgroud)

然后这不起作用:

$ (cat /proc/self/fd/88 | sed  "s/cd/II/g")  > /proc/self/fd/88
Run Code Online (Sandbox Code Playgroud)

这导致/proc/self/fd/88变空

mos*_*svy 6

sed -i从来没有真正“就地”编辑文件;它的工作原理是将其输出重定向到一个临时文件,然后将临时文件重命名/移动到原始文件。

这样可以确保在中途出现问题时不会丢失原始文件。

更糟糕的是,sed(就像vim)试图在与原始文件相同的目录中创建临时文件。

/proc文件系统是合成的,你不能只是创建或移动里面的文件; 这就是为什么你会收到那个错误。但是即使在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
Run Code Online (Sandbox Code Playgroud)

文件名应始终是ised.

这打破了sed -i;的一致性保证。的cat in > out操作,不象rename("in", "out"),不是原子; 如果中途停止,out文件将被截断。


agc*_*agc 1

假设实际文件仍然存在,这可能会更好,(但请谨慎使用,因为它会修改实际文件):

sed -i s/cd/II/g "$(realpath "/proc/$$/fd/88")"
Run Code Online (Sandbox Code Playgroud)

正如mosvy所指出的realpath /proc/$$/fd/88,如果 的结果已被删除,则此操作将不起作用。例子:

exec 7>/tmp/junk; echo yes >&7; rm /tmp/junk; 
cat /proc/$$/fd/7; cat "$(realpath "/proc/$$/fd/7")"
Run Code Online (Sandbox Code Playgroud)

输出(即使/tmp/junk不存在),第一行到STDOUT,第二行到STDERR

yes
cat: '/tmp/junk (deleted)': No such file or directory
Run Code Online (Sandbox Code Playgroud)