O que exatamente é () em bash (e = () em zsh)?

18

Estou bastante confortável com o bash, mas recentemente acabei em uma substituição que não sabia.

O que exatamente é <(<command>) no bash? Como se compara ao =(<command>) em zsh?

Eu entendo que isso tem algo a ver com os descritores de arquivos padrão. No meu computador

echo <()

retorna /proc/self/fd/11 , que eu descobri ser uma cópia do script STDOUT, mas isso ainda parece bastante confuso para mim.

    
por Henrique Barcelos 31.03.2016 / 20:18

2 respostas

25

Isso é chamado de substituição de processo.

A sintaxe <(list) é suportada por ambos, bash e zsh . Ele fornece uma maneira de passar a saída de um comando ( list ) para outro comando ao usar um canal ( | ) não é possível. Por exemplo, quando um comando simplesmente não suporta entrada de STDIN ou você precisa da saída de múltiplos comandos:

diff <(ls dirA) <(ls dirB)

<(list) conecta a saída de list com um arquivo em /dev/fd , se suportado pelo sistema, caso contrário, um pipe nomeado (FIFO) é usado (o que também depende do suporte do sistema; nenhum manual diz o que acontece se ambos os mecanismos não são suportados, presumivelmente, ele aborta com um erro). O nome do arquivo é então passado como argumento na linha de comando.

zsh adicionalmente suporta =(list) como possível substituto para <(list) . Com =(list) , um arquivo temporário é usado no lugar do arquivo em /dev/fd ou FIFO. Ele pode ser usado como um substituto para <(list) se o programa precisar procurar na saída.

De acordo com o manual do ZSH , pode haver outros problemas em como <(list) funciona:

The = form is useful as both the /dev/fd and the named pipe implementation of <(...) have drawbacks. In the former case, some programmes may automatically close the file descriptor in question before examining the file on the command line, particularly if this is necessary for security reasons such as when the programme is running setuid. In the second case, if the programme does not actually open the file, the subshell attempting to read from or write to the pipe will (in a typical implementation, different operating systems may have different behaviour) block for ever and have to be killed explicitly. In both cases, the shell actually supplies the information using a pipe, so that programmes that expect to lseek (see man page lseek(2)) on the file will not work.

    
por 01.04.2016 / 09:02
7

Note que esta é uma resposta bash, não zsh.

Existem casos no bash em que você não pode usar pipes:

some_command | some_other_command

porque os pipes introduzem subshells para cada componente do pipeline, quando as subshells saem, todos os efeitos colaterais que você estava usando desapareceriam. Por exemplo, este exemplo inventado:

cat file | while read line; do ((count++)); done
echo $count

exibirá uma linha em branco, porque a variável $count não existe no shell atual.

Uma bash substituição de processos permite evitar esse enigma, permitindo que você para ler a saída "some_command" como você faria em um arquivo

while read line; do ((count++)); done < <(cat file)
# ....................................1.2
echo $count   # the variable *does* exist in the current shell

(1) é um redirecionamento de entrada normal. (2) é o início da sintaxe de substituição do processo <() .

    
por 31.03.2016 / 21:02