Como posso enviar caracteres para um comando como se viessem de um arquivo?

22

Como posso enviar caracteres para um comando como se viessem de um arquivo?

Por exemplo, eu tentei:

wc < "apple pear orange"
-bash: apple pear orange: No such file or directory
Tyler Durden
fonte

Respostas:

32

Em shells que suportam aqui strings , incluindo bash, zshe ksh93, você pode usar

wc <<< "apple pear orange"
chave de aço
fonte
@Kusalananda graças - Eu editei a sua informação em
steeldriver
18

Duas outras abordagens (que permitem entrada de várias linhas sem esforço extra):

  1. Use um "documento aqui":

    $ wc << EOF
    maçã pêra laranja
    EOF
      1 3 18
    $

    A EOFsequência é um delimitador. Você pode usar qualquer string; EOFé apenas uma escolha convencional.

  2. Use o tty como entrada:

    $ wc
    maçã pêra laranja
    Ctrl+D
      1 3 18
    $

    Isso tem a desvantagem de que o programa começa a ser executado e começa a ler a entrada assim que você digita seu nome. Isso pode ser desconcertante; por exemplo:

    $ grep v
    A raposa marrom rápida              (digitada) 
    salta sobre                       (digitada) 
    salta sobre                       (Isso é saída do grep!) 
    O cachorro preguiçoso.                   (digitado)
    Ctrl + D
                                    (Nenhuma saída aqui) 
    $
G-Man diz que 'restabelece Monica'
fonte
Para o registro: O <<<formulário também permite entrada de várias linhas sem esforço extra, pois a "cadeia de caracteres -enclosed pode conter novas linhas. É claro que o << EOFformulário (a sintaxe original do documento aqui) é mais fácil de ler se você tiver entrada com várias linhas.
21417 alexis
A página de manual diz que aqui a sintaxe da string é <<< word- é claro, no contexto do shell, a wordpode ser uma string citada, contendo espaços e novas linhas! D'oh! Isso é tão óbvio que nem é preciso dizer (e, de fato, não vejo isso mencionado na página de manual). :-( Obrigado por me indicar isso!
G-Man diz 'Reinstate Monica'
Eu não chamaria isso de simples ou óbvio, na verdade. A wordé definido na página de manual como "Uma sequência de caracteres considerados como uma única unidade pelo shell" (também conhecida como "token") e você precisa saber que as seqüências de caracteres entre aspas são tratadas como "uma única unidade" no sentido relevante (após processamento de barra invertida, expansão variável etc. "Mas, na verdade, esse é o objetivo de fazer aspas duplas no shell. (As aspas simples também protegem da expansão.) O modelo de processamento do shell é muito bem pensado e é tudo menos simples.
alexis
@alexis: Quando passo por cima e incluo um emoticon, deve-se considerar a possibilidade de estar sendo irônico.
G-Man Diz 'Reinstate Monica'
10

Embora existam várias soluções válidas aqui outra sintaxe que pode ser às vezes úteis, é executar um comando no <(). Isso permitiria criar mais de um objeto descritor de arquivo em uma linha de comando.

Isso pode ser útil quando você estiver fazendo algo como comparar longas sequências de texto ou se quiser diferenciar algum conteúdo que não esteja em um arquivo.

Por exemplo, comparando os arquivos hosts em dois nós sem precisar copiar o arquivo hosts no host local:

diff -Naur <(cat /etc/hosts) <(ssh -q otherhost 'cat /etc/hosts')

O <redireciona um arquivo para STDIN e ()cria um subshell para executar o comando entre parênteses. É o STDOUT do subshell que é passado para STDIN do comando que está sendo executado.

É uma maneira mais fácil de criar mais de 1 "arquivo" de entrada para um comando do que tentar usar vários documentos aqui, ou tentar repetir vários comandos em um pipeline para o comando final.

Tim Kennedy
fonte
<fileorpathnameredireciona stdin, mas <(subcmd)não; ele substitui um nome que quando / se aberto pelo programa pode ler stdout do subcmd. < <(subcmd)(espaço necessário) faz redirecionamento stdin a partir desse ficheiro, quase como subcmd |. Você diffpode ler uma das entradas do stdin especificando um argumento, -mas não ambos.
precisa saber é o seguinte
Essa é uma substituição de processo que não é suportada, ao contrário das partes que você afirma serem feitas (mas não é como a Dave explicou).
Phk #
1
Meu diff funciona bem no bash nos sistemas Ubuntu 16.04 e Solaris 11.2 com os quais tenho que testar. É possível que não funcione para todos os shells em todos os sistemas operacionais. Na verdade, ele está criando descritores de arquivo que podem ser usados ​​para ler a saída do subprocesso como se estivesse lendo um arquivo. Como o diff usa dois argumentos de arquivo, ele pode ler a saída de ambos os subprocessos através dos descritores de arquivo criados e compará-los.
Tim Kennedy
Você pode adicionar à sua resposta a diferença entre cmd <(cmd2 ...)e cmd < <(cmd2 ...). O primeiro permite que dados derivados (a saída do cmd2) sejam usados ​​no lugar de um nome de arquivo. O último é equivalente a cmd2 ... | cmd. Os comandos devem ser escritos para aceitar explicitamente a entrada stdin e muitos não. Isto é especialmente verdade nos scripts de shell.
precisa saber é o seguinte
8

você pode usar um cachimbo

echo "apple pear orange" | wc
Slh47
fonte
8
Um canal não é o mesmo que "ler de um arquivo". Por exemplo, você não pode procurar para trás em um pipe, enquanto em um arquivo.
Rbialon
0

Você pode usar algo semelhante ao esperado. A seguir, é apresentado um exemplo simples de como abrir uma sessão remota de telnet, aguardando o prompt, enviar alguns dados, aguardar uma resposta, dormir e sair.

#!/usr/bin/expect
spawn telnet localhost 8555
expect "Escape character is '^]'."
send "Hello World\n"
expect "Connection closed by foreign host."
sleep 1
Covarde anônimo
fonte