Por que o shell não corrige automaticamente o "uso inútil de gato"? [fechadas]

28

Muitas pessoas usam oneliners e scripts que contêm código ao longo das linhas

cat "$MYFILE" | command1 | command2 > "$OUTPUT"

O primeiro caté freqüentemente chamado de "uso inútil de gato", porque tecnicamente requer o início de um novo processo (geralmente /usr/bin/cat) onde isso poderia ser evitado se o comando tivesse sido executado.

< "$MYFILE" command1 | command2 > "$OUTPUT"

porque o shell só precisa iniciar command1e simplesmente apontar stdinpara o arquivo fornecido.

Por que o shell não faz essa conversão automaticamente? Eu sinto que a sintaxe "uso inútil de gato" é mais fácil de ler e o shell deve ter informações suficientes para se livrar automaticamente do gato inútil. Como caté definido no padrão POSIX, o shell deve implementá-lo internamente, em vez de usar um caminho binário. O shell pode até conter implementação apenas para exatamente uma versão de argumento e fallback para binário no caminho.

Mikko Rantalainen
fonte
22
Na verdade, esses comandos não são equivalentes, já que, em um caso, stdin é um arquivo e, no outro, é um pipe, portanto não seria uma conversão estritamente segura. Você poderia criar um sistema que fizesse isso.
Michael Homer
14
O fato de você não poder imaginar um caso de uso não significa que um aplicativo não pode confiar inutilmente no comportamento especificado. Obter um erro lseekainda é um comportamento definido e pode causar um resultado diferente, o comportamento de bloqueio diferente pode ser semanticamente significativo etc. Seria permitido fazer a alteração se você soubesse quais eram os outros comandos e sabia que eles não se importavam, ou se você simplesmente não se importava com a compatibilidade nesse nível, mas o benefício é bem pequeno. Imagino que a falta de benefício conduz a situação mais do que o custo de conformidade.
Michael Homer
3
É absolutamente permitido que o shell se implemente cat, ou qualquer outro utilitário. Também é permitido saber como os outros utilitários que pertencem ao sistema funcionam (por exemplo, ele pode saber como se comporta a grepimplementação externa que acompanha o sistema ). Isso é completamente viável, por isso é perfeitamente justo imaginar por que eles não o fazem.
Michael Homer
6
@ MichaelHomer, por exemplo, ele pode saber como a implementação grep externa que acompanha o sistema se comporta. Portanto, o shell agora depende do comportamento de grep. E sed. E awk. E du. E quantas centenas, senão milhares de outros utilitários?
Andrew Henle
19
Seria bastante desagradável do meu shell editar meus comandos para mim.
Azor Ahai

Respostas:

25

Os 2 comandos não são equivalentes: considere o tratamento de erros:

cat <file that doesn't exist> | less produzirá um fluxo vazio que será passado para o programa canalizado ... assim, você acaba com uma exibição que não mostra nada.

< <file that doesn't exist> less falhará ao abrir a barra e, em seguida, não abrirá menos.

Tentar alterar o primeiro para o último pode interromper qualquer número de scripts que esperam executar o programa com uma entrada potencialmente em branco.

UKMonkey
fonte
1
Marcarei sua resposta como aceita porque acho que essa é a diferença mais importante entre as duas sintaxes. A variante com catsempre executará o segundo comando no pipeline, enquanto a variante com apenas redirecionamento de entrada não executará o comando se o arquivo de entrada estiver ausente.
Mikko Rantalainen 13/04
No entanto, observe que <"missing-file" grep foo | echo 2não será executado, grepmas será executado echo.
Mikko Rantalainen 16/04
51

"Uso inútil de cat" é mais sobre como você escreve seu código do que sobre o que realmente é executado quando você executa o script. É um tipo de design anti-padrão , uma maneira de ir sobre algo que provavelmente poderia ser feito de uma forma mais eficiente. É uma falha no entendimento de como combinar melhor as ferramentas fornecidas para criar uma nova ferramenta. Eu diria que amarrar vários sede / ou awkcomandos juntos em um pipeline também pode às vezes ser considerado um sintoma desse mesmo antipadrão.

