Comando para enviar o conteúdo do arquivo para stdout?

23

Eu sei que cat pode fazer isso, mas seu objetivo principal é concatenar em vez de apenas exibir o conteúdo.

Eu também sei sobre less e more , mas estou procurando por algo simples ( não um pager ) que apenas exibe o conteúdo de um arquivo para o terminal e é feito especificamente para isso, se é que existe tal coisa.

    
por confused00 03.09.2014 / 12:59

7 respostas

30

O mais óbvio é cat . Mas também dê uma olhada em head e tail . Há também outras utilidades de shell para imprimir um arquivo linha por linha: sed , awk , grep . Mas esses são para alternar o conteúdo do arquivo ou para pesquisar dentro do arquivo.

Eu fiz alguns testes para estimar qual é o mais eficaz. Eu corro todo o strace para ver qual fez menos chamadas do sistema. Meu arquivo tem 1275 linhas.

  • awk : 1355 chamadas do sistema
  • cat : 51 chamadas do sistema
  • grep : 1337 chamadas do sistema
  • head : 93 chamadas do sistema
  • tail : 130 chamadas do sistema
  • sed : 1378 chamadas do sistema

Como você pode ver, mesmo que cat tenha sido projetado para concatenar arquivos, é o mais rápido e eficaz. sed , awk e grep imprimiram o arquivo linha por linha, por isso eles têm mais de 1275 chamadas de sistema.

    
por 03.09.2014 / 13:52
22

I know cat can do this, but its main purpose is to concatenate rather than just displaying the content.

A finalidade de cat é exatamente isso, ler um arquivo e enviá-lo para o stdout.

    
por 03.09.2014 / 13:03
10

Primeiro, cat grava na saída padrão, que não é necessariamente um terminal, mesmo que cat tenha sido digitado como parte de um comando em um shell interativo. Se você realmente precisa de algo para gravar no terminal mesmo quando a saída padrão é redirecionada, isso não é tão fácil (você precisa especificar qual terminal, e pode não haver um se o comando for executado a partir de um script), embora poderia (ab) usar a saída de erro padrão se o comando for meramente uma parte de um pipeline. Mas desde que você indicou que cat realmente faz o trabalho, eu suponho que você não estava perguntando sobre tal situação.

Se o seu propósito fosse enviar o que está escrito para a saída padrão em um pipeline, então usar cat seria elegível para o Uso inútil do Cat Award , já que cat file | pipeline (onde pipeline representa qualquer pipeline) pode ser feito com mais eficiência como <file pipeline . Mas, novamente, a partir do seu texto, deduzo que essa não era sua intenção.

Portanto, não é tão claro com o que você está se preocupando. Se você achar cat muito longo para digitar, você pode definir um alias de um ou dois caracteres (ainda existem alguns nomes que permanecem sem uso no Unix padrão). Se no entanto você está se preocupando que cat está gastando ciclos inúteis, você não deveria.

Se houvesse um programa null que não aceita argumentos e apenas copia a entrada padrão para a saída padrão (o objeto neutro para pipelines), você poderia fazer o que quiser com <file null . Não existe tal programa, embora seja fácil escrever (um programa C com apenas uma função main de uma linha pode fazer o trabalho), mas chamando cat sem argumentos (ou cat - se você gosta de ser explícito) faz exatamente isso.

Se houvesse um programa nocat que pegasse exatamente um argumento de nome de arquivo, tentasse abrir o arquivo, reclamasse se não pudesse e continuasse copiando do arquivo para a saída padrão, então seria exatamente o que você é pedindo por. É apenas um pouco mais difícil de escrever do que null , o trabalho principal é abrir o arquivo, testar e possivelmente reclamar (se você for meticuloso, também pode incluir um teste que exija apenas um argumento e queixar-se do contrário) . Mas novamente cat , agora fornecido com um único argumento, faz exatamente isso, então não há necessidade de nenhum programa nocat .

