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?

iruvar
fonte

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
Stéphane Chazelas
fonte
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
Thorsten Staerk
fonte
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