A correção de instâncias de "uso inútil de cat" em um script é principalmente uma questão de corrigir o código-fonte do script manualmente. Uma ferramenta como o ShellCheck pode ajudar com isso, apontando os casos óbvios:

$ cat script.sh
#!/bin/sh
cat file | cat
$ shellcheck script.sh

In script.sh line 2:
cat file | cat
    ^-- SC2002: Useless cat. Consider 'cmd < file | ..' or 'cmd file | ..' instead.

Conseguir que o shell faça isso automaticamente seria difícil devido à natureza dos scripts do shell. A maneira como um script é executado depende do ambiente herdado de seu processo pai e da implementação específica dos comandos externos disponíveis.

O shell não sabe necessariamente o que caté. Pode ser potencialmente qualquer comando de qualquer lugar da sua $PATHfunção ou.

Se fosse um comando interno (que pode estar em alguns shells), ele teria a capacidade de reorganizar o pipeline, pois conheceria a semântica de seu catcomando interno. Antes de fazer isso, seria necessário fazer suposições sobre o próximo comando no pipeline, após o original cat.

Observe que a leitura da entrada padrão se comporta de maneira um pouco diferente quando conectada a um pipe e a um arquivo. Um tubo não pode ser procurado; portanto, dependendo do que o próximo comando no pipeline faz, ele pode ou não se comportar de maneira diferente se o pipeline foi reorganizado (pode detectar se a entrada é procurável e decidir fazer as coisas de forma diferente se for ou se não é, de qualquer forma, se comportaria de maneira diferente).

Essa pergunta é semelhante (em um sentido muito geral) a " Existem compiladores que tentam corrigir erros de sintaxe por conta própria? " (No site Software Engineering StackExchange), embora essa pergunta seja obviamente sobre erros de sintaxe, não padrões de design inúteis . A idéia de alterar automaticamente o código com base na intenção é basicamente a mesma.

Kusalananda
fonte
É perfeitamente compatível com um shell saber o que caté e os outros comandos no pipeline (a regra como se) e se comportar de acordo, eles simplesmente não estão aqui porque é inútil e muito difícil.
Michael Homer
4
@MichaelHomer Sim. Mas também é permitido sobrecarregar um comando padrão com uma função com o mesmo nome.
Kusalananda
2
@PhilipCouling É absolutamente conforme, desde que se saiba que nenhum dos comandos do pipeline se importa. O shell tem permissão específica para substituir utilitários por funções internas ou de shell e esses não possuem restrições no ambiente de execução, desde que o resultado externo seja indistinguível, é permitido. Para o seu caso, cat /dev/ttyé o interessante com o qual seria diferente <.
Michael Homer
1
@MichaelHomer , desde que o resultado externo seja indistinguível, é permitido Isso significa que o comportamento de todo o conjunto de utilitários otimizados dessa maneira nunca poderá mudar . Isso tem que ser o inferno da dependência final.
Andrew Henle
3
@MichaelHomer Como os outros comentários disseram, é claro que é perfeitamente compatível com o shell saber que, dada a entrada do OP, é impossível dizer o que o catcomando realmente faz sem executá-lo . Pelo que você sabe (e o shell), o OP possui um comando catem seu caminho, que é uma simulação interativa de gatos, "myfile" é apenas o estado do jogo armazenado command1e command2está pós-processando algumas estatísticas sobre a atual sessão de reprodução ...
alephzero 11/04
34

Porque não é inútil.

No caso de cat file | cmd, o fd 0(stdin) de cmdserá um pipe e, no caso cmd <filedele, poderá ser um arquivo, dispositivo normal etc.

