O aplicativo em si não está em questão, só estou me perguntando como o Bash não está se comportando como eu esperava, como se, de alguma forma, qualquer comportamento que esse aplicativo tenha, estivesse vazando de uma forma que não consigo explicar o porquê.
Para contextualizar, o aplicativo é patsh , ele é destinado a coisas do Nix (como no gerenciador de pacotes), mas essencialmente ele pega um arquivo de entrada, e o reescreve com base em algumas regras e então o salva no arquivo de saída (que aqui é /dev/stdout
), neste contexto, ele não reescreve nada, então é essencialmente cp
. Aqui está a configuração:
$ cat <<EOF > foo
1
2
3
4
5
6
EOF
$ cat <<EOF > bar
a
b
c
EOF
$ { patsh -f bar /dev/stdout; } >> foo # Using braces to avoid any ambiguity...
$ cat foo # It replaced instead of appending
a
b
c
4
5
6
$ cat <(patsh -f bar /dev/stdout) >> foo # Does what I expected
$ cat foo
a
b
c
4
5
6
a
b
c
Alguém pode explicar esse comportamento?
No Linux ou Cygwin, a abertura
/dev/stdout
não duplica o descritor, ele abre o mesmo arquivo novamente , então uma descrição de arquivo aberto separada é criada.Aparentemente
patsh
abre o arquivo especificado pelo operando não no modo append. Então a ferramenta não escreve em seu stdout (descritor de arquivo 1), ela escreve no novo descritor apontando para a nova descrição de arquivo aberto que por acaso aponta para o mesmo arquivo que o stdout real (porque você especificou/dev/stdout
), mas o modo é independente e neste caso é realmente diferente.Se a abertura
/dev/stdout
trouxesse um descritor de arquivo que fosse uma duplicata de stdout (fd 1), ou seja, um descritor de arquivo apontando para a mesma descrição de arquivo aberto que stdout (equivalente a fazerdup(1)
), então o comando funcionaria como você esperava. Em alguns Unices/dev/stdout
,/dev/stdin
,/dev/stderr
,/dev/fd/n
funcionam exatamente assim; mas não no Linux.Dentro
<(…)
do stdout há um pipe. Como acima,patsh
abre o mesmo arquivo que seu stdout novamente, mas agora não importa porque o arquivo é um pipe e escrever em um pipe sempre adiciona dados ao final do fluxo. O pipe está sendo lido porcat
. Imprime apenascat
emfoo
. Ele faz isso usando seu stdout real (em oposição a abrir o mesmo arquivo novamente via/dev/stdout
) cujo modo de anexação foi definido por>>
você usado; então isso funciona como você esperava.