Descubrí que puedes hacer esto simplemente usa comillas dobles:
while read -r proc; do
#do work
done <<< "$(ps -ewo pid,cmd,etime | grep python | grep -v grep | grep -v sh)"
Esto guardará cada línea en la matriz en lugar de cada elemento.
Nunca for
Repita los resultados de un comando de shell si desea procesarlo línea por línea a menos que esté cambiando el valor del separador de campo interno $IFS
a \n
. Esto se debe a que las líneas estarán sujetas a división de palabras lo que conduce a los resultados reales que está viendo. Es decir, si, por ejemplo, tiene un archivo como este:
foo bar
hello world
El siguiente bucle for
for i in $(cat file); do
echo "$i"
done
te da:
foo
bar
hello
world
Incluso si usas IFS='\n'
las líneas aún pueden estar sujetas a expansión de nombre de archivo
Recomiendo usar while
+ read
en cambio porque read
lee línea por línea.
Además, usaría pgrep
si está buscando pids pertenecientes a un determinado binario. Sin embargo, dado que python puede aparecer como binarios diferentes, como python2.7
o python3.4
Sugiero pasar -f
al pgrep
lo que hace que busque en toda la línea de comando en lugar de solo buscar binarios llamados python
. Pero esto también encontrará procesos que se han iniciado como cat foo.py
. ¡Usted ha sido advertido! Al final, puede refinar la expresión regular pasada a pgrep
como desees.
Ejemplo:
pgrep -f python | while read -r pid ; do
echo "$pid"
done
o si también quieres el nombre del proceso:
pgrep -af python | while read -r line ; do
echo "$line"
done
Si desea el nombre del proceso y el pid en variables separadas:
pgrep -af python | while read -r pid cmd ; do
echo "pid: $pid, cmd: $cmd"
done
Ya ves, read
ofrece una forma flexible y estable de procesar la salida de un comando línea por línea.
Por cierto, si prefieres tu ps .. | grep
línea de comando sobre pgrep
usa el siguiente bucle:
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
Observe cómo cambié el orden de etime
y cmd
. Así poder leer cmd
, que puede contener espacios en blanco, en una sola variable. Esto funciona porque read
dividirá la línea en variables, tantas veces como haya especificado las variables. La parte restante de la línea, posiblemente incluidos los espacios en blanco, se asignará a la última variable que se haya especificado en la línea de comando.
Al usar for
bucles en bash divide la lista dada por defecto por whitespaces
, esto se puede adaptar usando el llamado Separador de campo interno o IFS
en resumen.
IFS El separador de campo interno que se usa para dividir palabras después de la expansión y para dividir líneas en palabras con el comando integrado de lectura. El valor predeterminado es "".
Para su ejemplo, tendríamos que decirle a IFS
usar new-lines
como punto de quiebre.
IFS=$'\n'
for tbl in $(ps -ewo pid,cmd,etime | grep python | grep -v grep | grep -v sh)
do
echo $tbl
done
Este ejemplo devuelve el siguiente resultado en mi máquina.
668 /usr/bin/python /usr/bin/ud 03:05:54
27892 python 00:01