Um canal possui semântica diferente de um arquivo regular e sua semântica não é um subconjunto daquelas de um arquivo regular:

  • um arquivo regular não pode ser select(2)editado ou poll(2)editado de maneira significativa; um select(2)sempre retornará "pronto". Interfaces avançadas como epoll(2)no Linux simplesmente não funcionam com arquivos regulares.

  • no Linux há chamadas de sistema ( splice(2), vmsplice(2), tee(2)), que só funcionam em tubos [1]

Como caté muito usado, ele pode ser implementado como um shell embutido, o que evitará um processo extra, mas assim que você iniciar esse caminho, a mesma coisa poderá ser feita com a maioria dos comandos - transformar o shell em um mais lento e desajeitado perlou python. provavelmente é melhor escrever outra linguagem de script com uma sintaxe semelhante a um pipe fácil de usar para continuações ;-)

[1] Se você quer um exemplo simples não confeccionados para a ocasião, você pode olhar para o meu "binary exec do stdin" git essência com algumas explicações no comentário aqui . Implementar catdentro dele para fazê-lo funcionar sem UUoC o tornaria 2 ou 3 vezes maior.

mosvy
fonte
2
Na verdade, ksh93 faz implementar alguns comandos externos como catinternos.
jrw32982 suporta Monica em 11/04
3
cat /dev/urandom | cpu_bound_programexecuta as read()chamadas do sistema em um processo separado. No Linux, por exemplo, o trabalho real da CPU de gerar mais números aleatórios (quando o pool está vazio) é feito nessa chamada do sistema; portanto, o uso de um processo separado permite que você aproveite um núcleo separado da CPU para gerar dados aleatórios como entrada. Por exemplo, em Qual é a maneira mais rápida de gerar um arquivo de texto de 1 GB contendo dígitos aleatórios?
Peter Cordes
4
Mais importante, na maioria dos casos, significa lseekque não funcionará. cat foo.mp4 | mpv -funcionará, mas você não pode procurar mais além do que o buffer de cache do mpv ou mplayer. Mas com a entrada redirecionada de um arquivo, você pode. cat | mpv -é uma maneira de verificar se um MP4 tem seu moovátomo no início do arquivo, para que possa ser reproduzido sem procurar o final e o retorno (ou seja, se for adequado para transmissão). É fácil imaginar outros casos em que você deseja testar um programa para arquivos não procuráveis ​​executando-o /dev/stdincom catum redirecionamento.
Peter Cordes
Isso é ainda mais verdadeiro ao usar xargs cat | somecmd. Se os caminhos do arquivo ultrapassarem o limite do buffer de comando, xargspoderão ser executados catvárias vezes, resultando em um fluxo contínuo, enquanto o uso xargs somecmddireto falhará frequentemente, porque somecmdnão pode ser executado em múltiplos para obter um resultado contínuo.
tasket 13/04
17

Porque detectar gatos inúteis é realmente muito difícil.

Eu tinha um script de shell onde escrevi

cat | (somecommand <<!
...
/proc/self/fd/3
...
!) 0<&3

O script do shell falhou na produção se o catfoi removido porque foi chamado via su -c 'script.sh' someuser. O aparentemente supérfluo catfez com que o proprietário da entrada padrão mudasse para o usuário em que o script estava sendo executado, de modo que a reabrisse por meio do /proctrabalho.

Joshua
fonte
Esse caso seria bem fácil, pois claramente não segue o modelo simples de catseguido por exatamente um parâmetro, portanto o shell deve usar catexecutável real em vez de atalho otimizado. Um bom argumento sobre credenciais possivelmente diferentes ou padrões não padronizados para processos reais, no entanto.
Mikko Rantalainen 13/04
13

tl; dr: Os reservatórios não fazem isso automaticamente porque os custos excedem os benefícios prováveis.

