Question Capture de plusieurs lignes dans une variable Bash


J'ai un script "myscript" qui affiche ce qui suit:

abc
def
ghi

dans un autre script, j'appelle:

declare RESULT=$(./myscript)

et $RESULT obtient la valeur

abc def ghi

Existe-t-il un moyen de stocker le résultat soit avec les nouvelles lignes, soit avec le caractère '\ n' afin que je puisse le sortir avec 'echo -e'?


441
2018-03-05 04:32


origine


Réponses:


En fait, RESULT contient ce que vous voulez - pour démontrer:

echo "$RESULT"

Ce que vous montrez est ce que vous obtenez:

echo $RESULT

Comme noté dans les commentaires, la différence est que (1) la version entre guillemets de la variable (echo "$RESULT") conserve l'espacement interne de la valeur exactement tel qu'il est représenté dans la variable - nouvelles lignes, tabulations, plusieurs blancs et tous - alors que (2) la version sans guillemets (echo $RESULT) remplace chaque séquence d'un ou plusieurs espaces, tabulations et nouvelles lignes par un seul espace. Donc (1) conserve la forme de la variable d'entrée, alors que (2) crée une ligne de sortie potentiellement très longue avec des 'mots' séparés par des espaces simples (où un 'mot' est une séquence de caractères non-blancs; ne sont pas des caractères alphanumériques dans aucun des mots).


829
2018-03-05 04:36



Un autre écueil avec cela est que substitution de commande - $() - des bandes qui suivent les nouvelles lignes. Probablement pas toujours important, mais si vous voulez vraiment préserver exactement quelle était la sortie, vous devrez utiliser une autre ligne et quelques citations:

RESULTX="$(./myscript; echo x)"
RESULT="${RESULTX%x}"

Ceci est particulièrement important si vous voulez manipuler tout noms de fichiers possibles (pour éviter un comportement indéfini, comme un mauvais fonctionnement du fichier).


76
2018-03-16 09:03



En plus de la réponse donnée par @ l0b0, j'ai juste eu la situation où j'avais besoin à la fois de garder toutes les nouvelles lignes de sortie en arrière par le script et vérifiez le code de retour du script. Et le problème avec la réponse de l0b0 est que «echo x» réinitialisait $? retour à zéro ... alors j'ai réussi à trouver cette solution très astucieuse:

RESULTX="$(./myscript; echo x$?)"
RETURNCODE=${RESULTX##*x}
RESULT="${RESULTX%x*}"

13
2017-07-11 13:03



Dans le cas où vous êtes intéressé par des lignes spécifiques, utilisez un tableau de résultats:

declare RESULT=($(./myscript))  # (..) = array
echo "First line: ${RESULT[0]}"
echo "Second line: ${RESULT[1]}"
echo "N-th line: ${RESULT[N]}"

12
2017-07-11 20:28



Que diriez-vous, il lira chaque ligne à une variable et qui peut être utilisé par la suite! que la sortie de myscript est redirigée vers un fichier appelé myscript_output

awk '{while ( (getline var < "myscript_output") >0){print var;} close ("myscript_output");}'

0
2018-05-21 14:21



Après avoir essayé la plupart des solutions ici, la chose la plus simple que j'ai trouvée était évidente: utiliser un fichier temporaire. Je ne suis pas sûr de ce que vous voulez faire avec votre sortie de ligne multiple, mais vous pouvez alors traiter ligne par ligne en utilisant lire. À propos de la seule chose que vous ne pouvez pas vraiment faire est de coller tout simplement dans la même variable, mais pour la plupart des objectifs pratiques, c'est beaucoup plus facile à traiter.

./myscript.sh > /tmp/foo
while read line ; do 
    echo 'whatever you want to do with $line'
done < /tmp/foo

Piratage rapide pour faire l'action demandée:

result=""
./myscript.sh > /tmp/foo
while read line ; do
  result="$result$line\n"
done < /tmp/foo
echo -e $result

Notez que cela ajoute une ligne supplémentaire. Si vous travaillez dessus, vous pouvez le coder, je suis juste trop paresseux.


EDIT: Bien que ce cas fonctionne parfaitement bien, les gens qui lisent ceci doivent être conscients que vous pouvez facilement écraser votre stdin dans la boucle while, vous donnant ainsi un script qui exécutera une ligne, effacera stdin, et quittera. Comme ssh va faire ce que je pense? Je viens de le voir récemment, d'autres exemples de code ici: https://unix.stackexchange.com/questions/24260/reading-lines-from-a-file-with-bash-for-vs-while

Encore une fois! Cette fois avec un handle de fichier différent (stdin, stdout, stderr sont 0-2, donc nous pouvons utiliser & 3 ou plus haut dans bash).

result=""
./test>/tmp/foo
while read line  <&3; do
    result="$result$line\n"
done 3</tmp/foo
echo -e $result

Vous pouvez également utiliser mktemp, mais ce n'est qu'un exemple de code rapide. L'utilisation de mktemp ressemble à ceci:

filenamevar=`mktemp /tmp/tempXXXXXX`
./test > $filenamevar

Utilisez ensuite $ filenamevar comme vous le feriez avec le nom d'un fichier. Probablement pas besoin d'être expliqué ici mais quelqu'un s'est plaint dans les commentaires.


0
2018-05-03 22:52