GNU/Linux >> Linux Esercitazione >  >> Linux

Come posso eseguire il loop sull'output di un comando di shell?

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

Linux
  1. Come usare il comando Linux grep

  2. Come scorrere le righe di un file?

  3. Come evidenziare una parola nell'output di "cat"??

  4. Qual è la differenza nell'ottenere l'output del comando usando `command`e $(command) in Shell??

  5. Come sapere se l'output di un comando o di uno script di shell è Stdout o Stderr?

Come eseguire i comandi della shell tramite il server HTTP

Come reindirizzare l'output del comando della shell

Come posso trovare la mia versione della shell usando un comando Linux?

Come eseguire il comando Vim dalla shell?

Come posso nascondere l'output di un'applicazione shell in Linux?

Come leggere la colonna IDLE nell'output del comando Linux 'w'?