Zjistil jsem, že to můžete udělat pomocí dvojitých uvozovek:
while read -r proc; do
#do work
done <<< "$(ps -ewo pid,cmd,etime | grep python | grep -v grep | grep -v sh)"
Tím se uloží každý řádek do pole, nikoli každá položka.
Nikdy for
smyčka přes výsledky příkazu shell, pokud jej chcete zpracovat řádek po řádku, pokud nezměníte hodnotu vnitřního oddělovače polí $IFS
do \n
. Je to proto, že řádky budou předmětem rozdělení slov což vede ke skutečným výsledkům, které vidíte. To znamená, pokud máte například soubor jako tento:
foo bar
hello world
Následující smyčka for
for i in $(cat file); do
echo "$i"
done
vám dává:
foo
bar
hello
world
I když používáte IFS='\n'
řádky mohou být stále předmětem rozšíření názvu souboru
Doporučuji použít while
+ read
místo toho, protože read
čte řádek po řádku.
Dále bych použil pgrep
pokud hledáte pids patřící do určité binární soustavy. Protože se však python může jevit jako různé binární soubory, například python2.7
nebo python3.4
Doporučuji předat -f
na pgrep
což umožňuje prohledávat celý příkazový řádek spíše než jen hledat binární soubory nazvané python
. Ale najde se také procesy, které byly spuštěny jako cat foo.py
. Byl jsi varován! Na konci můžete upravit regulární výraz předaný na pgrep
jak si přejete.
Příklad:
pgrep -f python | while read -r pid ; do
echo "$pid"
done
nebo chcete-li také název procesu:
pgrep -af python | while read -r line ; do
echo "$line"
done
Pokud chcete název procesu a pid v samostatných proměnných:
pgrep -af python | while read -r pid cmd ; do
echo "pid: $pid, cmd: $cmd"
done
Vidíte, read
nabízí flexibilní a stabilní způsob zpracování výstupu příkazového řádku po řádku.
Btw, pokud dáváte přednost vašemu ps .. | grep
příkazového řádku přes pgrep
použijte následující smyčku:
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
Všimněte si, jak jsem změnil pořadí etime
a cmd
. Aby bylo možné číst cmd
, který může obsahovat mezery, do jedné proměnné. To funguje, protože read
rozdělí řádek na proměnné, kolikrát jste zadali proměnné. Zbývající část řádku – případně včetně mezer – bude přiřazena poslední proměnné, která byla zadána v příkazovém řádku.
Při použití for
smyčkách v bash rozděluje daný seznam standardně o whitespaces
, lze to upravit pomocí takzvaného vnitřního separátoru polí nebo IFS
ve zkratce .
IFS Interní oddělovač polí, který se používá k dělení slov po rozšíření a k rozdělení řádků na slova pomocí vestavěného příkazu read. Výchozí hodnota je "".
Pro váš příklad bychom potřebovali sdělit IFS
použít new-lines
jako bod zlomu.
IFS=$'\n'
for tbl in $(ps -ewo pid,cmd,etime | grep python | grep -v grep | grep -v sh)
do
echo $tbl
done
Tento příklad vrací na mém počítači následující výstup.
668 /usr/bin/python /usr/bin/ud 03:05:54
27892 python 00:01