Comando para saída do conteúdo do arquivo para stdout?

28

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

Eu também conheço lesse more, mas estou procurando por algo simples ( não um pager ) que apenas envie o conteúdo de um arquivo para o terminal e seja feito especificamente para isso, se houver.

confused00
fonte
11
Na verdade, 99% das vezes que você usa o gato é exibir arquivos em vez de concatenar qualquer coisa.
LatinSuD
11
@LatinSuD - 100% do tempo - catconcatena.
mikeserv
@ mikeserv: É uma questão do que você quer dizer com executar uma operação; o uso normal da linguagem seria sugerir que isso é feito pelo menos uma vez. "Imprimir" uma sequência vazia não envolve a impressão de caracteres; seria justo dizer que não está imprimindo nada. Agora, a computação a+b+cenvolve a realização de duas adições, e a computação anão envolve a adição de nada. Da mesma forma, executar cat fnão envolve concatenar nada (mesmo que essa seja a única coisa que "concatenar uma sequência de um arquivo" possa significar).
Marc van Leeuwen
2
@ MikeServ: Eu não entendo o que você quer dizer com in + out. Claro, catlê um arquivo e grava outro arquivo (stream), mas isso não significa que concatenou alguma coisa. Talvez você queira dizer que cat frealmente está fazendo cat - f, isso simplesmente não é verdade.
Marc van Leeuwen
11
@ confused00: catfoi realmente feito para concatenar ( cat file1 file2concatenará os dois arquivos para o stdout). Mas o efeito colateral é que, ao ter apenas um arquivo como argumento, ele gera esse arquivo para stdout (onde quer que vá, seja no seu terminal ou redirecionado para alguma coisa). Portanto, não havia outro comando criado apenas para produzir no stdout, como catexistia e o permitia simplesmente. Portanto, você deseja usar cat.
Olivier Dulac

Respostas:

37

O mais óbvio é cat. Mas, também dê uma olhada heade tail. Há também outros utillities shell para imprimir um arquivo linha por linha: sed, awk, grep. Mas isso é para alternar o conteúdo do arquivo ou pesquisar dentro do arquivo.

Fiz alguns testes para estimar qual é o mais eficaz. Eu corro todo o caminho stracepara ver o que fez menos chamadas de 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 tenha catsido projetado para concatenar arquivos, é o mais rápido e eficaz. sed, awkE grepimprimiu o arquivo linha por linha, por isso que eles têm mais que 1275 chamadas do sistema.

caos
fonte
8
Boa idéia para contar os syscalls!
Jan
11
+1, a resposta é mais preciso (sobre o significado de gato), mais completos (alternativas), e pesquisados (syscalls)
Olivier Dulac
23

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

O objetivo caté exatamente isso, leia um arquivo e envie para stdout.

Jan
fonte
11
Mas cat --helpdiz "Concatenar FILE (s), ou entrada padrão, para saída padrão". Eu não quero concatenar nada
confused00
18
Acredite ou não, gato é exatamente o que você está procurando de qualquer maneira.
Jan
5
Não, @ confused00, Jan está certo. O problema é - o terminal está desativado - você vê? faça readlink /dev/fd/1por exemplo - você deve colocar o nome do seu tty lá se estiver executando em um prompt padrão. Portanto, concatenar entrada e saída é o que você está pedindo para fazer.
mikeserv
2
@ MikeServ Sim, entendo o seu ponto, acho que estava muito fixo no significado de 'concatenar'.
confused00
3
A lógica é que imprimir o conteúdo de um arquivo é apenas um caso especial de imprimir o conteúdo de um ou mais arquivos em sequência.
zwol
10

Primeiro, catescreve na saída padrão, que não é necessariamente um terminal, mesmo que tenha catsido digitado como parte de um comando em um shell interativo. Se você realmente precisa escrever algo no terminal, mesmo quando a saída padrão é redirecionada, isso não é tão fácil (você precisa especificar qual terminal e talvez não exista um se o comando for executado a partir de um script), embora um poderia (ab) usar a saída de erro padrão se o comando for apenas uma parte de um pipeline. Mas como você indicou que catrealmente faz o trabalho, suponho que não estava perguntando sobre essa situação.

