Comment lire plusieurs lignes de STDIN dans une variable?


24

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. Il n'y a pas non plus 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).


Vous obtenez ces informations de l'utilisateur, n'est-ce pas?
glenn jackman

Correct; Je souhaite que l'utilisateur saisisse ces informations dans le terminal lors de l'exécution du script.
Robert K

1
Vous n'avez pas été clair, je préfère dire.
poige

Réponses:


20

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.


1
Comment arrêter après une entrée multiligne? Si j'appuie sur Ctrl C, cela s'arrête mais la variable n'est pas enregistrée!
Nikhil

2
Les terminaux UNIX® ont une "discipline": en.wikipedia.org/wiki/Line_discipline • Découvrez ce que signifie "eof" • Lisez man stty, découvrez comment obtenir les paramètres actuels
poige

2
ctrl-d pour arrêter.
freb

9

Essaye ça:

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

Sans saut de ligne:

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

Avec des sauts de ligne:

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

2
-d ''c'est exactement ce dont j'avais besoin. Merci
Bruno Bronosky

@Bruno Mon plaisir; c'est délicat. Surtout à première vue, il semble assez standard. Cela peut être très utile, une fois que vous maîtrisez les différentes particularités.
voix


2

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

Utilisez read -rplutôt.
adaptr

2

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

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

Hum ... comment cela répond-il de quelque façon que ce soit à la question du PO?
adaptr

Il peut démarrer l'éditeur à partir du script.
Mircea Vutcovici

Et cela accomplit quoi, exactement? Il veut utiliser le texte d' un fichier dans le script, pas écrire des informations dans un fichier.
adaptr

Il n'a pas besoin de lire le texte de l'utilisateur et de l'écrire dans un fichier. Veuillez lire les commentaires ajoutés à la question.
Mircea Vutcovici

1

Quelques corrections:

  1. Pour autoriser "l'édition" sur la ligne, utilisez la ligne de -electure (vous avez donc l'historique de bash et toutes les fonctionnalités d'édition)
  2. -dne 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

0

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"

Sauf que je n'exécute pas une commande shell comme LS. Je demande une entrée multiligne à l'utilisateur.
Robert K

C'est une très mauvaise pratique; ne traitez pas la sortie de ls!
adaptr

@adaptr Nous avons déjà entendu tout cela, cela vous dérangerait-il de suggérer une bonne alternative, s'il vous plaît?
voix

0

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 "\\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+="\"" 

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


-1

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

Utilisez readet notez que si vous terminez une ligne, \la nouvelle ligne est ignorée. Vous pourriez donc faire:

#! / bin / bash

lire -p "version:" version
echo $ version

# entrez quelques entrées et terminez les longues lignes avec "\", puis entrez simplement à la fin
lire -p "description:" description
echo -e "$ version \ n $ description >> votrefichier.txt

Si je voulais juste ignorer un paragraphe avec des sauts de ligne, oui. Mais comme il s'agit d'une liste générée de notes de publication pour un script de build, j'ai besoin de pouvoir conserver ces sauts de ligne; Je pourrais essayer d'entrer une liste à puces, par exemple.
Robert K

L'ABS est une monstruosité aux proportions horribles. 90% est tout à fait faux.
adaptr

Ce n'est pas si mal.
voix
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.