J'ai une commande renvoyant plusieurs lignes. Pour un traitement ultérieur, je dois traiter chaque ligne unique de ces lignes.
Mon code actuel fonctionne en modifiant l'IFS ( séparateur de champ interne ):
ROWS=$(some command returning multiple lines)
O=$IFS #save original IFS
IFS=$(echo -en "\n\b") # set IFS to linebreak
for ROW in ${ROWS[@]}
do
echo "$ROW"
done
IFS=$O #restore old IFS
Je me demande, y a-t-il un meilleur moyen d'accéder aux lignes simples de la sortie de plusieurs lignes, une sans modifier l'IFS? Surtout la lisibilité de mon script se dégrade en modifiant l'IFS.
Mise à jour: j'ai du mal à faire fonctionner les réponses, par exemple celle de choroba:
while IFS= read -r line ; do
let var+=line #line 42
done << $(sqlite3 -list -nullvalue NULL -separator ',' /var/log/asterisk/master.db "${QUERY}")
echo "$var" # line 44
Donne moi
./bla.sh: row 44: Warning: here-document at line 43 delimited by end-of-file (wanted `$(sqlite3 -list -nullvalue NULL -separator , /var/log/asterisk/master.db ${QUERY})')
./bla.sh: row 42: let: echo "": syntax error: invalid arithmetic operator. (error causing character is \"""\").
N'importe qui peut m'aider avec ça? Merci!
bash
shell
command
command-substitution
stefan.at.wpf
la source
la source
< <(some command returning multiple lines)
, mais ce n'est pas ce que vous faites.Réponses:
Et
read
enwhile
boucle?Attention, cependant, le canal est exécuté dans un sous-shell, ce qui signifie que vous ne pouvez pas modifier les valeurs des variables pour le reste du script. Si vous avez besoin de quelque chose pour survivre à votre boucle while, vous pouvez utiliser la substitution de processus de bash:
la source
bash
, mais il convient de noter que la portée des variables en sous-shell n'est qu'un problème dansbash
, faire la même chose danszsh
n'aurait pas ce problème du tout.La définition
IFS
d'une nouvelle ligne n'est pas suffisante. (Pourquoi vous séparez-vous également des caractères de retour arrière, au fait?)Dans votre code,
${ROWS[@]}
(qui est une façon étrange d'écrire$ROWS
-ROWS
n'est pas un tableau) n'est pas entre guillemets. (Si c'était entre guillemets, vous obtiendriez une seule chaîne, car ilROWS
ne s'agit pas d'un tableau.) Ainsi, le shell divise la valeur de la variable en champs à chaqueIFS
caractère, puis traite chaque champ comme un modèle global. Par exemple, si l'une des lignes imprimées par la commande contient le caractère unique*
, celui-ci sera remplacé par les noms de fichier dans le répertoire courant.Vous pouvez désactiver la globalisation avec
set -f
. Dans la plupart des cas, lorsque vous définissez l'IFS
utilisation de la fonction de fractionnement de champ du shell, vous devez également désactiver la globalisation. Remettez-le avecset +f
.L'idiome fiable pour lire ligne par ligne la sortie d'une commande est
while IFS= read -r
.Notez que la plupart des shells exécutent chaque commande d'un pipeline dans un sous-shell séparé. Donc, si vous devez définir des variables et les utiliser après la boucle, encapsulez ces commandes dans un groupe avec la boucle. (Ksh et zsh sont les exceptions, ils exécutent la dernière commande d'un pipeline dans le shell parent.)
la source
Vous mélangez la syntaxe ici-document et ici-chaîne dans votre question de mise à jour.
Soit utiliser ici-document:
Ou ici-chaîne:
la source