Outras respostas apontaram a diferença técnica entre stdin ser um pipe e ser um arquivo. Tendo isso em mente, o shell pode fazer um dos seguintes:

  1. Implemente catcomo um interno, ainda preservando a distinção entre arquivo e tubulação. Isso economizaria o custo de um executivo e talvez, possivelmente, de um garfo.
  2. Faça uma análise completa do pipeline com conhecimento dos vários comandos usados ​​para verificar se o arquivo / canal é importante e, em seguida, aja com base nisso.

Em seguida, você deve considerar os custos e benefícios de cada abordagem. Os benefícios são bastante simples:

  1. Nos dois casos, evite um exec (of cat)
  2. No segundo caso, quando a substituição de redirecionamento é possível, evite um garfo.
  3. Nos casos em que você tem que usar um tubo, que pode ser possível, por vezes, para evitar um garfo / vfork, mas muitas vezes não. Isso ocorre porque o equivalente a gato precisa ser executado ao mesmo tempo que o resto do pipeline.

Assim, você economiza um pouco de tempo e memória da CPU, especialmente se puder evitar o garfo. Obviamente, você só economiza esse tempo e memória quando o recurso é realmente usado. E você está realmente economizando o tempo do garfo / exec; com arquivos maiores, o tempo é principalmente o tempo de E / S (ou seja, gato lendo um arquivo do disco). Então, você deve perguntar: com que frequência é catusado (inutilmente) em scripts de shell em que o desempenho realmente importa? Compare-o com outros componentes comuns do shell, como test- é difícil imaginar que catseja usado (inutilmente) até um décimo com a frequência testusada em locais importantes. Esse é um palpite que ainda não medi, o que você gostaria de fazer antes de qualquer tentativa de implementação. (Ou da mesma forma, pedindo a outra pessoa para implementar, por exemplo, uma solicitação de recurso.)

Em seguida, você pergunta: quais são os custos. Os dois custos que vêm à mente são: (a) código adicional no shell, que aumenta seu tamanho (e, portanto, possivelmente uso de memória), requer mais trabalho de manutenção, é outro ponto para erros, etc .; e (b) surpresas de compatibilidade com versões anteriores, o POSIX catomite muitos recursos, por exemplo, GNU coreutils cat, portanto, você deve ter cuidado exatamente com o que o catbuilt-in implementaria.

  1. A opção embutida adicional provavelmente não é tão ruim - adicionando mais uma embutida onde um monte já existe. Se você tivesse dados de perfil mostrando a ajuda, provavelmente poderia convencer os autores do seu shell favorito a adicioná-los.

  2. Quanto à análise do pipeline, acho que os projéteis não fazem nada parecido atualmente (alguns reconhecem o final de um pipeline e podem evitar um garfo). Essencialmente, você adicionaria um otimizador (primitivo) ao shell; os otimizadores geralmente se tornam códigos complicados e a fonte de muitos bugs. E esses erros podem ser surpreendentes - pequenas alterações no script do shell podem acabar evitando ou acionando o erro.

Postscript: Você pode aplicar uma análise semelhante aos usos inúteis do gato. Benefícios: mais fácil de ler (embora se command1 aceite um arquivo como argumento, provavelmente não). Custos: bifurcação e exec extra (e se o comando1 puder usar um arquivo como argumento, provavelmente mensagens de erro mais confusas). Se sua análise lhe disser para usar inutilmente o gato, vá em frente.

derobert
fonte
10

O catcomando pode aceitar -como um marcador para stdin . ( POSIX , " Se um arquivo for '-', o utilitário cat deve ler a entrada padrão naquele ponto da sequência. ") Isso permite o manuseio simples de um arquivo ou stdin onde, caso contrário, isso não seria permitido.

Considere estas duas alternativas triviais, onde o argumento do shell $1é -:

cat "$1" | nl    # Works completely transparently
nl < "$1"        # Fails with 'bash: -: No such file or directory'

Outro momento catútil é quando é usado intencionalmente como não operacional simplesmente para manter a sintaxe do shell:

