¿Por qué `sort <(ls -l)` funciona pero `sort <(ls -l)` falla?

32

Hoy estoy aprendiendo algo sobre fifo con este artículo: Introducción a las tuberías con nombre , que menciona cat <(ls -l).

Hice algunos experimentos usando sort < (ls -l), lo que muestra un error:

-bash: syntax error near unexpected token `('`

Luego descubrí que había agregado un espacio extra en el comando.

Pero, ¿por qué este comando adicional conducirá a este fracaso? ¿Por qué el símbolo de redireccionamiento debe estar cerca del (?

zen
fuente
Cabe señalar que * nix shells divide las cosas en función del espacio en blanco que crea los tokens que mencionó Alec.
pollitos

Respuestas:

45

Porque eso no es un <, <()es algo completamente diferente. Esto se llama sustitución de proceso , es una característica de ciertos shells que le permite usar la salida de un proceso como entrada para otro.

Los operadores >y <redirigen la salida y la entrada de los archivos . El <()operador maneja comandos (procesos), no archivos. Cuando corres

sort < (ls)

Está intentando ejecutar el comando lsen una subshell (eso es lo que significan los paréntesis), luego pasar esa subshell como un archivo de entrada sort. Sin embargo, esta sintaxis no es aceptada y obtiene el error que vio.

terdon
fuente
3
Su respuesta es buena, pero then sort is attempting to read the subshell as its input file→ esto obviamente es incorrecto, ya que Bash ni siquiera analizará la sintaxis. Ni lstampoco sortse ejecuta realmente.
sleblanc
1
@sebleblanc punto justo, reformuló la respuesta, gracias.
terdon
1
No hay sub-shell en este caso. < (ls)No es un token válido aquí.
Cuonglm
@cuonglm no, porque bash lo trata como un error de sintaxis. Mi punto es que (ls)se ejecutaría lsen una subshell.
terdon
22

Porque así es como debe ser.

<(...)in bashes la sintaxis para la sustitución de procesos. Se copia del mismo operador en ksh.

<, (, ), |, &, ;Son tokens léxicos especiales en bashque se utilizan para formar operadores especiales en diferentes combinaciones. <, <(, <<, <&... cada uno tiene su papel. <es por redireccionamiento. <file, < fileredirigiría la entrada de un archivo. <'(file)'redirigiría la entrada de un archivo llamado (file), pero <(file)es un operador diferente que no es un operador de redirección.

< (file)sería <seguido por (file). En ese contexto, en bash, (file)no es válido. (...)puede ser válido como un token único en algunos contextos como:

(sub shell)
func () {
  ...
}
var=(foo bar)

Pero no en

sort < (cmd)

En la fishcáscara, es diferente. In fish, (...)es para la sustitución de comandos (el equivalente de $(...)in bash). Y <es para la redirección de entrada como en shells tipo Bourne.

Entonces en fish:

sort <(echo file)

sería lo mismo que:

sort < (echo file)

Es decir:

sort < file

Pero eso es algo completamente diferente de bashla sustitución del proceso.

En el yashshell, otro shell POSIX, <(...)no es para la sustitución de procesos sino para la redirección de procesos.

Ahí,

sort <(ls -l)

Corto para:

sort 0<(ls -l)

es un operador de redireccionamiento. Es más o menos equivalente a:

ls -l | sort

Mientras está adentro bash, <(ls -l)se expande a la ruta de una tubería, por lo que es más como:

ls -l | sort /dev/fd/0

En zsh, (...)se sobrecarga como operador global ( (*.txt|*.png)se expandiría a txty pngarchivos) y como calificador global ( *(/)por ejemplo, se expande a archivos de directorio).

En zsh, en:

sort < (ls -l)

Eso se (ls -l)trataría como un calificador global. El lcalificador global es coincidir en el número de enlaces y espera un número después l(como ls -ld ./*(l2)se enumeraría en los archivos con 2 enlaces), así que es por eso que obtiene un zsh: number expectederror allí.

sort < (w)habría dado un zsh: no matches found: (w)error en su lugar, ya que (w)coincide con los archivos con nombre vacío que se pueden escribir.

sort < (w|cat)habría ordenado el contenido de los archivos wy / o caten el directorio actual ...

Stéphane Chazelas
fuente
por qué sort < $(ls -l)da este error:bash: $(ls -l): ambiguous redirect
Edward Torvalds
@edwardtorvalds, porque se $(ls -l)expande a más de una palabra. Use comillas para evitar split + glob ( sort < "$(echo file)"). Tenga en cuenta que el comportamiento o bashdifiere del de POSIX sh en ese bash hace que la división + glob allí también cuando no sea interactiva (no cuando se llama como shsi fuera).
Stéphane Chazelas
Al mirar ls -l | sort /dev/fd/0, puedo decir que la salida de ls -lse almacena en /dev/fd/0y el sortcomando lo lee para dar la salida deseada. Estoy usando tail -f --retry /dev/fd/0para monitorear ese archivo pero no obtengo ningún resultado. ¿por qué? ¿Cómo puedo leer ese archivo?
Edward Torvalds
En peces, puede usar (foo | psub)para lograr la sustitución del proceso de entrada; todavía no hay sustituto (ha) para la sustitución del proceso de salida.
Zanchey