Passar texto para o programa esperando um arquivo

30

Relacionado a uma pergunta que fiz no Stack Overflow: Passando várias linhas de código para o wsadmin.sh? .

Eu tenho, como uma string, algumas linhas de entrada que eu preciso alimentar em um comando. O comando, no entanto, aceita apenas um arquivo cheio de entrada.

Existe alguma maneira de armazenar as linhas em um arquivo ou canal temporário que nunca é realmente gravado em disco e depois alimentá-lo diretamente no programa?

Como faço para adquirir o tubo, alimentar a entrada dele, passar o tubo para o comando e depois me livrar do tubo?

ArtOfWarfare
fonte
2
Você pode adicionar um exemplo do comando que está usando e como ele deve ser chamado?
Breakthrough
2
Isso significa que o programa não aceita stdin?
Léo Lam
Eu concordo com os dois comentadores acima. É impossível sugerir qualquer coisa que possa funcionar sem conhecer as especificações do programa.
Larssend 13/07/2015

Respostas:

27

Outra solução é usar a Substituição de Processo no Bash. Se o seu sistema tiver nomeado pipes, você poderá usar esse recurso.

É usado assim:

program_expecting_a_file <(list)

Onde listestá uma sequência de comandos do shell (na verdade pipelines; os detalhes completos estão aqui ). listserá executado e sua saída será conectada ao tubo. O nome do canal é passado para o seu programa.

NOTA: não são permitidos espaços entre <e (.

(A outra substituição >(list)também funciona como você esperaria.)

No seu caso específico, você pode usar

program_expecting_a_file <(echo "$your_strings")

embora você possa achar a solução do @ meuh mais elegante.

Atualização: Muitos exemplos de uso podem ser encontrados no Advanced Bash Scripting Guide .

Edward
fonte
Os outros dois não funcionaram nem nos casos mais triviais. O seu passa nos testes que fiz até agora. Eu votei no seu por agora. Voltarei e marcarei como aceito se fizer tudo o que preciso.
ArtOfWarfare
O seu funciona perfeitamente. Se desejar, você pode adicioná-lo à pergunta relacionada no StackOverflow e também posso aceitá-lo por lá. stackoverflow.com/questions/31374202/…
ArtOfWarfare
Olá @ArtOfWarfare, prazer em ajudar. Já existe um comentário com a mesma solução proposta, portanto não seria correto postar uma resposta lá.
Edward
Você postou sua solução antes dele. De qualquer forma, pedi a ele que alterasse seu comentário para uma resposta para que eu pudesse aceitá-lo. Se nenhum de vocês postar respostas dentro de ~ 24 horas sobre essa pergunta, eu mesmo postarei a resposta para que eu possa aceitá-la (não gosto de deixar minhas perguntas como sem resposta depois de descobrir qual é a resposta. apenas maus modos para futuros leitores / potenciais respondentes da questão).
ArtOfWarfare
Olá @ArtOfWarfare, estou absolutamente bem com o que você propõe!
Edward
15

Você pode usar um documento aqui do bash . Por exemplo,

$ cat -n <<<'a
> b'
 1  a
 2  b

Se você tem algo em uma variável bash, também pode interpolar: por exemplo <<<"path is $PATH".


Se o seu comando insistir em um nome de arquivo, você poderá atribuí-lo /dev/stdin. Por exemplo:

$ sed -f /dev/stdin <<<'s/a/b/'

produz a saída: s/b/b/.

meuh
fonte
Não está claro na questão se o comando aceita entrada stdine, se não, isso não vai funcionar. Espero que o OP esclareça.
David Z
1
:( - Isso parecia super promissor, mas quando eu tentei, eu tenho a mensagem de erro"-f" option must be followed by a file name.
ArtOfWarfare
Um documento aqui é para stdin. Se seu comando absolutamente precisar -fe um nome de arquivo, forneça o nome do arquivo /dev/stdin. Veja minha edição.
Meu 13/07/2015
Acho que depois das edições é absolutamente uma opção viável!
Edward
1
+1 para a /dev/stdinsugestão. O programa que estou tentando chamar aceita apenas um nome de arquivo, então combinei /dev/stdincom um heredoc.
Huw Walters
7

Dependendo do conteúdo do script, você poderá usar o nome de arquivo especial - (menos), que significa stdin

$ mycmd -
Line 1
Line 2
^D

Outro método que pode funcionar para você é abrir o arquivo /dev/fd/0que novamente significa stdin .

Uma terceira opção pode ser criar um FIFO (primeiro a entrar, primeiro a sair). Isso é como um arquivo, mas tem duas extremidades - você escreve em uma extremidade e lê na outra.

-- Process 1 --                  -- Process 2 --
$ mkfifo foo
$ cat foo
<waits>                          $ echo hello > foo
hello                            $
$ rm foo
Majenko
fonte
3
Pode ser interessante notar que o programa precisa ser escrito para interpretar -dessa maneira - não é um recurso do shell ou do sistema operacional. Embora, é claro, a maioria dos utilitários padrão do Linux siga esta convenção, tanto quanto eu sei.
David
1
Não. Isso não funciona para o programa. Existe um modo interativo, mas quero passar os comandos para executar neste programa a partir de outro programa, e não quero entrar na toca do coelho expect.
ArtOfWarfare
@ArtOfWarfare Acabei de adicionar uma terceira opção que pode funcionar.
Majenko 13/07/2015
Boa resposta! A segunda e terceira opções são basicamente como a <()solução, mas mais explícitas - o que pode ser muito útil!
Edward
4

Há outra opção semelhante à mycmd -solução, mas mesmo para programas que não tratam -especificamente:

$ mycmd /dev/stdin
Line 1
Line 2
^D

/dev/stdin parece estar relacionado ao sistema operacional e funciona para mim no Debian GNU / Linux, mas não tenho certeza de onde mais ele funcionará.

Axel Beckert
fonte
1
Parece que pode funcionar, mas o que é ^D?
ArtOfWarfare
^Dé uma notação comum para pressionar Ctrl-D. ^ D tem a semântica de "fim do fluxo de entrada" aqui. Provavelmente é visto com mais frequência ^Cou ^Zque significa pressionar Ctrl-C, respectivamente, pressionando Ctrl-Z.
Axel Beckert
1
Isso parece funcionar, mas como eu colocaria as coisas programaticamente /dev/stdine depois as fecharia?
ArtOfWarfare
1
Basta colocar algo nesse comando e ele deve funcionar, ie cat content | mycmd /dev/stdin. Imagine comandos diferentes do que cataqui.
Axel Beckert