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

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 mv 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
  • Using sed -i implies that you want to modify an actual file, what do you mean with that word of caution? – Stéphane Chazelas Nov 8 '18 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")" – mosvy Nov 8 '18 at 16:01
  • @StéphaneChazelas, the OP's understanding of /proc/$$/fd was inaccurate, and might benefit from reinforcement. – agc Nov 8 '18 at 19:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.