Como leio várias linhas de STDIN em uma variável?


24

Eu estive pesquisando esta questão no Google. Estou automatizando um processo de compilação aqui no trabalho, e tudo o que estou tentando fazer é obter números de versão e uma pequena descrição da compilação que pode ser de várias linhas. O sistema executado é o OSX 10.6.8.

Eu já vi tudo, desde o uso do CAT até o processamento de cada linha, conforme necessário. Não consigo descobrir o que devo usar e por quê.

Tentativas

read -d '' versionNotes

Resulta em entrada ilegível se o usuário precisar usar a tecla backspace. Também não há uma boa maneira de finalizar a entrada, pois ^ D não termina e ^ C apenas sai do processo.

read -d 'END' versionNotes

Funciona ... mas ainda ilumina a entrada se a tecla backspace for necessária.

while read versionNotes
do
  echo "  $versionNotes" >> "source/application.yml"
done

Não finaliza corretamente a entrada (porque estou muito atrasado para procurar uma correspondência vazia).


Você está recebendo essas informações do usuário, correto?
Glenn Jackman

Corrigir; Quero que o usuário insira essas informações no terminal ao executar o script.
Robert K

1
Você não se deixou claro, eu prefiro dizer.
poige

Respostas:


20

man bash menciona «…

A substituição do comando $ (arquivo cat) pode ser substituída pelo equivalente, mas mais rápido, $ (<file).

... »

$ myVar=$(</dev/stdin)
hello
this is test
$ echo $myVar
hello this is test
$ echo "$myVar"
hello
this is test

e eu concordo que vale a pena mencionar - echo "$myVar"teria exibido a entrada como foi dada.


1
Como parar após a entrada de várias linhas? Se eu pressionar Ctrl C, ele para, mas a variável não é salva!
22618 Nikhil

2
Terminais UNIX têm "disciplina": en.wikipedia.org/wiki/Line_discipline • Confira o que significa "eof" média • Do ler man stty, descobrir como obter as configurações atuais
poige

2
Ctrl-d para parar.
FREB

9

Tente o seguinte:

user@host:~$ read -d '' x <<EOF
> mic
> check
> one
> two
> EOF

Sem quebras de linha:

user@host:~$ echo $x
mic check one two

Com quebras de linha:

user@host:~$ echo "$x"
mic
check
one
two

2
-d ''é exatamente o que eu precisava. Obrigado
Bruno Bronosky

@Bruno O prazer é meu; é complicado. Especialmente à primeira vista, parece bastante padrão. No entanto, pode ser bastante útil quando você pegar o jeito das várias idiossincrasias.
voices


2

Resolvi esse problema lidando com cada linha até encontrar uma linha em branco. Funciona bem o suficiente para a minha situação. Mas se alguém quiser adicionar uma solução melhor, sinta-se à vontade para fazê-lo.

echo "---
notes: |" > 'version.yml'

while read line
do
  # break if the line is empty
  [ -z "$line" ] && break
  echo "  $line" >> "source/application.yml"
done

Use em read -rvez disso.
adaptr

2

Você pode iniciar um editor como vim, pico ...

${VISUAL:-${EDITOR:-vi}} source/application.yml

Hum ... como isso responde à pergunta do OP de alguma forma?
adaptr

Ele pode iniciar o editor a partir do script.
Mircea Vutcovici

E isso realiza o que exatamente? Ele deseja usar o texto de um arquivo no script, não gravar informações em um arquivo.
adaptr

Ele não precisava ler o texto do usuário e gravá-lo em um arquivo. Por favor, leia os comentários adicionados à pergunta.
Mircea Vutcovici

1

Primeiro, algumas correções:

  1. Para permitir "edição" na linha, use o -euso de readline (para que você tenha o histórico do bash e todos os recursos de edição)
  2. -dleva apenas um personagem. Por exemplo, de 'END' pega 'E' e sempre que o usuário escreve um 'E' a leitura para (acho que não é isso que você deseja ...)

Existem algumas possibilidades para fazer isso. Eu leria linha por linha e pararia quando uma linha vazia fosse encontrada (embora você possa definir qualquer palavra de parada):

unset tmp
while :
do 
 read line
 [[ $line == "" ]] && tmp="${tmp:0:$((${#tmp}-1))}" && break
 tmp="$tmp"$line$'\n'
done

0

Você tem vários métodos.

Um dos métodos mais simples é:

MYVAR=$(yourcommand)
echo $"MYVAR"

Por exemplo:

MYVAR=$(ls /)
echo $"MYVAR"

Exceto que não estou executando um comando de shell como o LS. Estou solicitando entrada de várias linhas do usuário.
Robert K

Esta é uma prática muito ruim; não processe a saída de ls!
adaptr

@adaptr Já ouvimos tudo isso antes, você se importaria em sugerir uma boa alternativa, por favor?
voices

0

Estamos usando uma construção usando xargs e ctrl-d para quebrar. Eu não estou perfeitamente satisfeito com isso, mas certamente faz o trabalho de receber entradas de usuários com várias linhas e inserir essas variáveis ​​em uma variável (formatação intacta). (A primeira e a terceira atribuições adicionam aspas ao conteúdo da entrada xargs.)

    printf "\\033[1mWhen finished hit ctrl-d on a new line to proceed.\\033[0m  \\n\\n" 
    # this will load the user's input into a variable instead of a file 
    reminderBody="\"" 
    reminderBody+=$( xargs -0 ) 
    reminderBody+="\"" 

Usamos reminderBody como o assunto de um email enviado por email (via bash).


-1

Veja: http://tldp.org/LDP/abs/html/internal.html#READR

Use reade observe que, se você terminar uma linha com \a nova linha, será ignorada. Então você poderia fazer:

#! / bin / bash

leia -p "version:" version
eco $ version

# insira algumas entradas e termine as linhas longas com "\"; em seguida, insira no final
leia -p "description:" description
echo -e "$ version \ n $ description >> seuarquivo.txt

Se eu apenas queria que um parágrafo com quebras de linha fosse ignorado, sim. Mas, como essa é uma lista gerada de notas de versão para um script de construção, preciso preservar essas quebras de linha; Eu posso tentar entrar em uma lista com marcadores, por exemplo.
31712 Robert

O ABS é uma monstruosidade de proporções horríveis. 90% está completamente errado.
adaptr

Não é que ruim.
voices
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.