Automatizando a entrada de texto a partir de um script bash sem usar o EOF

10

Estou executando o Ubuntu Linux. Suponha que exista um programa chamado myprogram. Este programa solicita a entrada do usuário; especificamente, o usuário deve digitar um número inteiro quando solicitado e pressionar Enter. Eu gostaria de automatizar esse processo usando um script bash. Em particular, eu gostaria de executar myprogram, digamos, 100 vezes (usando um contador ique passa de 1para 100). Em cada execução de myprogram, gostaria de inserir o valor atual de iquando solicitado.

(A propósito, myprogramaceita opções / opções -options, todas as quais serão constantes e, portanto, especificadas no script bash.)

Um esqueleto incompleto desse script bash pode ser:

#!/bin/bash
for i in {1..100}
do
   myprogram -options
done

Agora eu gostaria de modificar o código acima para que o valor atual de iseja inserido quando solicitado pelo programa. Qual é a melhor maneira de fazer isso?

O site do software que estou usando sugere usar <<EOFno final da myprogram -optionslinha. Eu acho que isso diz ao bash para olhar para o "final do arquivo" para a entrada usar. Mas e se eu não quiser colocar a entrada no final do arquivo? E se eu gostaria de colocá-lo imediatamente após o <<ou <?

A razão é que as coisas ficarão mais complicadas. Por exemplo, posso introduzir um contador inteiro jque muda de alguma maneira não linear e não seqüencial. Gostaria, então, de alimentar o valor atual de jpara myprogramem cada iteração, mas o valor de jpode mudar entre a chamada myprogram -optionse o final do arquivo EOF.

Você tem alguma sugestão?

Andrew
fonte
Confira este blog - Executando programas interativos
Suresh

Respostas:

14

Para quase todos os programas, ambos echo $i | myprogram -optionse myprogram -options <<<$idevem funcionar, alimentando o programa $ipor meio de entrada padrão.

<foousará o conteúdo do arquivo nomeado foocomo stdin.

<<foousará o texto entre isso e uma linha consistindo apenas foocomo entrada padrão. Este é um documento aqui (heredoc), como disse Gilles; EOFna verdade não significa o final do arquivo, é apenas um delineador heredoc comum (usamos "foo" nesse exemplo).

<<<foousará a string "foo" como entrada padrão. Você também pode especificar uma variável $fooe o shell usará seu conteúdo como stdin, como mostrei acima. Isso é chamado de herestring , pois usa uma cadeia curta em contraste com um bloco inteiro, como em um heredoc. Herestrings funcionam no bash, mas não no /bin/sh.

Kevin
fonte
9

A sintaxe recomendada por este site é chamada de documento aqui . A entrada para o programa de arquivo inicia imediatamente abaixo da linha que contém <<EOF, e não é finalizada no final do script, mas por uma linha que contém exatamente o texto EOF(tome cuidado para não ter espaço em branco extra). A propósito, você pode usar qualquer marcador final que não contenha nenhum caractere especial do shell: EOFnão é uma palavra-chave, é apenas tradicional.

#!/bin/bash
for i in {1..100}
do
   myprogram -options <<EOF
$i
EOF
   for j in {1..42}; do
     myprogram2 <<EOF
$i
$j
EOF
   done
done
Gilles 'SO- parar de ser mau'
fonte
em outras palavras, o EOF nesse contexto significa um marcador de fim de arquivo , não o final real do arquivo de script. o texto "EOF" é qualquer texto arbitrário - o que você usar imediatamente após os caracteres << indicará o final do documento aqui-agora. Normalmente, eu uso o EOF porque ele se destaca e é muito improvável que esteja dentro do documento abaixo se, por exemplo, eu estiver gerando programaticamente o shell script (o que eu faço com bastante frequência).
28812
que o EOF em negrito deve ser <underscore><underscore>EOF<underscore> <underscore>
cas
Usando documentos aqui como esse, muitas vezes mudei o marcador final para algo muito mais significativo (e menos provável de ser correspondido "aleatoriamente"), como END_OF_WHATEVER_FUNCTION. Às vezes, tentar "economizar" espaço / tamanho é realmente um desperdício de esforço, pois causa ambiguidade quanto ao que realmente está acontecendo.
Killermist
Como você pode sleepler comandos a partir do script?
Boltup_im_coding
@ inesperado62 Não entendo o que você está perguntando. Você provavelmente deve fazer uma nova pergunta neste site. Certifique-se de dar contexto suficiente.
Gilles 'SO- stop be evil' em
3

aqui os documentos mencionados por Kevin e Gilles acima, ou a tubulação simples funcionará em muitos casos.

Para situações mais complicadas, você pode procurar no Expect ou similar (por exemplo, o módulo Expect :: Simple CPAN é uma implementação perl muito fácil de usar). pessoalmente, prefiro o módulo perl (o próprio esperado é tcl), mas existem implementações para muitas linguagens de script comuns. É até possível escrever uma implementação muito primitiva da ideia em sh ou bash usando while e read.

A idéia geral do Expect e ferramentas similares é esperar por uma sequência ou padrão especificado na saída de um programa e, em seguida, alimentá-lo com a entrada desejada.

Um exemplo comum de uso é automatizar o login, "esperando" (ou seja, aguardando) a string "ogin:", envie o nome de login e, em seguida, espere a string "word:" e envie a senha.

Uma opção final, se você tiver a fonte do meu programa, é apenas modificá-lo para receber a entrada que você deseja fornecer como uma opção de linha de comando. Isso pode ser um pouco mais trabalhoso, mas será muito menos irritante do que mexer com o Expect ou canalizar dados para um programa que não foi projetado para ser usado dessa maneira.

... e não se esqueça de enviar seu patch para o meu programa de volta para o upstream :) Mesmo que eles não gostem da maneira como você o codificou, eles podem gostar da idéia o suficiente para adicionar o recurso. Os desenvolvedores a montante tendem a apreciar as pessoas que ficam loucas e contribuem em vez de exigir ou reclamar.

cas
fonte