¿Por qué hay un "/ dev / fd / 63" en la salida de "echo 123> (cat)"?

echo 123 | cat 123 

está haciendo lo que esperaba, ambos commands se ejecutan dentro del mismo shell.

pero cuando los conecto con el

> (…) Expresión

que conecta la salida de un command en el shell a un segundo en una subshell, obtengo esto:

 echo 123 >(cat) 123 /dev/fd/63 

esto también es cierto con otros valores:

 echo 101 >(cat) 101 /dev/fd/63 echo $BASHPID >(cat) 3252 /dev/fd/63 

Pensé que command1> (command2) es lo mismo que command1 | command2 , pero con la diferencia, que en command1> (command2) cada command está dentro de un shell diferente, por lo tanto, deberían tener el mismo resultado, ¿dónde estoy equivocado?

La sustitución de process >(thing) será reemplazada por un nombre de file. Este nombre de file corresponde a un file que está conectado a la input estándar de la thing dentro de la sustitución.

El siguiente sería un mejor ejemplo de su uso:

 $ sort -o >(cat -n >/tmp/out) ~/.profile 

Esto orderaría el file ~/.profile y enviaría la salida a cat -n que enumeraría las líneas y almacenaría el resultado en /tmp/out .

Entonces, para responder a su pregunta: Obtiene esa salida porque echo obtiene los dos arguments 123 y /dev/fd/63 . /dev/fd/63 es el file conectado a la input estándar del process cat en la sustitución del process.

Modificando su código de ejemplo levemente:

 $ echo 101 > >(cat) 

Esto produciría solo 101 en salida estándar ( echo escribiría en el file que sirve como input para cat , y cat produciría el contenido de ese file en salida estándar).


También tenga en count que en el cmd1 | cmd2 cmd1 | cmd2 pipeline, cmd2 puede que no se ejecute en el mismo shell que cmd1 (dependiendo de la implementación de shell que esté utilizando). ksh93 funciona de la manera que describes (mismo shell), mientras que bash crea una subshell para cmd2 .

Como eso es lo que hace la sustitución de processs , hace que el command dentro de la sustitución aparezca como un nombre de file. Internamente, conecta los commands a través de una tubería, dando la ruta /dev/fd/NN al command principal, por lo que puede abrir el descriptor de file ya abierto a la tubería.

No es lo mismo que una tubería. Las tuberías conectan stdout a stdin sin involucrar nada que se parezca a los nombres de file. La sustitución de processs es más flexible, ya que puede tener varias de estas sustituciones en una línea de command, pero requiere el command principal para abrir files por nombre (por ejemplo, cat lugar de echo ).

Puede emular una tubería con sustitución de process haciendo algo como esto:

 echo foo > >(cat -n) 

Por completitud

 cmd1 >(cmd2) 

es casi lo mismo que

 cmd1 | cmd2 

en el caparazón yash , y solo ese caparazón.

En ese shell, >(cmd) es una networkingirección de processs en lugar de >(cmd) de ksh / bash / zsh que es la sustitución de processs.

No es estrictamente equivalente, porque en cmd1 >(cmd2) , yash no espera a cmd2 , por lo que puede encontrar que:

 $ yash -c 'echo A >(cat); echo B' B A $ yash -c 'echo A | cat; echo B' A B 

Por el contrario, la sustitución de processs se expande a una ruta de file (típicamente una tubería con nombre o una /dev/fd/<x> donde <x> es una fd a una tubería que se ha creado de antemano) que, cuando se abre para escritura, permite enviar salida a cmd .

Si bien la sustitución del process fue introducida por ksh , en ese shell, no se puede pasar como argumento a las networkingirecciones.

 ksh -c 'cmd1 > >(cmd2)' 

emular la yash process yash no funcionará. Allí, debes pasar ese nombre de file que resulta de la sustitución como argumento a un command como en:

 ksh -c 'diff <(echo a) <(echo b)' 

Funcionará en bash y zsh .

Sin embargo, en bash like para la networkingirección de process de yash , el shell no espera el command ( cmd2 ). Asi que:

 $ bash -c 'echo A > >(cat); echo B' B A 

ksh sustitución del process ksh se puede emular con yash con:

 cmd1 /dev/fd/5 5>(cmd2) 

Me gusta:

 diff /dev/fd/3 3<(echo a) /dev/fd/4 4<(echo b) 
 $ echo 1 >(cat > /dev/null) 1 /dev/fd/63 $ echo echo >(cat /dev/null) echo /dev/fd/63 # We can trace how the commands are executed # so long as we avoid using shell builtin commands, # and run the equivalent external program instead, ie /usr/bin/echo $ strace -f -e execve bash -c '/usr/bin/echo >(cat /dev/null)' execve("/usr/bin/bash", ["bash", "-c", "/usr/bin/echo >(cat /dev/null)"], [/* 56 vars */]) = 0 strace: Process 4213 attached [pid 4212] execve("/usr/bin/echo", ["/usr/bin/echo", "/dev/fd/63"], [/* 56 vars */]) = 0 strace: Process 4214 attached [pid 4214] execve("/usr/bin/cat", ["cat", "/dev/null"], [/* 56 vars */]/dev/fd/63 ) = 0 [pid 4212] +++ exited with 0 +++ [pid 4214] +++ exited with 0 +++ --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=4214, si_uid=1001, si_status=0, si_utime=0, si_stime=0} --- +++ exited with 0 +++ # Apparently, the order of evaluation is arranged so this works nicely: $ echo 1 > >(cat > /dev/null) $