Como evitar canos quebrados em comandos com cat?

3

Por que esse comando simples falha usando o shell emacs (eshell)?

cat file.txt | wc 

Eu tenho um arquivo com 10241 linhas. Cada linha tem menos de 50 caracteres. Cerca de 90% das vezes que eu lanço este comando, ele dá o resultado errado, ou seja, contagem de linhas. No entanto, nenhuma mensagem de erro é dada.

Parece que o cano quebrado é um tópico muito comum, mas não encontrei nenhuma explicação razoável. Além disso, ninguém propõe nenhuma solução alternativa. Como posso ter este comando simples funcionando de forma confiável?

Claro, eu poderia ter acabado de executar wc file.txt . Mas eu estou procurando uma solução mais geral em que qualquer ferramenta funcionaria bem gato canalizado: cat file.txt | any_tool_here .

Detalhes

Estou usando o CentOS 5. Esse problema aparece ao usar o eshell (shell do emacs) . Estou usando o GNU Emacs 24.5.2.

Experiências

Amostras de resultados usando cat file.txt | wc (esperado: a primeira coluna será sempre 10241).

  1. 8568 25706 110571
  2. 9837 29513 126947
  3. 5395 16187 69615
  4. 9202 27608 118757
  5. 7299 21899 94199
  6. 9837 29513 126947

Exemplo de resultados usando wc file.txt :

  1. 10241 30723 132156
  2. 10241 30723 132156
  3. 10241 30723 132156
  4. 10241 30723 132156
  5. 10241 30723 132156
  6. 10241 30723 132156

O comando cat em si (quando executado sozinho) está funcionando corretamente. Eu validei com o seguinte comando (algumas vezes): cat file.txt > file2.txt . Então, eu diferi os dois arquivos e eles são idênticos.

    
por rkioji 17.10.2016 / 11:51

1 resposta

5

Reunindo as informações sobre o shell que foi usado ( eshell ), parece que o aspecto de fluxo desse shell é o culpado. Normalmente, piping significa abrir duas extremidades de um pipe + fork / exec, de modo que você obtenha dois processos que compartilham um descritor de arquivo em um pipe, e a comunicação passa diretamente pelo kernel. Dessa forma, nada pode ser perdido - é garantido que é seguro (embora, se o pipe ou qualquer fluxo envolvido estiver em buffer, talvez seja necessário aguardar que o primeiro processo saia normalmente para liberar o último fragmento do fluxo). / p>

A julgar pelo trecho do manual do eshell :

Eshell is not a replacement for system shells such as bash or zsh. Use Eshell when you want to move text between Emacs and external processes; if you only want to pipe output from one external process to another (and then another, and so on), use a system shell, because Emacs’s IO system is buffer oriented, not stream oriented, and is very inefficient at such tasks. If you want to write shell scripts in Eshell, don’t; either write an elisp library or use a system shell.

eshell não está fazendo isso da maneira normal, mas falsifica o pipe usando seus "buffers" (representação de arquivos abertos do emacs) como depósito intermediário de dados, e (sem mais pesquisas) eu acho que em algum momento, wc executa read e emacs responde com um trecho vazio (e retornar 0 de read é um sinal de que o fluxo terminou), em vez de esperar mais entradas do primeiro programa para preencher o buffer. Se for esse o caso, significa que o eshell não é apenas ineficiente, mas cheio de bugs quando se trata de tubos.

    
por 17.10.2016 / 12:57

Tags