Seus redirecionamentos têm uma condição de corrida. Isso:
>(wc -l | awk '{print $1}' > n.txt)
é executado em paralelo com:
awk 'BEGIN{getline n < "n.txt"}...'
mais tarde no pipeline. Às vezes, n.txt
ainda está vazio quando o programa awk
começa a ser executado.
Isso é documentado (obliquamente) no Manual de Referência do Bash. Em um canal :
The output of each command in the pipeline is connected via a pipe to the input of the next command. That is, each command reads the previous command’s output. This connection is performed before any redirections specified by the command.
e depois:
Each command in a pipeline is executed in its own subshell
(ênfase adicionada). Todos os processos no pipeline são iniciados, com suas entradas e saídas conectadas juntas, sem esperar que algum dos programas anteriores conclua ou mesmo comece a fazer qualquer coisa. Antes disso, processo de substituição com >(...)
is:
performed simultaneously with parameter and variable expansion, command substitution, and arithmetic expansion.
O que isso significa é que o subprocesso executando o comando wc -l | awk ...
inicia no início e o redirecionamento esvazia n.txt
logo antes disso, mas o processo awk
que causa o erro é iniciado logo após. Ambos os comandos são executados em paralelo - você terá vários processos ao mesmo tempo aqui.
O erro ocorre quando awk
executa seu bloco BEGIN
antes que a saída do comando wc
tenha sido gravada em n.txt
. Nesse caso, a variável n
está vazia e, portanto, é zero quando usada como um número. Se o BEGIN
for executado após o preenchimento do arquivo, tudo funcionará.
Quando isso acontece, depende do agendador do sistema operacional e de qual processo recebe um slot primeiro, que é essencialmente aleatório da perspectiva do usuário. Se o awk
final for executado antes ou o wc
pipeline for agendado um pouco mais tarde, o arquivo ainda estará vazio quando awk
começar a fazer seu trabalho e a coisa toda será interrompida. Com toda a probabilidade, os processos serão executados em diferentes núcleos, na verdade, simultaneamente, e é para baixo que se chega ao ponto de contenção primeiro. O efeito que você terá é provavelmente o comando trabalhando com mais freqüência do que não, mas às vezes falhando com o erro que você postou.
Em geral, os pipelines são seguros apenas na medida em que são apenas pipelines - a saída padrão na entrada padrão é boa, mas como os processos são executados em paralelo não é confiável confiar no sequenciamento de qualquer outra comunicação canais , como arquivos, ou qualquer parte de qualquer processo em execução antes ou depois de qualquer parte de outra, a menos que eles estejam bloqueados lendo a entrada padrão.
A solução aqui é provavelmente fazer todos os seus arquivos antes de precisar deles: no final de uma linha, é garantido que um pipeline inteiro e todos os seus redirecionamentos tenham sido concluídos antes do próximo comando ser executado. Este comando nunca será confiável, mas se você realmente precisar dele para trabalhar neste tipo de estrutura, você pode inserir um atraso ( sleep
) ou fazer um loop até que n.txt
esteja não vazio antes de executar o comando awk
final. para aumentar as chances de as coisas funcionarem como você quer.