Qual é a diferença entre STDIN e argumentos passados ​​para o comando?

16

Eu poderia usar o formulário para executar o catmétodo:

cat file_name
cat < file_name

O resultado é o mesmo

Então eu quero executar manno formato destdin

man < file_name

Enquanto file_namecontém:

# file_name
cat

Mas aparece em What manual page do you want?vez de executar man cat.

Quero saber por que catpoderia aceitar stdincomo argumentos, mas mannão posso. E qual é a diferença entre argumentos de linha de comando e stdin?

Steveyang
fonte

Respostas:

21

Sua pergunta está intimamente relacionada a como o shell que você está usando analisa a entrada do usuário na linha de comando.

Se a primeira palavra na linha de comando for um programa, localizado em uma pasta especial (geralmente definida por PATH) e não houver mais caracteres especiais (depende do shell que você está usando), todas as palavras subsequentes separadas por espaços ou tabulações serão passadas para o programa de uma forma especial, ou seja, uma matriz. Com cada palavra como um elemento na matriz.

Como o programa que você vai chamar interpreta os argumentos (localizados na matriz) depende de como ele é programado. Existem alguns padrões para a aparência da sintaxe dos argumentos, mas em geral o programador é totalmente gratuito. Portanto, o primeiro argumento pode ser interpretado como o nome de um arquivo ou qualquer que seja o pensamento do programador na época em que ele escreveu o programa.

No caso de você adicionar o carácter especial <ou >a sua linha de comando, o acréscimo shell dosn't <e >nem palavras subseqüentes para a matriz que será passado para o programa. Com <ou >dado, o shell começa a criar coisas sofisticadas, suportadas pelo kernel subjacente ( canal de palavras-chave ). Para entender o que está acontecendo, você deve entender o que STDINe STDOUT(já que não está imediatamente relacionado, eu omito STDERR) são.

Tudo o que você vê no seu terminal (na maioria dos casos, parte do seu monitor) é gravado pelo shell ou por qualquer outro programa que você chamou anteriormente em um arquivo especial (no unix, tudo é um arquivo ). Este arquivo tem um ID especial e é chamado STDOUT. Se um programa deseja ler dados do teclado, ele não pesquisa diretamente o teclado (pelo menos na maioria dos casos), mas lê de um arquivo especial chamado STDIN. Internamente, esse arquivo está conectado ao seu dispositivo de entrada padrão, seu teclado na maioria dos casos.

Se o shell lê <ou >em uma linha de comando analisada, ele manipula STDINou STDOUTde um tipo específico pelo tempo em que o programa correspondente está sendo executado. STDINe STDOUTnão aponte mais para o terminal ou o dispositivo de entrada padrão, mas para o nome do arquivo subsequente na linha de comando.

No caso das duas linhas

cat file_name
cat < file_name

o comportamento observado é idêntico porque o desenvolvedor correspondente faz catpara ler dados STDINou ler os dados do arquivo, cujo nome é dado como o primeiro argumento da linha de comando (que é o primeiro elemento na matriz para a qual o shell passa cat). Posteriormente, catgrava todo o conteúdo de file_nameou STDINpara o terminal, pois não instruímos o shell a manipular STDOUT. Lembre-se de que na segunda linha seu shell manipula STDINdessa maneira, que não aponta mais para o seu dispositivo de entrada padrão, mas aponta para um arquivo chamado file_nameno seu diretório de trabalho atual.

No outro caso da linha

man < file_name

mannão pretende ler nada, STDINse for chamado sem argumento, ou seja, uma matriz vazia. Então a linha

man < file_name

é igual a

man

Por exemplo, mantambém lerá algo de STDINse você passar -l -para man. Com esta opção fornecida na linha de comando, você pode exibir o conteúdo de qualquer coisa manlida STDINno seu terminal. então

man -l - < file_name

funcionaria também (mas tenha cuidado mannão é apenas um pager, mas também analisa a entrada do arquivo e, portanto, o conteúdo do arquivo e o conteúdo exibido podem ser diferentes).

Então STDIN, como STDOUTe os argumentos da linha de comando são interpretados, tudo depende do desenvolvedor correspondente.

Espero que minha resposta possa esclarecer as coisas.

user1146332
fonte
Obrigado por esta explicação detalhada. Nos seus últimos parágrafos, você mencionou o uso man -l - < file_namepara maninterpretar STDINcomo argumentos, mas ele falha no meu sistema com o STDERR:man -l - < tee man: invalid option -- l man, version 1.6c
steveyang
Seja bem-vindo. Mas eu não mencionei que pelo menos minha versão do man( man-db ) lê argumentos STDINcom os argumentos fornecidos, -lseguidos por -. Ele apenas interpreta os dados STDINcomo uma página de manual. Para explicações mais detalhadas dos argumentos válidos e como eles são interpretados, você deve consultar a página de manual do programa relacionado. No seu caso, consulte man man. Talvez haja uma opção semelhante para o seu man. Se você quiser ler os argumentos da linha de comando para um programa específico STDIN xargs(como mencionado acima), é o caminho a seguir.
usar o seguinte comando
Eu man mane o local no meu sistema operacional não o suporta. De qualquer forma, obrigado por esta declaração desses dois conceitos para mim.
steveyang
Eu editei sua resposta para que ela contenha links realmente úteis em vez de lmgtfy. A publicação de links lmgtfy é 1) rude, 2) inútil e 3) realmente desaprovada nos sites do SE. Forneça um link ou não, mas se você optar por fazê-lo, forneça um link para informações reais e não para uma maneira sarcástica de mostrar a alguém como encontrá-las.
terdon
12

Eles são completamente diferentes. Os argumentos da linha de comando são passados ​​para o programa em uma matriz e ele pode fazer o que quiser com eles; stdin é um fluxo de entrada do qual o programa solicita dados. Os programas que processam arquivos geralmente optam por oferecer suporte a ambos, mas precisam fazê-lo manualmente - verificam se um nome de arquivo foi passado como argumento da linha de comando e, se não, eles lêem em stdin

Você espera manler stdin para encontrar a página de manual que deve exibir, o que seria um comportamento realmente estranho; quando você usaria isso? O fato de catexibir seu stdin é um artefato do fato de que ele não faz mais nada; Eu não acho que nenhuma outra ferramenta funcione dessa maneira. Por exemplo, greppode pegar um nome de arquivo ou ler stdin, mas processa os dados stdin, não lê um nome de arquivo stdine, em seguida, abre-o

Se você realmente precisar desse comportamento, poderá usar o xargsque converte um arquivo em argumentos da linha de comando:

$ xargs man < file_name

Ou apenas incorpore uma catchamada na manchamada:

$ man $(cat file_name)
Michael Mrozek
fonte
No bash, você pode usar man $(<file_name).
jordanm
Re: "Eu não acho que qualquer outra ferramenta funciona dessa maneira" - Perl (<>)em um loop vai fazer STDINou argumentos de linha de comando como nomes de arquivos ...
Aaron D. Marasco
@ AaronD.Marasco eu quis dizer nenhuma ferramenta seja leva um argumento ou lê um nome de arquivo da entrada padrão e lê o argumento a partir desse arquivo
Michael Mrozek
@MichaelMrozek Obrigado por este esclarecimento. O objetivo que usei man < file_nameé me ajudar a entender esses dois conceitos. Lendo sua explicação, a implementação é decidida pelo autor do comando. Então, se eu estiver certo, o findargumento leva processa STDIN?
steveyang