5

I have this file and fd: exec 88<>abc

Why

$ sed -i "s/cd/II/g" /proc/$$/fd/88
sed: couldn't open temporary file /proc/26194/fd/sedS1D1FT: No such file or directory

but this work:

$ cat /proc/self/fd/88 | sed  "s/cd/II/g" 
abIIefg

And then this doesn't work:

$ (cat /proc/self/fd/88 | sed  "s/cd/II/g")  > /proc/self/fd/88

this causes /proc/self/fd/88 to become empty

2

2 Answers 2

6

sed -i does not actually edit the file "in-place", ever; it works by redirecting its output to a temporary file, then renaming/moving the temporary file to the original.

That makes sure that the original file is not lost in case something goes wrong mid-way.

To make things worse, sed (just like vim) tries to create the temporary file in the same directory as the original.

The /proc filesystem is synthetic, you cannot just create or move files inside it; that's why you're getting that error. But even if sed was creating the temporary file in /tmp, the last operation (the renaming of the temporary file to the original) would still fail.

You can try to do what sed -i does in a round-about manner:

$ ised(){ for a; do :; done; t=`mktemp` && sed "$@" > "$t" && cat "$t" > "$a" && rm "$t"; }
$ ised s/cd/II/g /proc/$$/fd/88

The filename should always be the last argument to ised.

This breaks the consistency guarantee of sed -i; the cat in > out operation, unlike rename("in", "out"), is not atomic; if stopped in the middle, the out file will be truncated.

1

Assuming the actual file still exists, this might work better, (but use with caution since it would modify an actual file):

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

As mosvy notes, this will not work if the result of realpath /proc/$$/fd/88 was already deleted. Example:

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

Output (even though /tmp/junk doesn't exist), 1st line to STDOUT, 2nd line to STDERR:

yes
cat: '/tmp/junk (deleted)': No such file or directory
3
  • Using sed -i implies that you want to modify an actual file, what do you mean with that word of caution? Nov 8, 2018 at 15:54
  • 1
    This will not work if the "realpath" of /proc/$$/fd/88 was already deleted. Example: exec 7>/tmp/junk; echo yes >&7; rm /tmp/junk; cat /proc/$$/fd/7; cat "$(realpath "/proc/$$/fd/7")"
    – user313992
    Nov 8, 2018 at 16:01
  • @StéphaneChazelas, the OP's understanding of /proc/$$/fd was inaccurate, and might benefit from reinforcement.
    – agc
    Nov 8, 2018 at 19:10

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .