substituição do processo aninhado seguido por pipe: “descritor de arquivo inválido”

2

Encontrei um erro desconcertante que gostaria de entender melhor. O problema parece exigir a presença de uma função shell "wrapper" (como descrito abaixo), então meu interesse imediato é descobrir como modificar essa função de shell para se livrar do erro. (Eu dou uma declaração mais específica da minha pergunta no final do post.)

O código mais simples que eu criei para reproduzir este erro é dado no script a seguir. (Este script é certamente artificial e bobo, mas a situação da vida real em que o erro apareceu pela primeira vez é um pouco complicada demais para uma demonstração como essa.)

# create an input file
cat <<EOF > demo.txt
a
b
c
EOF

# create a "wrapper shell function" for /usr/bin/join
my_join_fn () {
  /usr/bin/join "$@"
}
cat <(my_join_fn  <(cat demo.txt) <(cat demo.txt))
cat <(my_join_fn  <(cat demo.txt) <(cat demo.txt)) | head -1

# create a "wrapper shell function" for /usr/local/bin/gjoin, a port of
# GNU's join function for OS X
my_gjoin_fn () {
  /usr/local/bin/gjoin "$@"
}
cat <(my_gjoin_fn <(cat demo.txt) <(cat demo.txt))
cat <(my_gjoin_fn <(cat demo.txt) <(cat demo.txt)) | head -1

# show the version of zsh
$SHELL --version

Se alguém originar esse script (em zsh ), ele terminará com êxito e produzirá a seguinte saída (correta):

% source demo.sh
a
b
c
a
a
b
c
a
zsh 5.0.2 (x86_64-apple-darwin11.4.2)

Mas se alguém reexecutar diretamente da linha de comando de uma das duas linhas do script que terminam com | head -1 , receberá um erro bad file descriptor :

% cat <(my_join_fn  <(cat demo.txt) <(cat demo.txt)) | head -1
join: /dev/fd/11: Bad file descriptor
% cat <(my_gjoin_fn <(cat demo.txt) <(cat demo.txt)) | head -1
/usr/local/bin/gjoin: /dev/fd/11: Bad file descriptor

Estas são as duas únicas linhas no script que produzem um erro quando são executadas diretamente na linha de comando.

Como indicado na saída de $SHELL --version , os resultados mostrados acima foram obtidos no OS X, mas obtenho resultados semelhantes quando realizo um teste análogo no Linux:

% cat <(my_join_fn  <(cat demo.txt) <(cat demo.txt)) | head -1
/usr/bin/join: /proc/self/fd/11: No such file or directory
% $SHELL --version
zsh 4.3.10 (x86_64-unknown-linux-gnu)

Eu não consegui reproduzir esse erro em bash (OS X ou Linux). Isso me leva a suspeitar que o erro é devido a um erro em zsh . Mas, em caso afirmativo, é um bug extremamente misterioso e, portanto, provavelmente não será corrigido em breve.

Portanto, gostaria de encontrar uma solução alternativa. Minha pergunta é:

How should I modify the definition of the wrapper shell function my_gjoin_fn so as to avoid this error?

(O equivalente real para my_gjoin_fn é quase idêntico ao dado acima, diferindo apenas na inclusão de um sinalizador na invocação de gjoin :

my_gjoin_fn () {
  /usr/local/bin/gjoin -t$'\t' "$@"
}

Eu uso esta função de shell wrapper o tempo todo , portanto, eu realmente gostaria de "salvá-lo".

EDITAR:

O erro persiste mesmo se eu substituir o | head -1 no final do comando por | head -10 , | cat , | tee /dev/null , | : etc. Por exemplo:

% cat <(my_join_fn  <(cat demo.txt) <(cat demo.txt)) | cat
/usr/bin/join: /proc/self/fd/11: No such file or directory

Além disso, adicionar ls -l /proc/self/fd , conforme sugerido por msw, produz o seguinte:

% cat <(ls -l /proc/self/fd; my_join_fn  <(cat demo.txt) <(cat demo.txt)) | cat
total 0
lrwx------ 1 jones jones 64 Aug 21 12:29 0 -> /dev/pts/18
l-wx------ 1 jones jones 64 Aug 21 12:29 1 -> pipe:[312539706]
lrwx------ 1 jones jones 64 Aug 21 12:29 2 -> /dev/pts/18
lr-x------ 1 jones jones 64 Aug 21 12:29 3 -> /proc/23849/fd
/usr/bin/join: /proc/self/fd/11: No such file or directory

... o que não me diz muito , mas pode ser mais informativo para os outros. FWIW, a saída produzida pelo subcomando ls -l /proc/self/fd parece a mesma se eu executar isso em zsh ou sob bash . Além disso, FWIW, a saída de ls -l /proc/self/fd quando executada por si só é

% ls -l /proc/self/fd
total 0
lrwx------ 1 jones jones 64 Aug 21 12:32 0 -> /dev/pts/18
lrwx------ 1 jones jones 64 Aug 21 12:32 1 -> /dev/pts/18
lrwx------ 1 jones jones 64 Aug 21 12:32 2 -> /dev/pts/18
lr-x------ 1 jones jones 64 Aug 21 12:32 3 -> /proc/5246/fd
    
por kjo 21.08.2013 / 15:59

2 respostas

1

Consegui reproduzir o comportamento usando zsh 4.3.10 (i686-pc-linux-gnu) .

% cat <(funjoin  <(cat demo) <(cat demo)) | head -1 
join: /proc/self/fd/11: No such file or directory

Eu procurei no manual e o mais próximo que encontrei desse problema foi o capítulo Substituição de processo em man zshexpn e MULTIOS em man zshmisc .

Ambos os capítulos estão sugerindo uma solução envolvendo colocar chaves em torno de parte do comando.

Eu tentei isso

% { cat <(funjoin  <(cat demo) <(cat demo)) } | head -1
1

e funciona.

Eu não consegui entender completamente o que é a semântica de { } em zsh. O manual explica isso simplesmente como uma lista de comandos. Eu também não entendo completamente o que exatamente isso faz MULTIOS. Parecia não fazer diferença se foi ativado ou desativado.

Eu tentei colocar as chaves em lugares diferentes, incluindo no corpo da função funjoin , mas o único lugar onde ele funciona corretamente é em torno do exterior cat .

    
por 21.08.2013 / 19:15
1

Eu não consigo reproduzir isso em zsh_5.0.0-2ubuntu3_amd64.deb no Linux, mas /proc/self/fd/11 parece ser um número bem alto. Só falha com head -1 ? Como cerca de head -10 ? A saída de

cat <(ls -l /proc/self/fd ; my_join_fn  <(cat demo.txt) <(cat demo.txt)) | head -1

produz alguma iluminação?

    
por 21.08.2013 / 16:48

Tags