Por que o sinal de menor que não funciona como um substituto para o gato no bash?

17

Ouvi falar de "uso inútil de gato" e encontrei algumas sugestões, mas as seguintes não produzem nada no meu shell bash.

< filename

Usar o gato funciona como esperado.

cat filename

Estou usando o Fedora Core 18 e o GNU bash, versão 4.2.45 (1).

EDIT: Usá-lo na frente de um tubo também não funciona.

< filename | grep pattern

Considerando que o uso de gato funciona como esperado.

cat filename | grep pattern

EDIT2: Para esclarecer, eu sei que posso usar esse

grep pattern < filename

mas eu li aqui /programming/11710552/useless-use-of-cat que também posso usá-lo na frente do comando. Porém, ele não funciona na frente do comando.

erro
fonte
2
Funciona. O que você tentou não é o mesmo que o comentário de Jonathan Leffler sugere.
manatwork
"O objetivo do gato é concatenar (ou" catenar ") os arquivos. Se for apenas um arquivo, concatená-lo sem nada é uma perda de tempo e custa um processo." partmaps.org/era/unix/award.html
Scott,

Respostas:

22

O símbolo menor que e ( <) está abrindo o arquivo e anexando-o ao identificador padrão do dispositivo de entrada de algum aplicativo / programa. Mas você não deu ao shell nenhum aplicativo para anexar a entrada.

Exemplo

Estes 2 exemplos fazem essencialmente a mesma coisa, mas obtêm sua contribuição de duas maneiras ligeiramente diferentes.

abre arquivo

$ cat blah.txt 
hi

abre STDIN

$ cat < blah.txt 
hi

Espreitar por trás da cortina

Você pode usar stracepara ver o que está acontecendo.

Quando lemos de um arquivo

open("blah.txt", O_RDONLY)              = 3
fstat(3, {st_mode=S_IFREG|0664, st_size=3, ...}) = 0
fadvise64(3, 0, 0, POSIX_FADV_SEQUENTIAL) = 0
read(3, "hi\n", 65536)                  = 3
write(1, "hi\n", 3hi
)                     = 3
read(3, "", 65536)                      = 0
close(3)                                = 0
close(1)                                = 0

Quando lemos do STDIN (identificado como 0)

read(0, "hi\n", 65536)                  = 3
write(1, "hi\n", 3hi
)                     = 3
read(0, "", 65536)                      = 0
close(0)                                = 0
close(1)                                = 0

No primeiro exemplo, podemos ver que catabriu o arquivo e leu a partir dele blah.txt. No segundo, podemos ver que catlê o conteúdo do arquivo blah.txtatravés do descritor de arquivo STDIN, identificado como descritor número 0.

read(0, "hi\n", 65536)                  = 3
slm
fonte
1
Então essa conversa sobre o uso inútil de um gato é falsa?
bug
@ bug - não, existem usos. Mas catgeralmente é mal compreendido e é usado quando não é necessário.
slm
Mas é necessário quando eu quero preservar a ordem das operações da esquerda para a direita? Eu li que também é possível usar a construção menor que na frente do comando.
bug
@ bug sim, o redirecionamento pode ocorrer antes ou depois do comando, veja a resposta de Stephane, ele mostra este exemplo também.
slm
Ah, agora entendi. Eu teria que escrever < filename command.
bug
14

O uso inútil clássico de caté quando você o utiliza para dar entrada em programas perfeitamente capazes de abrir arquivos diretamente. Por exemplo:

Mau

cat file | grep foo
cat file | while read line; do echo "$line"; done
cat file | sed 's/a/b/'
cat file | awk '{print $1}'

Boa

grep foo file
while read line; do echo "$line"; done < file 
sed 's/a/b/' file
awk '{print $1}' file

Também é bom ( <filepode estar em ambos os lados do comando)

<file grep foo
 sed 's/a/b/' < file
<file awk '{print $1}' 
terdon
fonte
6
"Mau" é subjetivo aqui. Acho que essas são melhores em geral, porque é muito mais consistente e fácil de ler. E o fluxo de dados é totalmente da esquerda para a direita, como deveria ser, se há mais tubos envolvidos
Izkata
2
@ Izkata eles são "ruins" no sentido de que são usos inúteis cat.
terdon
"Baixa! Saia da mesa! Você é um gato ruim! ”;-) Mas sério ...
G-Man diz 'Reinstate Monica'
1
Boa digno de nota (ou, pelo menos, úteis) usos de catincluir (1) cat file(com saída para a tela / terminal; embora, se o arquivo é maior do que a tela é alta, você pode preferir usar moreou lessou algo parecido), (2) cat file1 file2 file3 > all_data( exatamente para que catserve), (3) cat f1 f2 f3 | tr …(ou canalize para qualquer outro programa para o qual você não queira passar os arquivos diretamente; por exemplo, wc(por exemplo, se você quiser ver apenas o total geral) ou grep(por exemplo, se você tem uma versão antiga que não suporta -h, por exemplo, --no-filename)),… (continua)
G-Man diz 'Reinstate Monica' '
(Continua) ... (4) cat -n file | sort … -k1 | sed 's/^ *[0-9]*\t//', (5) sudo cat file600 | untrusted_program(ou seja, você (seu UID) não pode ler o arquivo e não deseja executar o programa como root ou mesmo qualquer UID semi-privilegiado). Além disso, ( e ) (ou seja, um número entre 2 e 3) program_that_generates_html | cat static_html_header - static_html_footer(que você provavelmente desejaria redirecionar para um arquivo ou canal).
G-Man diz 'Reinstate Monica'
13

O UUOC está em:

cat somefile | some-cmd

ou

cat < somefile | some-cmd

Lá, some-cmdestá lendo o conteúdo de somefileum tubo alimentado pelo catqual ele o lê somefile.

some-cmdpode ler diretamente de somefile(depois que o shell o abriu no stdin), não há necessidade de cat:

some-cmd < somefile

ou

< somefile some-cmd

(os redirecionamentos podem aparecer em qualquer lugar em uma linha de comando simples).

Stéphane Chazelas
fonte