file="$1"
reader=cat
[[ $file =~ \.gz$ ]] && reader=zcat
[[ $file =~ \.bz2$ ]] && reader=bzcat
"$reader" "$file"

Finalmente, acredito que a única vez em que o UUOC pode realmente ser chamado corretamente é quando caté usado com um nome de arquivo conhecido por ser um arquivo regular (ou seja, não é um dispositivo ou pipe nomeado) e que nenhum sinalizador é dado ao comando:

cat file.txt

Em qualquer outra situação, as catpróprias propriedades podem ser necessárias.

roaima
fonte
6

O comando cat pode fazer coisas que o shell não pode necessariamente fazer (ou pelo menos, não pode fazer facilmente). Por exemplo, suponha que você queira imprimir caracteres que, de outra forma, seriam invisíveis, como guias, retornos de carro ou novas linhas. Pode haver uma maneira de fazer isso apenas com os comandos internos do shell, mas não consigo pensar em nada fora do topo da minha cabeça. A versão GNU do gato pode fazer isso com o-A argumento ou os -v -E -Targumentos (embora eu não conheça outras versões do gato). Você também pode prefixar cada linha com um número de linha usando -n(novamente, IDK se versões não-GNU puderem fazer isso).

Outra vantagem do gato é que ele pode facilmente ler vários arquivos. Para fazer isso, pode-se simplesmente digitar cat file1 file2 file3. Para fazer o mesmo com um shell, as coisas ficariam complicadas, embora um loop cuidadosamente criado possa provavelmente alcançar o mesmo resultado. Dito isto, você realmente quer reservar um tempo para escrever esse loop, quando existe uma alternativa tão simples? Eu não!

A leitura de arquivos com o gato provavelmente usaria menos CPU do que o shell, pois o cat é um programa pré-compilado (a exceção óbvia é qualquer shell que possua um gato interno). Ao ler um grande grupo de arquivos, isso pode se tornar aparente, mas nunca o fiz nas minhas máquinas, por isso não tenho certeza.

O comando cat também pode ser útil para forçar um comando a aceitar entrada padrão nas instâncias em que não pode. Considere o seguinte:

echo 8 | sleep

O número "8" não será aceito pelo comando "sleep", pois nunca foi realmente aceito para aceitar entrada padrão. Assim, o sono desconsiderará essa entrada, reclamará da falta de argumentos e sairá. No entanto, se alguém digitar:

echo 8 | sleep $(cat)

Muitas conchas expandirão isso para sleep 8, e o sono aguardará 8 segundos antes de sair. Você também pode fazer algo semelhante com o ssh:

command | ssh 1.2.3.4 'cat >> example-file'

Este comando adiciona um arquivo de exemplo na máquina com o endereço 1.2.3.4 com o que for gerado a partir de "comando".

E isso é (provavelmente) apenas arranhando a superfície. Tenho certeza de que poderia encontrar mais exemplo de gato sendo útil se quisesse, mas este post é longo o suficiente. Então, concluirei dizendo o seguinte: pedir ao shell para antecipar todos esses cenários (e vários outros) não é realmente viável.

TSJNachos117
fonte
Eu terminaria a última frase com "não é facilmente viável"
Basile Starynkevitch
3

Lembre-se que um usuário pode ter um catna sua $PATH, que não é exatamente o POSIX cat(mas talvez alguma variante que pode logar alguma coisa em algum lugar). Nesse caso, você não deseja que o shell o remova.

o PATH poderia mudar dinamicamente, e então cat não é o que você acredita que é. Seria muito difícil escrever um shell fazendo a otimização que você sonha.

Além disso, na prática, cat é um programa bastante rápido. Existem poucas razões práticas (exceto estética) para evitá-lo.

Veja também o excelente Analisando POSIX [s] hell palestra sobre Parish Y de Yann Regis-Gianas no FOSDEM2018. Dá outras boas razões para evitar tentar fazer o que você sonha em um shell.