Se o seu objetivo fosse enviar o que está escrito para a saída padrão em um pipeline, o uso catseria elegível para o Useless Use of Cat Award , pois cat file | pipeline(onde pipelineestá qualquer pipeline) pode ser feito com mais eficiência <file pipeline. Mas, novamente, pelas suas palavras deduzo que essa não era sua intenção.

Portanto, não está tão claro com o que você está se preocupando. Se você achar catmuito tempo para digitar, poderá definir um alias de um ou dois caracteres (ainda existem alguns desses nomes que permanecem sem uso no Unix padrão). Se, no entanto, você está preocupado com o fato de catgastar ciclos inúteis, não deveria.

Se houver um programa nullque não aceite argumentos e apenas copie a entrada padrão para a saída padrão (o objeto neutro para pipelines), você poderá fazer o que quiser <file null. Não existe um programa desse tipo, embora seja fácil escrever (um programa C com apenas uma mainfunção de uma linha pode fazer o trabalho), mas chamar catsem argumentos (ou cat -se você quiser ser explícito) faz exatamente isso.

Se houvesse um nocatprograma que recebesse exatamente um argumento de nome de arquivo, tentasse abrir o arquivo, o reclamasse se não puder e, caso contrário, continuasse copiando do arquivo para a saída padrão, isso seria exatamente o que você estava solicitando. É 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 poderá incluir um teste de que existe exatamente um argumento e reclamar do contrário). Mas cat, novamente , agora fornecido com um único argumento, faz exatamente isso, portanto não há necessidade de nenhum nocatprograma.

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

Obviamente, no catprograma real , eles acrescentaram alguns sinos e assobios, porque sempre o fazem. Mas a essência é que o aspecto de "concatenação" dos catcustos realmente não exige nenhum esforço, nem para o programador nem para a máquina que o executa. O fato de que catsubsume nulle nocatexplica a inexistência de tais programas. Evite usar catcom um único argumento se o resultado entrar em um pipeline, mas se for usado apenas para exibir o conteúdo do arquivo no terminal, mesmo a página que eu vinculei admite que esse é um uso útil cat, portanto, não hesite.


Você pode testar o que caté realmente implementado por um loop simples em torno de uma nocatfuncionalidade hipotética , chamando catcom vários nomes de arquivos entre os quais um nome inválido, não na primeira posição: em vez de reclamar imediatamente que esse arquivo não existe, catprimeiro despeja o precedente arquivos válidos e depois reclama do arquivo inválido (pelo menos é assim que meu gato se comporta).

Marc van Leeuwen
fonte
7

Sob zshtentativa

<file

Eu acredito que é a maneira mais curta de imprimir um arquivo. Ele usa 'hidden' cat(ou morese stdout é um terminal), mas o comando usado para impressão é controlado por READNULLCMDvariável que você pode sobrescrever com segurança diretamente pelo nome do comando ou mesmo por alguma função. Por exemplo, para imprimir arquivos com numeração de linha:

numcat() { nl -s'> ' -w2 - }
READNULLCMD=numcat
<file
jimmij
fonte
5

O POSIX define gato como:

NOME

cat - concatena e imprime arquivos

SINOPSE

gato [-u] [arquivo ...]

DESCRIÇÃO

O utilitário cat deve ler os arquivos em sequência e escrever seu conteúdo na saída padrão na mesma sequência.

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

cuonglm
fonte
5

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

printf '%s' "$(<file.txt)"
James M. Lay
fonte
4
Além de ser particularmente indireto, o comando exibido não é equivalente a cat file.txt, pois removerá as novas linhas finais (o $(...)faz isso).
Marc van Leeuwen
+1, boa captura. Não sabia isso.
James M. Lay
3

Usando bashbuiltins e evitando a criação de subprocessos:

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

IFSserá aplicado apenas ao readcomando, portanto, não se preocupe com suas IFSalterações globais .

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

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

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

Para arquivos grandes ou binários melhores para usar cat '/path/to/file'ou mesmo dd if='/path/to/file' bs=1Mse possível.

Mikhail
fonte
11
Veja também pv -qqual Linux pode usar splice()e, para alguns tipos de stdin / stdout, melhorará o desempenho.
Stéphane Chazelas
1

Apenas como demonstração, você pode fazer

cp foo /dev/stdout
wisbucky
fonte