web-dev-qa-db-fra.com

Comment lire plusieurs lignes de STDIN dans une variable?

J'ai googlé cette question en vain. J'automatise un processus de construction ici au travail, et tout ce que j'essaie de faire est d'obtenir des numéros de version et une petite description de la construction qui peut être multiligne. Le système sur lequel il fonctionne est OSX 10.6.8.

J'ai tout vu, de l'utilisation de CAT au traitement de chaque ligne si nécessaire. Je n'arrive pas à comprendre ce que je dois utiliser et pourquoi.

Tentatives

read -d '' versionNotes

Résultats en entrée brouillée si l'utilisateur doit utiliser la touche de retour arrière. De plus, il n'y a pas de bon moyen de terminer l'entrée car ^ D ne se termine pas et ^ C quitte simplement le processus.

read -d 'END' versionNotes

Fonctionne ... mais brouille toujours l'entrée si la touche de retour arrière est nécessaire.

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

Ne termine pas correctement l'entrée (car je suis trop tard pour rechercher une correspondance avec une chaîne vide).

26
Robert K

man bash mentionne "…

La substitution de commande $ (fichier cat) peut être remplacée par l'équivalent mais plus rapide $ (<fichier).

… "

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

et je suis d'accord que cela mérite d'être mentionné - echo "$myVar" aurait affiché l'entrée telle qu'elle a été donnée.

21
poige

Essayez ceci:

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

Sans sauts de ligne:

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

Avec sauts de ligne:

user@Host:~$ echo "$x"
mic
check
one
two
10
voices

Reportez-vous à l'excellent Bash Guide pour tous vos besoins de script bash.

En particulier, le Bash FAQ contient cela au numéro # 1:

Comment lire un fichier (flux de données, variable) ligne par ligne (et/ou champ par champ)?

8
adaptr

Vous pouvez démarrer un éditeur comme vim, pico ...

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

J'ai résolu ce problème en traitant chaque ligne jusqu'à ce que je trouve une ligne vierge. Cela fonctionne assez bien pour ma situation. Mais si quelqu'un veut ajouter une meilleure solution, n'hésitez pas à le faire.

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

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

Quelques corrections:

  1. Pour autoriser "l'édition" sur la ligne, utilisez -e qui utilise readline (vous avez donc l'historique bash et toutes les fonctionnalités d'édition)
  2. -d ne prend qu'un seul caractère. Par exemple. de 'END' prend 'E' et chaque fois que l'utilisateur écrit un 'E' la lecture s'arrête (je suppose que ce n'est pas ce que vous voulez ...)

Il existe plusieurs possibilités pour ce faire. Je choisirais de lire ligne par ligne et m'arrêterais lorsqu'une ligne vide est trouvée (bien que vous puissiez définir n'importe quel mot d'arrêt):

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

Vous disposez de plusieurs méthodes.

L'une des méthodes les plus simples est:

MYVAR=$(yourcommand)
echo $"MYVAR"

Par exemple:

MYVAR=$(ls /)
echo $"MYVAR"
0
Bertrand SCHITS

Nous utilisons une construction utilisant xargs et ctrl-d pour la rupture. Je ne suis pas parfaitement satisfait de cela, mais cela fait certainement le travail de prendre les entrées utilisateur multi-lignes et de les bourrer dans une variable (formatage intact). (Les première et troisième affectations ajoutent des guillemets autour du contenu de l'entrée xargs.)

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

Nous utilisons reminderBody comme le corps d'un e-mail envoyé par courrier (via bash).

0
JamesIsIn