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

为什么 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变空

答案1

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

文件名应该始终是ised.

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

答案2

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

sed -i s/cd/II/g "$(realpath "/proc/$$/fd/88")"

作为莫斯维笔记,如果 的结果realpath /proc/$$/fd/88已被删除,则此操作将不起作用。例子:

exec 7>/tmp/junk; echo yes >&7; rm /tmp/junk; 
cat /proc/$$/fd/7; cat "$(realpath "/proc/$$/fd/7")"

输出(尽管/tmp/垃圾不存在),第一行标准输出, 第 2 行到标准错误错误率:

yes
cat: '/tmp/junk (deleted)': No such file or directory

相关内容