Ich habe festgestellt, dass Sie dies tun können, indem Sie einfach doppelte Anführungszeichen verwenden:
while read -r proc; do
#do work
done <<< "$(ps -ewo pid,cmd,etime | grep python | grep -v grep | grep -v sh)"
Dadurch wird jede Zeile im Array gespeichert und nicht jedes Element.
Niemals for
Schleifen Sie die Ergebnisse eines Shell-Befehls, wenn Sie ihn Zeile für Zeile verarbeiten möchten, es sei denn, Sie ändern den Wert des internen Feldtrennzeichens $IFS
bis \n
. Dies liegt daran, dass die Zeilen Gegenstand der Wortaufteilung werden was zu den tatsächlichen Ergebnissen führt, die Sie sehen. Das heißt, wenn Sie zum Beispiel eine Datei wie diese haben:
foo bar
hello world
Die folgende for-Schleife
for i in $(cat file); do
echo "$i"
done
gibt Ihnen:
foo
bar
hello
world
Auch wenn Sie IFS='\n'
verwenden die Zeilen werden möglicherweise immer noch Gegenstand der Dateinamenerweiterung
Ich empfehle die Verwendung von while
+ read
stattdessen weil read
liest Zeile für Zeile.
Außerdem würde ich pgrep
verwenden wenn Sie nach Pids suchen, die zu einer bestimmten Binärdatei gehören. Da Python jedoch möglicherweise als unterschiedliche Binärdateien angezeigt wird, wie python2.7
oder python3.4
Ich schlage vor, -f
zu übergeben bis pgrep
Dadurch wird die gesamte Befehlszeile durchsucht, anstatt nur nach Binärdateien mit dem Namen python
zu suchen . Dies findet aber auch Prozesse, die wie cat foo.py
gestartet wurden . Du wurdest gewarnt! Am Ende können Sie die an pgrep
übergebene Regex verfeinern wie Sie es wünschen.
Beispiel:
pgrep -f python | while read -r pid ; do
echo "$pid"
done
oder wenn Sie auch den Prozessnamen wollen:
pgrep -af python | while read -r line ; do
echo "$line"
done
Wenn Sie den Prozessnamen und die PID in separaten Variablen haben möchten:
pgrep -af python | while read -r pid cmd ; do
echo "pid: $pid, cmd: $cmd"
done
Sehen Sie, read
bietet eine flexible und stabile Möglichkeit, die Ausgabe eines Befehls Zeile für Zeile zu verarbeiten.
Übrigens, wenn Sie Ihren ps .. | grep
bevorzugen Befehlszeile über pgrep
Verwenden Sie die folgende Schleife:
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
Beachten Sie, wie ich die Reihenfolge von etime
geändert habe und cmd
. Also um cmd
lesen zu können , die Leerzeichen enthalten kann, in eine einzelne Variable. Das funktioniert, weil read
zerlegt die Zeile so oft in Variablen, wie Sie Variablen angegeben haben. Der restliche Teil der Zeile - möglicherweise inklusive Whitespace - wird der letzten Variable zugewiesen, die in der Kommandozeile angegeben wurde.
Bei Verwendung von for
Schleifen in Bash teilt es die angegebene Liste standardmäßig durch whitespaces
, dies kann durch die Verwendung des sogenannten Internen Feldtrenners angepasst werden , oder IFS
kurz .
IFS Das interne Feldtrennzeichen, das zum Aufteilen von Wörtern nach der Erweiterung und zum Aufteilen von Zeilen in Wörter mit dem eingebauten Lesebefehl verwendet wird. Der Standardwert ist "".
Für Ihr Beispiel müssten wir IFS
angeben um new-lines
zu verwenden als Haltepunkt.
IFS=$'\n'
for tbl in $(ps -ewo pid,cmd,etime | grep python | grep -v grep | grep -v sh)
do
echo $tbl
done
Dieses Beispiel gibt die folgende Ausgabe auf meinem Computer zurück.
668 /usr/bin/python /usr/bin/ud 03:05:54
27892 python 00:01