Ho scoperto che puoi farlo usando solo le virgolette:
while read -r proc; do
#do work
done <<< "$(ps -ewo pid,cmd,etime | grep python | grep -v grep | grep -v sh)"
Ciò salverà ogni riga nell'array piuttosto che in ogni elemento.
Mai for
eseguire un ciclo sui risultati di un comando shell se si desidera elaborarlo riga per riga, a meno che non si stia modificando il valore del separatore di campo interno $IFS
a \n
. Questo perché le righe saranno oggetto di suddivisione delle parole che porta ai risultati effettivi che stai vedendo. Significato se ad esempio hai un file come questo:
foo bar
hello world
Il seguente ciclo for
for i in $(cat file); do
echo "$i"
done
ti dà:
foo
bar
hello
world
Anche se usi IFS='\n'
le righe potrebbero ancora essere oggetto di espansione del nome file
Raccomando di usare while
+ read
invece perché read
legge riga per riga.
Inoltre userei pgrep
se stai cercando pid appartenenti a un determinato binario. Tuttavia, poiché python potrebbe apparire come binari diversi, come python2.7
o python3.4
Suggerisco di superare -f
a pgrep
che fa cercare l'intera riga di comando invece di cercare solo i binari chiamati python
. Ma questo troverà anche i processi che sono stati avviati come cat foo.py
. Sei stato avvertito! Alla fine puoi affinare la regex passata a pgrep
come desideri.
Esempio:
pgrep -f python | while read -r pid ; do
echo "$pid"
done
o se vuoi anche il nome del processo:
pgrep -af python | while read -r line ; do
echo "$line"
done
Se vuoi il nome del processo e il pid in variabili separate:
pgrep -af python | while read -r pid cmd ; do
echo "pid: $pid, cmd: $cmd"
done
Vedi, read
offre un modo flessibile e stabile per elaborare l'output di un comando riga per riga.
A proposito, se preferisci il tuo ps .. | grep
riga di comando su pgrep
usa il seguente ciclo:
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
Nota come ho cambiato l'ordine di etime
e cmd
. Quindi per poter leggere cmd
, che può contenere spazi bianchi, in una singola variabile. Funziona perché read
suddividerà la riga in variabili, tutte le volte che hai specificato le variabili. La parte rimanente della riga, possibilmente includendo gli spazi bianchi, verrà assegnata all'ultima variabile che è stata specificata nella riga di comando.
Quando si utilizza for
loop in bash divide l'elenco dato per impostazione predefinita per whitespaces
, questo può essere adattato utilizzando il cosiddetto Internal Field Seperator o IFS
in breve .
IFS Il separatore di campo interno utilizzato per la divisione delle parole dopo l'espansione e per dividere le righe in parole con il comando integrato read. Il valore predefinito è "".
Per il tuo esempio dovremmo dire IFS
per usare new-lines
come punto di rottura.
IFS=$'\n'
for tbl in $(ps -ewo pid,cmd,etime | grep python | grep -v grep | grep -v sh)
do
echo $tbl
done
Questo esempio restituisce il seguente output sulla mia macchina.
668 /usr/bin/python /usr/bin/ud 03:05:54
27892 python 00:01