The idiom >(...)
just means (in layman terms): "the name of a file".
And it works as a "name of a file" (sort of, all will be clear in an instant):
$ echo <(date)
/proc/self/fd/11
Or some other number/name on your OS. But echo does print a name, exactly as if you do:
$ echo ProcSubs11
ProcSubs11
And if a file with the label ProcSubs11 exists, you could also do:
$ cat ProcSubs11
contents_of_file_ProcSubs11
Which you could do exactly the same with:
$ cat <(date)
Fri Jan 15 21:25:18 UTC 2016
The difference is that the actual name of the "Process Substitution" is "not visible" and that the details are a lot longer than reading a simple file, as described quite well in all the painful detail in the link to How process substitution is implemented in bash?.
Having said the above, lets review your items.
Q 1
...seems operationally no different from a simple unnamed pipe...
Well, "Process Substitution" is exactly based in an unnamed pipe
as your given first link states:
- The bash process creates an unnamed pipe for communication between the two processes created later.
The difference is that all the ~6 steps explained in the link are simplified to one idiom >(...)
for writing to and <(...)
for reading from.
And, it could be argued that the connection (pipe) has a name, as a file has. Just that that name is hidden from the user (the /proc/self/fd/11
shown at the start).
Example 1
1) I add a pipe and redirection of shasum's output ...
$ cat file_{1,2,3} | tee file_4 | shasum -a 256 > file_4.sha256
There is no "Process Substitution" there, but it worth noting (for later) that tee
sends (writes to) what it receive in its stdin
to a file file_4
and also sends the same stdin
content to stdout
. Which happens to be connected to a pipe (in this case) that writes to shasum.
So, in short, in layman terms, tee copy stdin
to both file_4
and shasum
.
Example 2
2) I try the same with ProcSub:
$ cat file_{1,2,3} | tee file_4 >(shasum -a 256 > file_4.sha256)
Re-using the description above (in layman terms) to describe this example:
Tee copy stdin
to three elements: file_4
, shasum
and stdout
.
Why?. Remember that >(...)
is the name of a file, lets put that in the line:
$ cat file_{1,2,3} | tee file_4 /proc/self/fd/11
tee is serving the input to two files file_4
and shasum
(via "Process Substitution") and the stdout
of tee
is still connected to its default place: the console. That is why you see the numbers in the console.
To make this example exactly equal to 1), we could do:
$ cat file_{1,2,3} | tee file_4 > /proc/self/fd/11 ### note the added `>`
Which becomes (yes, the space between >
and >(
must be used.
$ cat file_{1,2,3} | tee file_4 > >(shasum -a 256 > file_4.sha256)
That is redirecting tee
's stdout to the "Process Substitution".
Q 3
Q: So the general question is: how are i/o processed for the 3 cases above
I believe I just did explain the 3 cases, if not clear, please comment.
Q 4 (in comments, Please edit and add the question)
why the <(...) construct won't work in the third case.
Because (in layman terms) you can not insert a male prong into a male socket.
The <(...) idiom reads from what is inside the "Process substitution" and therefore provides an "output" and should be inserted in the stdin
of the outside command. The outside command tee
is trying to connect stdout
(like) elements. So, that pair could not match.
An important note:
The command cat
hides some details when applied to "Process Substitution", as both this command will give the same output:
$ cat <(date)
$ cat < <(date)
All is correct, but drawing conclusions from a misleading equality is wrong.
Best Answer
First of all, do not use
ls
output as a file list. Use shell expansion orfind
. See below for potential consequences of ls+xargs misuse and an example of properxargs
usage.1. Simple way: for loop
If you want to process just the files under
A/
, then a simplefor
loop should be enough:2.pre1 Why not
ls | xargs
?Here's an example of how bad things may turn if you use
ls
withxargs
for the job. Consider a following scenario:first, let's create some empty files:
see the files and that they contain nothing:
run a magic command using
xargs
:the result:
So you've just managed to overwrite both
mypreciousfile.dat
andmypreciousfile.dat.ans
. If there were any content in those files, it'd have been erased.2. Using
xargs
: the proper way withfind
If you'd like to insist on using
xargs
, use-0
(null-terminated names) :Notice two things:
.dat.ans
ending;"
).Both issues can be solved by different way of shell invocation:
3. All done within
find ... -exec
This, again, produces
.dat.ans
files and will break if file names contain"
. To go about that, usebash
and change the way it is invoked: