Muitos utilitários de linha de comando podem receber suas entradas de um canal ou como um argumento de nome de arquivo. Para scripts shell longos, acho que iniciar a cadeia com a cat
torna mais legível, principalmente se o primeiro comando precisar de argumentos de várias linhas.
Comparar
sed s/bla/blaha/ data \
| grep blah \
| grep -n babla
e
cat data \
| sed s/bla/blaha/ \
| grep blah \
| grep -n babla
O último método é menos eficiente? Se sim, a diferença é suficiente para se preocupar se o script é executado, digamos, uma vez por segundo? A diferença de legibilidade não é enorme.
shell-script
performance
pipe
cat
tshepang
fonte
fonte
cat
. No entanto, acho que a questão maior aqui é a legibilidade do código, que geralmente é uma prioridade sobre o desempenho. Quando mais rápido pode realmente ser escrito mais bonito , por que não? Apontar o problemacat
geralmente leva o usuário a entender melhor os pipelines e processos em geral. Vale a pena o esforço para que eles escrevam códigos compreensíveis da próxima vez.cat
; ponto de Calebe sobre como utilizar funções e resolve redirecionamento isso também.)Respostas:
A resposta "definitiva" é obviamente trazida a você pelo The Useless Use of
cat
Award .A instanciação de um gato apenas para que seu código seja lido de maneira diferente gera apenas mais um processo e mais um conjunto de fluxos de entrada / saída que não são necessários. Normalmente, a retenção real em seus scripts será loops ineficientes e processamento real. Na maioria dos sistemas modernos, um extra
cat
não prejudica seu desempenho, masquasesempre existe outra maneira de escrever seu código.A maioria dos programas, como você observa, pode aceitar um argumento para o arquivo de entrada. No entanto, sempre há o shell interno
<
que pode ser usado onde quer que um fluxo STDIN seja esperado, o que poupa um processo, fazendo o trabalho no processo do shell que já está em execução.Você pode até ser criativo com ONDE escrevê-lo. Normalmente, ele seria colocado no final de um comando antes de você especificar qualquer redirecionamento ou canal de saída como este:
Mas não precisa ser assim. Pode até vir em primeiro lugar. Por exemplo, seu código de exemplo pode ser escrito assim:
Se a sua legibilidade é um problema e seu código é confuso o suficiente para que a adição de uma linha
cat
seja esperada para facilitar o acompanhamento, existem outras maneiras de limpar seu código. Um que eu uso muito que ajuda a tornar os scripts fáceis de descobrir depois é dividir os pipes em conjuntos lógicos e salvá-los em funções. O código do script se torna muito natural e qualquer parte do pipline é mais fácil de depurar.Você pode então continuar com
fix_blahs < data | fix_frogs | reorder | format_for_sql
. Um pipleline com a seguinte leitura é realmente fácil de seguir e os componentes individuais podem ser depurados facilmente em suas respectivas funções.fonte
<file
poderia acontecer antes do comando. Isso resolve todos os meus problemas!<file
pode chegar a qualquer lugar na linha de comando:<file grep needle
ougrep <file needle
ougrep needle <file
. A exceção são comandos complexos, como loops e agrupamentos; lá o redirecionamento deve ocorrer após o fechamentodone
/}
/)
/ etc. @Caleb Isso ocorre em todos os shells Bourne / POSIX. E eu discordo que é feio.$(cat /some/file)
com$(< /some/file)
, que faz a mesma coisa, mas evita disparando um processo.$(< /some/file)
é de portabilidade limitada. Ele funciona no bash, mas não no cinza do BusyBox, por exemplo, ou no FreeBSD sh. Provavelmente também não funciona apressado, já que essas três últimas conchas são todas primas próximas.Aqui está um resumo de algumas das desvantagens de:
sobre
$file
acima. No caso decat
, isso é sempre um problema, excetozsh
; no caso do redirecionamento, isso é apenas um problema parabash
ouksh88
e, para alguns outros shells, apenas quando interativos (não em scripts).cmd
está embutido, são 2 processos em alguns shellsbash
.cat
está embutido, esse também é um comando extra sendo executado (e, é claro, carregado e inicializado (e as bibliotecas às quais está vinculado também)).cat
ecmd
processos e constantemente encher e esvaziar o buffer pipe. Mesmocmd
que1GB
grandesread()
chamadas de sistema por vez, o controle precise ir e voltar entrecat
ecmd
porque um canal não pode conter mais do que alguns kilobytes de dados por vez.cmd
s (comowc -c
) podem fazer algumas otimizações quando o stdin é um arquivo regular, com o qual não conseguem fazer,cat | cmd
já que o stdin é apenas um cano. Comcat
e um pipe, isso também significa que eles não podem estarseek()
no arquivo. Para comandos comotac
outail
, isso faz uma enorme diferença no desempenho, pois significa quecat
eles precisam armazenar toda a entrada na memória.cat $file
, e até a versão mais corretacat -- "$file"
, não funcionarão corretamente para alguns nomes de arquivos específicos, como-
(--help
ou qualquer coisa que comece com-
se você esquecer o--
). Se alguém insistir em usarcat
, provavelmente deve usar emcat < "$file" | cmd
vez de confiabilidade.$file
não puder ser aberto para leitura (acesso negado, não existe ...),< "$file" cmd
reportará uma mensagem de erro consistente (pelo shell) e não será executadocmd
, enquantocat $file | cmd
ainda será executado,cmd
mas com seu stdin parecendo um arquivo vazio. Isso também significa que, em coisas como< file cmd > file2
,file2
não é derrotado sefile
não puder ser aberto.fonte
truncate -s10G a; time wc -c < a; time cat a | wc -c; time cat a | cat | wc -c
. Existem muitos parâmetros que entram em cena. A penalidade de desempenho pode ir de 0 a 100%. De qualquer forma, não acho que a penalidade possa ser negativa.wc -c
é um caso bastante exclusivo, porque possui um atalho. Se você preferirwc -w
, é comparável aogrep
meu exemplo (ou seja, muito pouco processamento - que é a situação em que '<' pode fazer a diferença).wc -w
em um arquivo esparso de 1 GB no local C em linux 4.9 amd64), acho que a abordagem cat leva 23% mais tempo quando em um sistema multicore e 5% ao vinculá-los a um núcleo. Mostrando a sobrecarga extra incorrida ao ter dados acessados por mais de um núcleo. Você poderá obter resultados diferentes se alterar o tamanho do canal, usar dados diferentes, envolver E / S real, usar uma implementação cat que use splice () ... Tudo confirmando que há muitos parâmetros entrando em cena e que, em qualquer casocat
, não ajudará.wc -w
, é uma diferença de cerca de 2% ... 15% de diferença se estiver em um grep simples e direto. Então, estranhamente, se estiver em um compartilhamento de arquivo NFS, na verdade, é 20% mais rápido para lê-lo se canalizadocat
( gist.github.com/rdp/7162414833becbee5919cda855f1cb86 ) Weird ...Colocar
<file
no final de um pipeline é menos legível do que tercat file
no início. O inglês natural lê da esquerda para a direita.Colocar
<file
o início do pipeline também é menos legível que o gato, eu diria. Uma palavra é mais legível que um símbolo, especialmente um símbolo que parece apontar o caminho errado.O uso
cat
preserva ocommand | command | command
formato.fonte
<
uma vez torna o código menos legível, pois destrói a consistência da sintaxe de uma linha múltipla.<
seguinte:alias load='<'
e use, por exemploload file | sed ...
. Aliases podem ser usados em scripts após a execuçãoshopt -s expand_aliases
.Uma coisa que as outras respostas aqui não parecem ter abordado diretamente é que usar
cat
dessa forma não é "inútil" no sentido de que "um processo estranho de gato é gerado e não funciona"; é inútil no sentido de que "é gerado um processo de gato que faz apenas trabalho desnecessário".No caso destes dois:
o shell inicia um processo sed que lê de algum arquivo ou stdin (respectivamente) e depois faz algum processamento - ele lê até atingir uma nova linha, substitui o primeiro 'foo' (se houver) nessa linha por 'bar' e depois imprime essa linha para stdout e loops.
No caso de:
A concha gera um processo de gato e um processo de sed e liga o stdout do gato ao stdin do sed. O processo do gato lê um pedaço de vários quilos ou talvez megabytes do arquivo e, em seguida, grava isso em seu stdout, onde o sommand começa a partir daí, como no segundo exemplo acima. Enquanto o sed está processando esse pedaço, o gato está lendo outro pedaço e escrevendo-o no stdout para que o sed trabalhe em seguida.
Em outras palavras, o trabalho extra necessário para adicionar o
cat
comando não é apenas o trabalho extra de gerar umcat
processo extra , é também o trabalho extra de ler e gravar os bytes do arquivo duas vezes em vez de uma vez. Agora, praticamente falando e em sistemas modernos, isso não faz muita diferença - pode fazer com que seu sistema faça alguns microssegundos de trabalho desnecessário. Mas se for para um script que você planeja distribuir, potencialmente para as pessoas que o usam em máquinas que já estão com pouca potência, alguns microssegundos podem adicionar várias iterações.fonte
cat
.cat
divididas pelas ms, semcat
no por cento (por exemplo, 264 ms / 216 ms = 1,22 = 122% = 22% mais lento comcat
)