Se o desempenho fosse realmente um problema para os shells, alguém teria proposto um shell que usa otimização sofisticada do compilador de programa inteiro, análise estática de código-fonte e técnicas de compilação just-in-time (todos esses três domínios têm décadas de progresso e publicações científicas e dedicadas conferências, por exemplo, sob SIGPLAN ). Infelizmente, mesmo como um tópico de pesquisa interessante, que atualmente não é financiado por agências de pesquisa ou capitalistas de risco, e deduzo que simplesmente não vale a pena o esforço. Em outras palavras, provavelmente não há mercado significativo para a otimização de cascas . Se você tiver meio milhão de euros para gastar em tais pesquisas, encontrará facilmente alguém para fazer isso, e acredito que daria resultados valiosos.

Em termos práticos, reescrevendo, para melhorar seu desempenho, geralmente é feito um pequeno shell script (de cem linhas) em qualquer linguagem de script melhor (Python, AWK, Guile, ...). E não é razoável (por muitas razões de engenharia de software) escrever grandes scripts de shell: quando você está escrevendo um script de shell com mais de cem linhas, é necessário reescrevê-lo (mesmo por motivos de legibilidade e manutenção) em uma linguagem mais adequada : como linguagem de programação, o shell é muito ruim. No entanto, existem muitos scripts shell gerados grandes e por boas razões (por exemplo, GNU autoconf geradoconfigure scripts ).

Em relação a grandes arquivos de texto, passá-los para catum único argumento não é uma boa prática, e a maioria dos administradores de sistemas sabe que (quando qualquer script de shell leva mais de um minuto para ser executado, você começa a otimizá-lo). Para arquivos de gigabytes grandes, nuncacat é a boa ferramenta para processá-los.

Basile Starynkevitch
fonte
3
"Poucas razões práticas para evitá-lo" - qualquer um que esperasse cat some-huge-log | tail -n 5correr (onde tail -n 5 some-huge-logpoderia pular direto até o fim, enquanto catlê apenas de frente para trás) discordaria.
Charles Duffy
O comentário do check-out de catum arquivo de texto grande em dezenas de GB (que foi criado para teste) leva bastante tempo. Não recomendaria.
Sergiy Kolodyazhnyy 13/04
1
BTW, re: "nenhum mercado significativo para otimizar cascas" - o ksh93 é um shell de otimização e bastante bom. Ele foi , por um tempo, vendidos com sucesso como um produto comercial. (Infelizmente, ser licenciado comercialmente também tornou bastante nicho que clones mal escritos e outros sucessores menos capazes, mas sem custo, conquistaram o mundo fora dos sites dispostos a pagar por uma licença, levando à situação em que tem hoje).
Charles Duffy
(não usando as técnicas específicas que você observa, mas, francamente, essas técnicas não fazem sentido, dado o modelo de processo; as técnicas aplicadas são, bem, bem aplicadas e com bom efeito ).
Charles Duffy
2

Adicionando a resposta @Kusalananda (e comentário @alephzero), cat pode ser qualquer coisa:

alias cat='gcc -c'
cat "$MYFILE" | command1 | command2 > "$OUTPUT"

ou

echo 'echo 1' > /usr/bin/cat
cat "$MYFILE" | command1 | command2 > "$OUTPUT"

Não há razão para que cat (por si só) ou / usr / bin / cat no sistema seja realmente a ferramenta concatenada.

