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

18

Eu pesquisei essa pergunta sem sucesso. Estou automatizando um processo de construção aqui no trabalho, e tudo o que estou tentando fazer é obter números de versão e uma pequena descrição da construção que pode ser multi-linha. O sistema em que isso é executado é o OSX 10.6.8.

Eu já vi de 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 tiver que usar a tecla backspace. Também não há uma boa maneira de terminar a entrada como ^ D não termina e ^ C apenas sai do processo.

read -d 'END' versionNotes

Funciona ... mas ainda reduz a entrada se for necessária a chave de retrocesso.

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

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

    
por Robert K 09.04.2012 / 23:20

9 respostas

13

man bash menciona «…

The command substitution $(cat file) can be replaced by the equivalent but faster $(< file).

… »

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

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

    
por 11.06.2012 / 12:29
6

Consulte o excelente Guia do Bash para todas as suas necessidades de script bash.

Em particular, a FAQ do Bash contém isso no número 1:

Como posso ler um arquivo (fluxo de dados, variável) linha a linha (e / ou campo-por -field)?

    
por 25.04.2012 / 15:17
5

Tente isto:

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

Sem quebra de linha:

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

Com quebra de linha:

user@host:~$ echo "$x"
mic
check
one
two
    
por 12.06.2016 / 20:34
2

Eu resolvi esse problema lidando com cada linha até chegar a 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
    
por 25.04.2012 / 15:13
1

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

${VISUAL:-${EDITOR:-vi}} source/application.yml
    
por 25.04.2012 / 15:23
1

Primeiro algumas correções:

  1. Para permitir "edição" na linha, use -e , que usa readline (para que você tenha o histórico bash e todos os recursos de edição)
  2. -d leva apenas um caractere. Por exemplo. de 'END' leva 'E' e sempre que o usuário escreve um 'E' a leitura pára (eu acho que não é o que você quer ...)

Existem algumas possibilidades para fazer isso. Eu iria ler linha por linha e parar quando uma linha vazia fosse encontrada (embora você pudesse definir qualquer palavra parada):

unset tmp
while :
do 
 read line
 [[ $line == "" ]] && tmp="${tmp:0:$((${#tmp}-1))}" && break
 tmp="$tmp"$line$'\n'
done
    
por 11.06.2012 / 12:23
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 pegar a entrada do usuário multi-linha e colocar isso em um arquivo (formatação intacta).

printf "Give me some input!  Use ctrl-d when you are done.  \n"
touch /some/path/file.txt
'xargs -0 > /tmp/.reminder/file.txt'
    
por 26.01.2018 / 19:45
0

Você tem vários métodos.

Um dos métodos mais simples é o seguinte:

MYVAR=$(yourcommand)
echo $"MYVAR"

Por exemplo:

MYVAR=$(ls /)
echo $"MYVAR"
    
por 10.04.2012 / 00:15
-1

Veja: link

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

#!/bin/bash

read -p "version: " version
echo $version

# enter some input and end long lines with "\", then plain enter at the end
read -p "description: " description
echo -e "$version\n$description >> yourfile.txt
    
por 24.04.2012 / 23:18