Ordem de saída com substituição de processo


11

Isto é o que eu costumo fazer para executar grepe wcem um arquivo sem ter que verificá-lo duas vezes

<file.txt  tee >(grep LITERAL) >(wc -l) >/dev/null

No entanto, isso gera

EXEC LITERAL
32

as vezes e

32
EXEC LITERAL

em outros momentos. (A saída de grepprecede a saída de wcna primeira instância e vice-versa na segunda.)

Por outro lado, com redirecionamentos e descritores de arquivo

{ { <file.txt tee /dev/fd/3 | grep LITERAL >&4; } 3>&1 | wc -l ;} 4>&1 

Eu sempre pareço

EXEC LITERAL
32

Prefiro que a ordem de saída seja previsível, mas é garantida com a segunda abordagem?

Respostas:


4

Em ambos

<file.txt  tee >(grep LITERAL) >(wc -l) >/dev/null

E:

{ { <file.txt tee /dev/fd/3 | grep LITERAL >&4; } 3>&1 | wc -l ;} 4>&1

Todos tee, grepe wcsão iniciados simultaneamente. O que importa então é o que acontece no final.

wcsó imprimirá o resultado quando vir o final do arquivo em sua entrada padrão. No primeiro caso, é quando teesai, porque então teeo fechará fdna outra extremidade do canal que wcestá sendo lido (iniciado pela substituição do processo). Não há garantia de que grepterá lido toda a sua entrada até esse momento, muito menos escrito sua saída (dado que os pipes podem conter uma quantidade bastante grande de dados e que wcprovavelmente será mais rápido que grep)

No segundo caso, wco final do arquivo será exibido quando todos os gravadores do canal de leitura estiverem fechando a extremidade do canal. Nesse caso, porém, existem vários escritores. tee(por meio de seu fd aberto sobre /dev/fd/3e por meio de seu fd 3) e grepque também tem seus fd3 abertos para o tubo wc(embora não esteja fazendo nenhum uso dele, muito menos escreva para ele). O interno {provavelmente causará um processo extra de subshell que também terá um fd3 aberto e aguardará ambos teee grep.

Isso significa que wcsó escreverá seu número de linha após a grepsaída.

Se você tivesse escrito da maneira correta, fechando os fds que não precisavam ser abertos:

{ { <file.txt tee /dev/fd/3 4>&- | 
   grep LITERAL >&4 3>&- 4>&-; } 3>&1 | wc -l 4>&-;} 4>&1

Então o pedido não teria sido garantido em shells que otimizam o processo do subshell. No entanto, o único shell que eu sei que é, ksh93mas ksh93usa pares de soquetes para pipes, então /dev/fd/3não funcionará lá no Linux pelo menos.

Para ver quais processos estão em execução, você pode substituir greppor ps:

$ { { <file.txt tee /dev/fd/3 4>&- | ps -H >&4 3>&- 4>&-; } 3>&1 | wc -l 4>&-;} 4>&1
  PID TTY          TIME CMD
 8727 pts/5    00:00:00 bash
 8815 pts/5    00:00:00   bash
 8817 pts/5    00:00:00     tee
 8818 pts/5    00:00:00     ps
 8816 pts/5    00:00:00   wc

Com bash, você pode ver esse processo extra de shell e também ver o canal aberto no fd 3 com:

$ (p=$BASHPID; { { <file.txt tee /dev/fd/3 4>&- | lsof -ag "$p" -d3 >&4 3>&- 4>&-; } 3>&1 | wc -l 4>&-;} 4>&1)
COMMAND  PID PGID     USER   FD   TYPE DEVICE SIZE/OFF   NODE NAME
bash    9843 9842 chazelas    3w  FIFO    0,8      0t0 153304 pipe
tee     9845 9842 chazelas    3w  FIFO    0,8      0t0 153304 pipe
lsof    9846 9842 chazelas    3r   DIR    0,3        0      1 /proc

Obrigado. No seu "exemplo adequado", o que grep LITERAL >&4 3>&- 4>&-significa, o fd 4 parece ser usado e fechado?
— Iruvar

@ 1_CR, depois >&4, abreviação de 1>&4, grepfd 1 e 4 apontam para o mesmo recurso (stdout inicial do shell). grepnão precisa ter o seu fd 4 aberto a nada. Ele não faz nada com isso, então o encerramos com #4>&-
— Stéphane Chazelas

Essa última linha de comando é uma mágica enigmática.

-1

Para obter um pedido previsível, use

(<file.txt  tee >(grep LITERAL) >(wc -l) >/dev/null)|sort

Talvez eu não tenha sido claro o suficiente. Eu quis dizer ordem previsível em termos de ordem de saídas de comando (ou seja, saída do grep antes da saída do wc). Eu não preciso da saída combinada classificada
— iruvar

acabei de encontrar o gnu.org/software/bash/manual/bashref.html#Command-Grouping , informa que, com os operadores {}, você garante (neste caso) que primeiro faz <file.txt tee / dev / fd / 3 grep LITERAL> & 4; e quando isso é feito, você liga para wc, para responder à sua pergunta original, sim, é garantido para minha compreensão #
— Thorsten Staerk

1
@ThorstenStaerk, você poderia adicionar as informações extras que encontrou à sua resposta?
— terdon

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.