J'ai trouvé que vous pouvez le faire en utilisant simplement des guillemets :
while read -r proc; do
#do work
done <<< "$(ps -ewo pid,cmd,etime | grep python | grep -v grep | grep -v sh)"
Cela enregistrera chaque ligne dans le tableau plutôt que chaque élément.
Jamais for
boucle sur les résultats d'une commande shell si vous souhaitez la traiter ligne par ligne, sauf si vous modifiez la valeur du séparateur de champ interne $IFS
à \n
. C'est parce que les lignes feront l'objet d'un fractionnement de mots ce qui conduit aux résultats réels que vous voyez. C'est-à-dire si vous avez par exemple un fichier comme celui-ci :
foo bar
hello world
La boucle for suivante
for i in $(cat file); do
echo "$i"
done
vous donne :
foo
bar
hello
world
Même si vous utilisez IFS='\n'
les lignes peuvent toujours faire l'objet d'une extension de nom de fichier
Je recommande d'utiliser while
+ read
à la place parce que read
lit ligne par ligne.
De plus, j'utiliserais pgrep
si vous recherchez des pid appartenant à un certain binaire. Cependant, puisque python peut apparaître comme différents binaires, comme python2.7
ou python3.4
Je suggère de passer -f
à pgrep
ce qui le fait rechercher toute la ligne de commande plutôt que de simplement rechercher des binaires appelés python
. Mais cela trouvera également les processus qui ont été démarrés comme cat foo.py
. Tu étais prévenu! A la fin vous pouvez affiner la regex passée à pgrep
comme vous le souhaitez.
Exemple :
pgrep -f python | while read -r pid ; do
echo "$pid"
done
ou si vous voulez aussi le nom du processus :
pgrep -af python | while read -r line ; do
echo "$line"
done
Si vous voulez le nom du processus et le pid dans des variables distinctes :
pgrep -af python | while read -r pid cmd ; do
echo "pid: $pid, cmd: $cmd"
done
Vous voyez, read
offre un moyen flexible et stable de traiter la sortie d'une commande ligne par ligne.
Au fait, si vous préférez votre ps .. | grep
ligne de commande sur pgrep
utilisez la boucle suivante :
ps -ewo pid,etime,cmd | grep python | grep -v grep | grep -v sh \
| while read -r pid etime cmd ; do
echo "$pid $cmd $etime"
done
Notez comment j'ai changé l'ordre de etime
et cmd
. Ainsi pour pouvoir lire cmd
, qui peut contenir des espaces, en une seule variable. Cela fonctionne car read
décomposera la ligne en variables, autant de fois que vous avez spécifié de variables. La partie restante de la ligne - y compris éventuellement des espaces blancs - sera affectée à la dernière variable qui a été spécifiée dans la ligne de commande.
Lors de l'utilisation de for
boucle dans bash, il divise la liste donnée par défaut par whitespaces
, cela peut être adapté en utilisant le soi-disant séparateur de champ interne , ou IFS
en bref .
IFS Le séparateur de champ interne qui est utilisé pour diviser les mots après expansion et pour diviser les lignes en mots avec la commande intégrée read. La valeur par défaut est "".
Pour votre exemple, nous aurions besoin de dire IFS
utiliser new-lines
comme point d'arrêt.
IFS=$'\n'
for tbl in $(ps -ewo pid,cmd,etime | grep python | grep -v grep | grep -v sh)
do
echo $tbl
done
Cet exemple renvoie la sortie suivante sur ma machine.
668 /usr/bin/python /usr/bin/ud 03:05:54
27892 python 00:01