With GNU cp on Linux, the commands
cp <( ( echo foo; sleep 1; echo bar) | sponge ) foobar
cp =( ( echo foo; sleep 1; echo bar) | sponge ) foobar
both have the same result: the file "foobar" containing the string "foo\nbar\n".With GNU cp on Linux, the commands
cp <( ( echo foo; sleep 1; echo bar) | sponge ) foobar
cp =( ( echo foo; sleep 1; echo bar) | sponge ) foobar
both have the same result: the file "foobar" containing the string "foo\nbar\n".Here's a better (but awkward) illustration of the problem:
:~$ python3 -c 'import sys; import shutil; shutil.copy(sys.argv[1], "foobar")' <
(echo foo ; sleep 1 ; echo bar)
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "/opt/homebrew/Cellar/python@3.9/3.9.9/Frameworks/Python.framework/Versions/3.9/lib/python3.9/shutil.py", line 427, in copy
copyfile(src, dst, follow_symlinks=follow_symlinks)
File "/opt/homebrew/Cellar/python@3.9/3.9.9/Frameworks/Python.framework/Versions/3.9/lib/python3.9/shutil.py", line 257, in copyfile
raise SpecialFileError("`%s` is a named pipe" % fn)
shutil.SpecialFileError: `/dev/fd/11` is a named pipe
:~$ python3 -c 'import sys; import shutil; shutil.copy(sys.argv[1], "foobar")' =(echo foo ; sleep 1 ; echo bar)
Notice the difference: :~$ echo =(echo foo ; sleep 1; echo bar)
/tmp/zshbusU5D
:~$ echo <(echo foo ; sleep 1; echo bar)
/dev/fd/11
/dev/fd/11 is a named pipe, whereas /tmp/zshbEF1D9 is a plain file. There are situations where named pipes fail, where you actually do need a plain file, and I can't think of a single one offhand. :)"I've run into it in the past" is all I can say. And the above snippet at least gives one specific example of a hypothetical case.
My go-to use-case for =() is
okular =(dot -Tpdf foo.dot)
PDF-viewers and its ilk typically don't work on non-files.In general: If the command you are passing the named pipe to expects a file which it can randomly access, a named pipe won’t work.
I ran into this today using a python tool, yamldiff. I was trying to diff a local yaml file with one from a cluster obtained via kubectl, eg:
yamldiff localManifest.yaml <(kubectl get … —output yaml)
and it failed with python telling me the file wasn’t seekable. Then I remembered this thread which I had initially read a few days ago and tried =() (since I use shell) — and it worked!