Quando eu canalizo vários comandos unix, como grep, sed, tr etc., tendem a especificar o arquivo de entrada que está sendo processado usando o gato. Então, algo como cat file | grep ... | awk ... | sed ...
.
Mas, recentemente, depois de alguns comentários deixados em minhas respostas, indicando que este era um uso inútil de gato, pensei em fazer a pergunta aqui.
Eu procurei a questão e me deparei com o artigo da Wikipedia sobre o UUOC e o Prêmio Uso Inútil de Gatos e me parece que os argumentos apresentados são do ponto de vista da eficiência.
A pergunta mais próxima que me deparei aqui foi esta: É um desperdício chamar gato? - mas não é bem o que estou perguntando.
Eu acho que o que o acampamento UUOC sugere é usar cmd1 args < file | cmd2 args | cmd3 ..
ou se o comando tiver uma opção para ler do arquivo e depois passar o arquivo como argumento.
Mas para mim cat file | cmd1 ... | cmd2
parece muito mais fácil de ler e entender. Não preciso me lembrar de diferentes maneiras de enviar arquivos de entrada para diferentes comandos, e o processo flui logicamente da esquerda para a direita. Primeira entrada, depois o primeiro processo ... e assim por diante.
Não estou conseguindo entender quais argumentos estão sendo feitos sobre o uso inútil do gato? Entendo que, se estou executando um trabalho cron que é executado a cada 2 segundos e que processa muito, nesse caso, cat pode ser um desperdício. Mas, caso contrário, qual é o consenso geral sobre o uso de gatos?
fonte
< file cmd1 args | cmd2 args ...
também funciona ... então seu argumento de "da esquerda para a direita " é nulo. Costumo usá-lo para maior clareza - a ordem que mostrei pode fazer com que as pessoas parem, o que não é bom. Com contagens mais altas de threads se tornando a norma, isso está se tornando menos um problema IMO ...Respostas:
É inútil no sentido de que usá-lo dessa forma não realiza nada do que o outro, opções possivelmente mais eficientes não podem (por exemplo, produzir resultados adequados).
Mas
cat
é muito mais poderoso do que apenascat somefile
. Consulteman cat
ou leia o que escrevi nesta resposta . Mas se você precisar absolutamente positivamente do conteúdo de um único arquivo, poderá obter alguma vantagem de desempenho ao não usácat
-lo para obter o conteúdo do arquivo.Quanto à legibilidade, isso depende do seu gosto pessoal. Gosto de
cat
incluir arquivos em outros comandos pelo mesmo motivo, principalmente se os aspectos de desempenho forem insignificantes.Também depende do que você está criando scripts. Se for o seu próprio shell e métodos de conveniência para a sua máquina desktop, ninguém, exceto você, se importará. Se você se deparar com um caso em que seria melhor procurar a próxima ferramenta na cadeia e distribuí-la como um software freqüentemente usado em algum sistema Linux mínimo em um roteador de baixo desempenho ou dispositivo semelhante com limites reais capacidade de processamento, isso é diferente. Depende sempre do contexto.
fonte
No uso diário da linha de comando, não é realmente muito diferente. Você especialmente não notará nenhuma diferença de velocidade, pois o tempo na CPU evitado por não usar
cat
, sua CPU ficará inativa. Mesmo se você estiver percorrendo centenas ou milhares (ou mesmo centenas de milhares) de itens com toda a praticidade, isso não fará muita diferença, a menos que você esteja em um sistema muito carregado (Load Average / N CPU> 1).O local onde a borracha encontra a estrada é formar bons hábitos e desencorajar os maus. Para arrastar um clichê mofado, o diabo está nos detalhes. E são detalhes como esse que separam o medíocre do ótimo.
É como dirigir um carro, por que virar à esquerda quando você pode apenas fazer três direitos? Claro que você pode, e funciona perfeitamente. Mas se você entendeu o poder da esquerda, três direitos parecem bobos.
Não se trata de salvar um identificador de arquivo, 17k de RAM e 0,004 segundos de tempo de CPU. É sobre toda a filosofia de usar o UNIX. O "poder de virar à esquerda" na minha ilustração não está apenas redirecionando a entrada, é a filosofia do UNIX. Isso significa que você se destacará muito melhor do que os que o rodeiam e conquistará o respeito daqueles que o entenderem.
fonte
cat
não eliminará nenhuma paginação, embora a tubulação para algo possa eliminar a paginação por alguns aplicativos.Eu costumo usar
cat file | myprogram
em exemplos. Às vezes, estou sendo acusado de uso inútil de gato ( http://www.iki.fi/era/unix/award.html ). Eu discordo pelos seguintes motivos:É fácil entender o que está acontecendo.
Ao ler um comando UNIX, você espera um comando seguido de argumentos seguidos de redirecionamento. Ele é possível colocar o lugar redirecionamento mas raramente é visto - assim, as pessoas terão mais dificuldade de ler o exemplo. Acredito
é mais fácil de ler do que
Se você mover o redirecionamento para o início, estará confundindo pessoas que não estão acostumadas a esta sintaxe:
e exemplos devem ser fáceis de entender.
É fácil mudar.
Se você sabe que o programa pode ler do gato, normalmente pode assumir que ele pode ler a saída de qualquer programa que saia para STDOUT e, portanto, você pode adaptá-lo às suas próprias necessidades e obter resultados previsíveis.
Salienta que o programa não falha, se STDIN não for um arquivo regular.
Não é seguro supor que, se
program1 < foo
funcionar,cat foo | program1
também funcionará. No entanto, é seguro assumir o contrário. Este programa funciona se STDIN for um arquivo, mas falhará se a entrada for um canal, porque usa o seek:Analisei a penalidade de desempenho em http://oletange.blogspot.dk/2013/10/useless-use-of-cat.html A conclusão é não usar
cat file |
se a complexidade do processamento for semelhante a um simples grep e desempenho importa mais do que legibilidade. Para outras situações, tudocat file |
bem.fonte
Eu acho que a posição de alguns dos que comentam algo sendo um UUOC é que, se realmente entendermos a sintaxe do Unix e do shell, não usaríamos o gato nesse contexto. É visto como usar gramática ruim: eu posso escrever uma frase usando gramática ruim e ainda entendo o que quero dizer, mas também demonstro meu pouco entendimento do idioma e, por extensão, minha baixa escolaridade. Dizer que algo é um UUOC é outra maneira de dizer que alguém não entende o que está fazendo.
Quanto à eficiência, se você estiver executando um pipeline a partir da linha de comando, leva menos tempo para a máquina executar
cat somefile |
do que para você pensar se pode ser mais eficiente usar< somefile
. Isso simplesmente não importa.fonte
cat somefile | prog
com casca sem gato, como,prog < somefile
mas elas sempre pareciam estar na ordem errada para mim, principalmente com uma cadeia de comandos unidos. Agora vejo que algo tão elegante quanto< somefile prog
o truque, obrigado. Fiquei sem as desculpas que me restavam para usar gato.Eu não estava ciente do prêmio até hoje, quando um novato tentou prender o UUOC em mim por uma das minhas respostas. Foi um
cat file.txt | grep foo | cut ... | cut ...
. Pensei um pouco sobre ele e só depois visitei o link que ele me deu, referindo-se às origens do prêmio e à prática de fazê-lo. Outras pesquisas me levaram a essa pergunta. Infelizmente, apesar da consideração consciente, nenhuma das respostas incluiu minha lógica.Eu não pretendia ficar na defensiva ao educá-lo. Afinal, nos meus anos mais jovens, eu teria escrito o comando,
grep foo file.txt | cut ... | cut ...
porque sempre que você faz os singles frequentes,grep
aprende a colocação do argumento do arquivo e é fácil saber que o primeiro é o padrão e os últimos são os nomes de arquivo.Foi uma escolha consciente quando respondi à pergunta com o
cat
prefixo, em parte por uma razão de "bom gosto" (nas palavras de Linus Torvalds), mas principalmente por uma razão convincente de função.A última razão é mais importante, por isso vou colocá-la em primeiro lugar. Quando ofereço um pipeline como solução, espero que seja reutilizável. É bem provável que um pipeline seja adicionado no final ou emendado em outro pipeline. Nesse caso, ter um argumento de arquivo para grep aumenta a capacidade de reutilização e, possivelmente, o faz silenciosamente sem uma mensagem de erro se o argumento de arquivo existir. I. e.
grep foo xyz | grep bar xyz | wc
fornecerá quantas linhasxyz
contêmbar
enquanto você espera o número de linhas que contêm ambosfoo
ebar
. A necessidade de alterar os argumentos para um comando em um pipeline antes de usá-lo é suscetível a erros. Acrescente a isso a possibilidade de falhas silenciosas e isso se torna uma prática particularmente insidiosa.A razão anterior não é sem importância, já que muito "bom gosto" é meramente uma lógica subconsciente intuitiva para coisas como as falhas silenciosas acima das quais você não consegue pensar exatamente no momento em que uma pessoa que precisa de educação diz "mas não é" aquele gato inútil ".
No entanto, tentarei também conscientizar a razão anterior de "bom gosto" que mencionei. Essa razão tem a ver com o espírito de design ortogonal do Unix.
grep
não fazcut
els
não fazgrep
. Portanto, pelo menos,grep foo file1 file2 file3
vai contra o espírito de design. A maneira ortogonal de fazê-lo écat file1 file2 file3 | grep foo
. Agora,grep foo file1
é apenas um caso especial degrep foo file1 file2 file3
, e se você não o tratar da mesma maneira, estará usando pelo menos os ciclos do relógio cerebral tentando evitar o prêmio inútil do gato.Isso nos leva ao argumento que
grep foo file1 file2 file3
está concatenando, ecat
concatena, por isso é apropriado,cat file1 file2 file3
mas porquecat
não está concatenando,cat file1 | grep foo
portanto, estamos violando o espírito docat
Unix e do Todo-Poderoso. Bem, se esse fosse o caso, o Unix precisaria de um comando diferente para ler a saída de um arquivo e cuspi-lo no stdout (não paginá-lo ou qualquer coisa apenas um cuspo puro no stdout). Portanto, você teria a situação em que você dizcat file1 file2
ou diz,dog file1
e lembre-se conscientemente de evitarcat file1
evitar o prêmio, além de evitar,dog file1 file2
pois esperançosamente, o design dedog
geraria um erro se vários arquivos fossem especificados.Esperamos que, neste momento, você simpatize com os designers do Unix por não incluir um comando separado para cuspir um arquivo no stdout, enquanto também nomeia
cat
concatenar, em vez de dar outro nome a ele.<edit>
existe um cão assim, o<
operador infeliz . É uma pena a sua colocação no final do pipeline, impedindo a fácil composição. Não existe uma maneira sintática ou esteticamente limpa de colocá-lo no início. Também é lamentável não ser suficientemente genérico, de modo que você comece com o cão, mas simplesmente adicione outro nome de arquivo, se quiser que ele seja processado após o anterior. (Por>
outro lado, a metade não é tão ruim. Tem um posicionamento quase perfeito no final. Normalmente não é uma parte reutilizável de um pipeline e, portanto, é distinguida simbolicamente.)</edit>
A próxima pergunta é por que é importante ter comandos que apenas cospem um arquivo ou a concatenação de vários arquivos no stdout, sem nenhum processamento adicional? Uma razão é evitar que cada comando Unix que opera na entrada padrão saiba como analisar pelo menos um argumento do arquivo de linha de comando e usá-lo como entrada, se existir. A segunda razão é evitar que os usuários precisem se lembrar: (a) para onde vão os argumentos do nome do arquivo; e (b) evitar o bug do pipeline silencioso conforme mencionado acima.
Isso nos leva ao porquê de
grep
ter uma lógica extra. A lógica é permitir a fluência do usuário para comandos usados com freqüência e de forma independente (e não como um pipeline). É um pequeno comprometimento da ortogonalidade para um ganho significativo na usabilidade. Nem todos os comandos devem ser projetados dessa maneira, e os comandos que não são usados com frequência devem evitar completamente a lógica extra dos argumentos do arquivo (lembre-se de que a lógica extra leva a uma fragilidade desnecessária (a possibilidade de um bug)). A exceção é permitir argumentos de arquivo como no caso degrep
. (a propósito, observe quels
há um motivo completamente diferente para não apenas aceitar, mas praticamente exigir argumentos de arquivo)Finalmente, o que poderia ter sido feito melhor é se comandos excepcionais como
grep
(mas não necessariamentels
) geram um erro se a entrada padrão estiver disponível. Isso é razoável porque os comandos incluem lógica que viola o espírito ortogonal do todo-poderoso Unix para conveniência do usuário. Para maior comodidade do usuário, ou seja, para impedir o sofrimento causado por uma falha silenciosa, esses comandos não devem hesitar em violar sua própria violação, alertando o usuário se houver uma possibilidade de falha silenciosa.fonte
grep pattern f1 f2 f3
não é uma concatenação simples .grep
conhece arquivos e imprime nomes de arquivos (e, opcionalmente, números de linha e qualquer outra coisa).grep . /sys/kernel/mm/transparent_hugepage/*
é um bom truque para imprimir o nome do arquivo: conteúdo do arquivo com muitos arquivos de linha única. O design clássico do Unix é que a maioria dos utilitários funciona*.txt
sem necessidadecat
.cat
é para achatar vários arquivos em um fluxo.grep
exemplo por um programa comocut
esse, que não tem nenhum motivo para se preocupar com vários arquivos, e sempre pode ser alimentado a partir do stdin. Alguns utilitários, comotr
, não aceitam argumentos de arquivo e funcionam apenas como um filtro; portanto, a opção é entrecat
e<
.<file cmd1 | cmd2 >out
não é maravilhoso, admito, mas é totalmente possível se acostumar. Você continua falando sobre "o espírito do Todo-Poderoso Unix" de uma maneira zombeteira, o que me deixa totalmente irritado porque parece que você não entende ou não quer entender da maneira que os designers do Unix realmente pensavam. Tudo bem se você não gosta do design do Unix, mas não é inerentemente idiota. Não tenho certeza se o design do sistema operacional é anterior à sintaxe do shell e como tudo evoluiu, mascat
vale a pena evitar um extra em 1970!cat
ajuda a reutilizar e emendar os pipelines, enquanto sem ele você pode obter falhas silenciosas (procure "silenciosamente" na minha resposta).Em defesa dos usos inúteis do gato
(Alguns parágrafos para ajudar a equilibrar o tsunami de comentários irritantes contra essa prática)
Uso o bash há muitos anos, tanto como shell quanto como linguagem de script para scripts pequenos (e às vezes lamentavelmente para não tão pequenos). Há muito tempo, aprendi sobre o "Uso inútil de gato" (UUoC). Ainda sou culpado pelo menos toda semana, mas, francamente, raramente me sinto um pouco compelido a evitá-lo. Acredito que o uso de
cat
vs< file
seja mais sobre o gosto do que diferenças técnicas e escrevi esta resposta para proteger pessoas novas no Linux que compartilham o meu gosto porcat
pensando que há algo seriamente errado no caminho deles (e observe as poucas ocasiões em que há). Como Linus Torvalds, também acredito que muitas vezes o sabor é mais importante que a habilidade. Isso não significa que meu gosto seja melhor que o seu, mas significa que, se algo tem um gosto ruim, não o farei sem ganhar algo digno.Já é óbvio que, como o autor da pergunta , sinto que o uso de cat é muito natural ao trabalhar em um basquete como o REPL, onde estou explorando um problema através da construção incremental de comandos complexos. Aqui está um exemplo muito típico: eu tenho um arquivo de texto e não sei muito sobre ele. Digitarei
cat file
para ter uma amostra do conteúdo. Se a saída é demais Eu vou bater minha seta para cima e, dependendo das circunstâncias, eu vou adicionar| head
ou| grep foo
ou| what_ever
estender meu comando anterior, acrescentando etapas de processamento. Essa maneira de passar gradualmente de um comando simples para um mais complexo, adicionando uma etapa de processamento após a outra, me parece muito natural (estou fazendo o mesmo no ipython e adoro o jeitopyfunctional
e ferramentas de programação similares abrangem esse estilo). Portanto, ao trabalhar no bash shell, estou confiante de que interromper meu fluxo para remover ocat
é mais inútil do que deixá-lo e sofrer ... bem, nenhuma consequência em 99,9% dos casos.É claro que, ao escrever scripts, as coisas podem mudar. Mas, mesmo ao escrever scripts, minha opinião é de que as pessoas que zombam do UUoC ignoram essas lições importantes com muita atenção: "A otimização prematura é a raiz de todo mal" . E se você não está fazendo algo atípico, é realmente difícil para o UUoC estar onde a otimização será necessária. Claro que você definitivamente precisa saber o que é ineficiente (é a invocação extra de processo BTW, já que poucos parecem mencioná-lo). Tendo esse conhecimento, se você trabalhar nesses sistemas raros em que invocar um processo é caro (por exemplo, alguns sistemas embarcados ou CygWin em menor grau), você saberá o que fazer se uma situação especial exigir. Por exemplo, se você estiver ligando
cat
muitas vezes por segundo em um loop (BTW, se você se encontrar nessa posição, pergunte-se se o bash é a ferramenta certa para o trabalho). Novamente, porém: "primeiro faça com que funcione corretamente e depois otimize, se necessário" .E como você explica o tsunami de reclamações sobre o UUoC Nick?
Além de nem todo mundo ter o meu gosto, acredito que a maior parte do motivo pelo qual tantas pessoas reclamam do UUoC não é técnica, mas humana: a maioria dos novatos no Unix não conhece o
< file command
idioma, por isso é tentador para uma pessoa mais experiente interpretar o "Velho Guru" " para eles. Ele também terá a oportunidade de usar palavras sofisticadas ("chamada de processo") e tocar no assunto querido "otimização". Uma boa impressão é garantida, por isso é muito difícil resistir. Então os recém-chegados seguirão o conselho do Guru pelo valor nominal e por um longo tempo o reproduzirão para outros como "A Única Verdade" (e votarão negativamente nesta resposta :-). Nota engraçada: provavelmente é tão fácil corrigir o bash para evitar ineficiências do UUoC que é preciso se perguntar por que ninguém adicionou esse recurso ou criou< filename
cat um arquivo depois de tantos anos. Uma alma sombria sugeriria que alguns hackers de barba grisalha gostam de deixar oportunidades para zombar de nós ;-)fonte
O que seria realmente bom é um shell que suporta sintaxe como:
Enquanto isso, acho
cat filename | realcmd1...
aceitável, pois mantém a sintaxe padronizada com comandos iniciais que exigem o nome do arquivo como argumento.fonte
< filename cmd | cmd2 ...
. Isso é perto o suficiente?< file command ...
desde pelo menos meados dos anos 80 e provavelmente já nos anos 70, quando o originalsh
foi escrito. De maneira mais geral, os redirecionamentos de E / S são analisados da esquerda para a direita e podem ser intercalados em qualquer ordem na linha de comando. Então,cmd <file arg arg...
também seria válido.Para todos que dizem que o gato é aceitável de usar porque "cheira" melhor ou "é mais legível", eu diria apenas isso:
Para você, talvez ... mas não para outras pessoas que possam ler ou tentar entender seu código. Se você nunca tentar instruir outras pessoas com seus exemplos ou compartilhar seu código, use-o como quiser.
Também adicionarei esse comentário, já que há muito tempo usuário e administrador / engenheiro do Linux ... (e há muitos de nós), nossos olhos ficam sangrando ao ver isso. Por quê? Porque ele usa recursos em sistemas nos quais controlamos os recursos firmemente. O comando cat e o próprio pipe usam memória extra e identificadores de arquivo que são completamente inúteis. Você amarrou recursos de que meu sistema precisa gratuitamente e ganhou NADA que pode explicar o uso desses recursos. Este é um enorme não, não.
Agora eu posso sentar aqui e debater coisas como cheiro ou legibilidade do código o dia todo com qualquer pessoa, mas no final do dia é uma questão de gravação ou de errado e sempre que você usa recursos em um sistema e não ganha nada por isso ... está errado.
Como usuário doméstico, você pode aprender com meus conselhos e aprender maneiras melhores de fazer as coisas ou pode optar por ficar cego pelo "cheiro" dos gatos, sua escolha ... mas saiba que se você usar abertamente essa prática, será chamado nessa prática o tempo todo e você silenciosamente terá que admitir que elas estão certas e você é teimosa porque é verdade. :-)
fonte
cat foo.txt | ...
. A outra resposta explica bem por que pode ser um bom uso. O resumo simples do caso a favor é: "$ CPU time << $ Brain time" (como @MikeP comentou acima).