Uma vez que você tenha conseguido escrever o programa nocat , por que parar em um único argumento? Embrulhar o código em um loop for(;*argp!=NULL;++argp) não é realmente nenhum esforço, adiciona no máximo duas instruções de máquina ao binário e evita ter que reclamar de um número errado de argumentos (o que poupa muito mais instruções). Voilà uma versão primitiva de cat , concatenando arquivos. (Para ser honesto, você precisa ajustá-lo um pouco para que, sem argumentos, ele se comporte como null .)

Claro que no programa cat real, eles adicionaram alguns sinos e assobios, porque eles sempre fazem. Mas a essência é que o aspecto de "concatenação" de cat não custa realmente nenhum esforço, nem para o programador nem para a máquina que o executa. O fato de cat incluir null e nocat explica a inexistência de tais programas. Evite usar cat com um único argumento se o resultado entrar em um pipeline, mas se for usado apenas para exibir o conteúdo do arquivo no terminal, até mesmo a página que eu associei para admitir que esse é um uso útil de cat , não hesite.

Você pode testar que cat é realmente implementado por um simples loop em torno de uma funcionalidade nocat , chamando cat com vários nomes de arquivos, entre eles um nome inválido, não na primeira posição: em vez de reclamar direito embora esse arquivo não exista, cat primeiro copia os arquivos válidos anteriores e depois reclama do arquivo inválido (pelo menos é assim que meu gato se comporta).

    
por 04.09.2014 / 12:04
7

Em zsh try

<file

Eu acredito que é o caminho mais curto para imprimir um arquivo. Ele usa 'hidden' cat (ou more se stdout for um terminal), mas o comando usado para impressão é controlado pela variável READNULLCMD , que você pode sobrescrever com segurança diretamente pelo nome do comando ou até mesmo por alguma função. Por exemplo, para imprimir arquivos com numeração de linhas:

numcat() { nl -s'> ' -w2 - }
READNULLCMD=numcat
<file
    
por 03.09.2014 / 17:48
5

POSIX define cat como:

NAME

cat - concatenate and print files

SYNOPSIS

cat [-u] [file...]

DESCRIPTION

The cat utility shall read files in sequence and shall write their contents to the standard output in the same sequence.

Então, acho que concatenar significa ler arquivos em sequência .

    
por 03.09.2014 / 13:47
5

Eu sei que esta é uma pergunta do pretérito. Tecnicamente, como imprimir o conteúdo de um arquivo em stdout é uma forma de concatenação, cat é semanticamente apropriado. Não se esqueça que printf é semanticamente destinado a formatar e imprimir dados. Bash também fornece sintaxe para redirecionar entrada e saída de arquivos. Uma combinação destes pode produzir isso:

printf '%s' "$(<file.txt)"
    
por 03.09.2014 / 23:25
3

Usando bash builtins e evitando a criação de subprocessos:

{ while IFS='' read -rd '' _bcat_; do printf '%s
{ while IFS='' read -rd '' _bcat_; do printf '%s%pre%' "${_bcat_}"; done; printf '%s' "${_bcat_}"; unset _bcat_; } <'/path/to/file'
' "${_bcat_}"; done; printf '%s' "${_bcat_}"; unset _bcat_; } <'/path/to/file'

IFS será aplicado apenas ao comando read , portanto, não se preocupe com as alterações globais de IFS .

Loop necessário para lidar com caracteres nulos (graças a Stéphane Chazelas ).

Desta forma, não é adequado para arquivos grandes, porque o conteúdo do arquivo é lido para a variável (então, memória) primeiro. BTW eu tentei imprimir 39M arquivo de texto desta forma e uso de memória bash não excedeu 5M, por isso não tenho certeza sobre este caso.

Também é lento e ineficiente na CPU: para o mesmo arquivo de 39M, demorou ~ 3 minutos com 100% de uso de um único núcleo.

Para arquivos grandes ou binários, é melhor usar cat '/path/to/file' ou até dd if='/path/to/file' bs=1M , se possível.

    
por 07.10.2017 / 11:57

Tags