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?


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 .


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/.


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

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á.


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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.