Roubar
fonte
3
Diferente do comportamento de caté definido pelo POSIX e, portanto, não deve ser muito diferente.
roaima 11/04
2
@roaima: PATH=/home/Joshua/bin:$PATH cat ...Tem certeza de que sabe o que catfaz agora?
Joshua
1
@ Josué, isso realmente não importa. Nós dois sabemos que catpodemos ser substituídos, mas também sabemos que não deve ser substituído voluntariamente por outra coisa. Meu comentário aponta que o POSIX exige um determinado (subconjunto de) comportamento que pode ser razoavelmente esperado que exista. Às vezes, escrevi um script de shell que estende o comportamento de um utilitário padrão. Nesse caso, o script do shell agiu e se comportou exatamente como a ferramenta substituída, exceto pelo fato de possuir recursos adicionais.
roaima 11/04
@ Josué: Na maioria das plataformas, os shells sabem (ou poderiam saber) quais diretórios contêm executáveis ​​que implementam comandos POSIX. Portanto, você pode adiar a substituição até depois da expansão do alias e da resolução do caminho, e apenas fazê-lo /bin/cat. (E você pode optar por desativar.) Ou criar catum shell interno (o que talvez recorra a /bin/catvários argumentos)? Para que os usuários possam controlar se desejam ou não a versão externa normal caminho, com enable cat. Como para kill. (Eu estava pensando que o bash command catiria funcionar, mas isso não pula os builtins)
Peter Cordes
Se você fornecer um alias, o shell saberá que catnesse ambiente não se refere mais ao habitual cat. Obviamente, a otimização deve ser implementada após o processamento dos aliases. Considero os shell embutidos para representar comandos no diretório virtual que sempre são anexados ao seu caminho. Se você deseja evitar a versão interna do shell de qualquer comando (por exemplo test), é necessário usar uma variante com um caminho.
Mikko Rantalainen
1

Dois usos "inúteis" para o gato:

sort file.txt | cat header.txt - footer.txt | less

... aqui caté usado para misturar entrada de arquivo e canalizada.

find . -name '*.info' -type f | sh -c 'xargs cat' | sort

... aqui, você xargspode aceitar um número praticamente infinito de nomes de arquivos e executar catquantas vezes forem necessárias, fazendo com que tudo se comporte como um fluxo. Portanto, isso funciona para grandes listas de arquivos em que o uso direto xargs sortnão.

tarefa
fonte
Ambos os casos de uso seriam trivialmente evitados, tornando o shell incorporado apenas uma intervenção se catfor chamado com exatamente um argumento. Especialmente no caso em que shé passada uma string e xargsa chamada será catdireta, não há como o shell usar sua implementação embutida.
Mikko Rantalainen
0

Além de outras coisas, cat-check adicionaria sobrecarga de desempenho adicional e confusão sobre qual uso caté realmente inútil, IMHO, porque essas verificações podem ser ineficientes e criar problemas com legítimoscat uso .

Quando os comandos lidam com os fluxos padrão, eles precisam se preocupar apenas com a leitura / gravação nos descritores de arquivo padrão. Os comandos podem saber se stdin é procurável / isável ou não, o que indica um pipe ou arquivo.

Se adicionarmos à mistura a verificação de qual processo realmente fornece esse conteúdo stdin, precisaremos encontrar o processo do outro lado do canal e aplicar a otimização apropriada. Isso pode ser feito em termos de shell em si, como mostra a postagem de SuperUser de Kyle Jones, e em termos de shell que é

(find /proc -type l | xargs ls -l | fgrep 'pipe:[20043922]') 2>/dev/null

como mostrado na postagem vinculada. Esta é mais 3 comandos (modo extras fork()s e exec()s) e percursos recursivos (por isso toda monte dereaddir() chamadas).

Em termos de código-fonte C e shell, o shell já conhece o processo filho, portanto não há necessidade de recursão, mas como sabemos quando otimizar e quando caté realmente inútil? De fato, existem usos úteis do gato , como

# adding header and footer to file
( cmd; cat file; cmd ) | cmd
# tr command does not accept files as arguments
cat log1 log2 log3 | tr '[:upper:]' '[:lower:]'

Provavelmente seria desperdício e sobrecarga desnecessária adicionar essa otimização ao shell. Como a resposta de Kusalanda já mencionou, o UUOC é mais sobre a falta de entendimento do usuário sobre como combinar melhor os comandos para obter melhores resultados.

Sergiy Kolodyazhnyy
fonte