Por que o `sort <(ls -l)` funciona, mas o `sort <(ls -l)` falha?

32

Hoje estou aprendendo algo sobre o fifo com este artigo: Introdução aos tubos nomeados , que menciona cat <(ls -l).

Fiz algumas experiências usando sort < (ls -l), o que mostra um erro:

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

Então, descobri que não havia espaço suficiente no comando.

Mas, por que esse comando extra levará a essa falha? Por que o símbolo de redirecionamento deve estar próximo ao (?

zen
fonte
Deve-se notar que o * nix shells divide as coisas com base no espaço em branco, o que cria os tokens mencionados por Alec.
pintainhos

Respostas:

45

Porque isso não é um <, é um <()que é completamente diferente. Isso é chamado de substituição de processo , é um recurso de certas shells que permite usar a saída de um processo como entrada para outro.

Os operadores >e <redirecionam a saída e a entrada dos arquivos . O <()operador lida com comandos (processos), não com arquivos. Quando você corre

sort < (ls)

Você está tentando executar o comando lsem um subshell (é o que os parênteses significam) e depois passar esse subshell como um arquivo de entrada sort. No entanto, essa sintaxe não é aceita e você recebe o erro que viu.

terdon
fonte
3
Sua resposta é boa, mas then sort is attempting to read the subshell as its input file→ isso está obviamente errado, pois o Bash nem sequer analisa a sintaxe. Nem lsnem sorté realmente executado.
sleblanc
1
@bleble fair point, reformulou a resposta, obrigado.
terdon
1
Não há subcasca neste caso. < (ls)não é um token válido aqui.
cuonglm
@cuonglm não, porque o bash o trata como um erro de sintaxe. O que quero dizer é que isso (ls)seria executado lsem um subshell.
terdon
22

Porque é assim que deve ser.

<(...)in bashé a sintaxe da substituição do processo. É copiado do mesmo operador em ksh.

<, (, ), |, &, ;São símbolos lexicais especiais em bashque são usados para formar os operadores especiais em diferentes combinações. <, <(, <<, <&... cada um tem o seu papel. <é para redirecionamento. <file, < fileredirecionaria a entrada de um arquivo. <'(file)'redirecionaria a entrada de um arquivo chamado (file), mas <(file)é um operador diferente que não é um operador de redirecionamento.

< (file)seria <seguido por (file). Nesse contexto, em bash, (file)não é válido. (...)pode ser válido como um único token em alguns contextos como:

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

Mas não em

sort < (cmd)

No fishshell, é diferente. In fish, (...)é para substituição de comando (o equivalente a $(...)in bash). E <é para redirecionamento de entrada como em shells tipo Bourne.

Então em fish:

sort <(echo file)

seria o mesmo que:

sort < (echo file)

Isso é:

sort < file

Mas isso é algo completamente diferente da bashsubstituição de processos.

No yashshell, outro shell POSIX, <(...)não é para substituição de processo, mas para redirecionamento de processo

Lá,

sort <(ls -l)

Abreviatura de:

sort 0<(ls -l)

é um operador de redirecionamento. É mais ou menos equivalente a:

ls -l | sort

Enquanto estiver no bash, o <(ls -l)é expandido para o caminho de um tubo, por isso é mais como:

ls -l | sort /dev/fd/0

In zsh, (...)é sobrecarregado como um operador globbing ( (*.txt|*.png)seria expandido para txte pngarquivos) e como qualificador global ( *(/)por exemplo, se expande para arquivos de diretório).

Em zsh, em:

sort < (ls -l)

Isso (ls -l)seria tratado como um qualificador global. O lqualificador glob deve corresponder ao número de links e espera um número depois l(como em ls -ld ./*(l2)listaria os arquivos com 2 links), é por isso que você recebe um zsh: number expectederro lá.

sort < (w)em zsh: no matches found: (w)vez disso , teria dado um erro, pois (w)corresponde aos arquivos com um nome vazio que pode ser gravado.

sort < (w|cat)teria classificado o conteúdo dos arquivos we / ou catno diretório atual ...

Stéphane Chazelas
fonte
por que sort < $(ls -l)dá esse erro:bash: $(ls -l): ambiguous redirect
Edward Torvalds
@edwardtorvalds, porque se $(ls -l)expande para mais de uma palavra. Use aspas para evitar divisão + glob ( sort < "$(echo file)"). Observe que o comportamento ou bashdifere do POSIX sh nesse bash faz com que o divisão + glob também seja inativo (não quando chamado como se shfosse).
Stéphane Chazelas
olhando, ls -l | sort /dev/fd/0posso dizer que a saída de ls -lé armazenada /dev/fd/0e o sortcomando lê para fornecer a saída desejada. Estou usando tail -f --retry /dev/fd/0para monitorar esse arquivo, mas não estou obtendo nenhuma saída. porque? como posso ler esse arquivo?
Edward Torvalds
No peixe, você pode usar (foo | psub)para obter a substituição do processo de entrada; ainda não há substituto (ha) para substituição do processo de saída.
Zanchey 22/09/2015