Come faccio a sapere se un comando è in esecuzione o in attesa di input dell'utente?


14

Sulla riga di comando, ho digitato un comando e ho premuto invio. Non produce nulla. Come faccio a sapere se è in esecuzione e non è ancora in uscita o sta chiedendo l'input dell'utente?


Se è in attesa, non ti verrà PS1richiesto.
Prvt_Yadav,

1. Per favore, dicci quale programma è (che è silenzioso) e possiamo darti consigli più precisi su cosa aspettarsi e come controllarlo; 2. Vorresti ricevere un avviso quando il programma chiede l'input o ha terminato (in modo che qualcosa sia scritto nella finestra del terminale?
sudodus,

se è previsto un input, suppongo che riceverai un prompt con un messaggio che richiede l'input.
Rinzwind,

5
@Rinzwind - È una pessima ipotesi. Il primo controesempio alla mente è il catcomando. Basta digitare catda solo e attenderà l'input da stdin, ma non dà alcun prompt. Molti altri comandi si comportano in modo simile perché si aspettano input da uno stdin o da un file, ma non fanno distinzione tra origini di input diverse (terminale interattivo, pipe, file ...).
Dave Sherohman,

Risposte:


15

Esistono diversi approcci:

  1. Prova a segnalare la fine dell'input : senza i privilegi di superutente è difficile sapere cosa succede sotto il cofano. Quello che si può fare è premere Ctrl+ d. Terminali e utility in modalità canonica inviano tutto il testo disponibile a read()syscall dopo aver ricevuto il segnale EOT associato a questa combinazione di tasti e, se non c'è input, read()restituisce uno stato di uscita negativo che la maggior parte delle utility accetta come segnale per uscire. Pertanto, se un'utilità è in attesa di input, uscirà alla ricezione della combinazione di tasti. In caso contrario, l'utilità esegue le attività o non è scritta correttamente.

  2. Spiare i syscall : se si dispone del privilegio di superutente, è possibile eseguire stracein un altro terminale per vedere cosa si sta attualmente facendo. Per questo è necessario scoprire il PID del programma. Ad esempio, in un'altra scheda terminale eseguire pgrep -f firefoxche può 1234 come esempio e quindi sudo strace -f -p 1234. Se l'output che vedi è bloccato su read()syscall, significa che probabilmente il comando è in attesa di input. Altrimenti, se vedi eseguire syscalls, allora il comando sta facendo qualcos'altro. Vedere una domanda correlata per l'uso di straceanche per capire se il comando di lunga durata è uscito.

  3. Usa i metodi del comando : tra le altre cose, utilità come i ddsegnali di utilizzo. Ad esempio, se si utilizza kill -USR1 1234(dove 1234 è PID del ddcomando in esecuzione ), verrà stampato su stdout la quantità di byte attualmente elaborati. Naturalmente, ciò richiede innanzitutto la conoscenza di tale comportamento del comando. I due metodi sopra riportati sono più generali e non richiedono una conoscenza approfondita del comportamento di ciascun comando (anche se è sempre meglio sapere cosa si sta effettivamente eseguendo, altrimenti si rischia di eseguire un comando che potrebbe danneggiare).


+1. Grazie per il stracemetodo :-) Ma sono utili anche metodi più semplici (generali o specifici per ciascun programma). Alcuni funzionano senza privilegi di superutente. Esempi: controlla se ddsta facendo qualcosa e controlla perché grep --color asdfsta aspettando in silenzio.
sudodus,

@sudodus Ah, un buon promemoria per ddaggiungere quello.
Sergiy Kolodyazhnyy,

Non hai bisogno dei privilegi di superutente per eseguire il debug di un processo di proprietà del tuo utente. Bene, a meno che tu non abbia impostato il sistema in modo appropriato .
Ruslan,

6

Come sapere se un programma è in esecuzione o desidera l'input dell'utente

Dipende dal programma e da come lo invochi.

  • Spesso, ma non sempre, verrà visualizzato un messaggio che indica che il programma richiede input.

  • Se non si è sicuri, è possibile verificare se il processo del programma è occupato

    • usa CPU - usa topohtop

    • legge o scrive - usa sudo iotop -o

  • E quando il programma è terminato, vedrai il prompt della shell.

shellscript running

Avevo uno shellscript che controlla se un programma è in esecuzione, e ora ho aggiunto l'opzione -sper farlo funzionare sudo strace -f -p <PID>(secondo la risposta di Sergiy Kolodyazhnyy) quando viene trovato un ...

Lo shellscript usa

  • ps -ef per trovare la maggior parte dei programmi
  • systemctl is-active --quiet per trovare alcuni programmi
  • e se lo desideri stracein una xtermfinestra.

    Installa xtermse vuoi usare straceper vedere l'attività di un programma.

uso

$ ./running
Usage:    ./running <program-name>
          ./running <part of program name>
Examples: ./running firefox
          ./running term                     # part of program name
          ./running dbus
          ./running 'dbus-daemon --session'  # words with quotes
          ./running -v term                  # verbose output
          ./running -s term                  # strace checks activity

È possibile installare lo shellscript runningin una directory PATHse si desidera accedervi facilmente.

Il codice shellscript

#!/bin/bash

# date        sign     comment
# 2019-02-14  sudodus  version 1.0

verbose=false
strace=false
if [ "$1" == "-v" ]
then
 verbose=true
 shift
fi
if [ "$1" == "-s" ]
then
 strace=true
 shift
fi

if [ $# -ne 1 ]
then
 echo "Usage:    $0 <program-name>
          $0 <part of program name>
Examples: $0 firefox
          $0 term                     # part of program name
          $0 dbus
          $0 'dbus-daemon --session'  # words with quotes
          $0 -v term                  # verbose output
          $0 -s term                  # strace checks activity"
 exit
fi

inversvid="\0033[7m"
resetvid="\0033[0m"
redback="\0033[1;37;41m"
greenback="\0033[1;37;42m"
blueback="\0033[1;37;44m"

runn=false
#tmpfil=$(mktemp)
tmpdir=$(mktemp -d)
tmpfil="$tmpdir/tmpfil"
vtfile="$tmpdir/vtfile"
vthead="$tmpdir/vthead"

# check by systemctl

systemctl is-active --quiet "$1"
if [ $? -eq 0 ]
then
 echo "systemctl is-active:"
 runn=true
fi

# check by ps

ps -ef | tr -s ' ' ' ' | cut -d ' ' -f 8- | grep "$1" | grep -vE -e "$0 *$1" -e "$0 *.* *$1" -e "grep $1" | sort -u > "$tmpfil"
#cat "$tmpfil"
if $verbose || $strace
then
 ps -ef |head -n1 > "$vthead"
 ps -ef | grep "$1" | grep -vE -e "$0 *.* *$1" -e "grep $1" | sort -u > "$vtfile"
fi

tmpstr=$(head -n1 "$tmpfil")
#echo "tmpstr=$tmpstr"
tmpess=$(grep -om1 "$1" "$tmpfil")
#echo "tmpess=$tmpess"
if [ "$tmpstr" == "$1" ] || [ "${tmpstr##*/}" == "$1" ] || [ "${1##*/}" == "${0##*/}" ] || [ "$tmpess" == "$1" ]
then
 echo "ps -ef: active:"
 runn=true
 if $verbose
 then
  cat "$vthead" "$vtfile"
 fi
elif test -s "$tmpfil"
then
 if $runn
 then
  echo "----- consider also ------------------------------------------------------------"
  if $verbose
  then
   cat "$vthead" "$vtfile"
  else
   cat "$tmpfil"
  fi
  echo "--------------------------------------------------------------------------------"
 else
  echo "----- try with: ----------------------------------------------------------------"
  if $verbose
  then
   cat "$vthead" "$vtfile"
  else
   cat "$tmpfil"
  fi
  echo "--------------------------------------------------------------------------------"
 fi
fi

if $runn
then
 echo -en "$greenback '$1"
 if [ "$tmpstr" != "$tmpess" ]
 then
  echo -n " ..."
 fi
 echo -e "' is running $resetvid"

 if $strace
 then
  which xterm
  if [ $? -eq 0 ]
  then
   pid=$(head -n1 "$vtfile" | sed 's/^ *//' | tr -s ' ' '\t' | cut -f 2)
   echo "checking pid=$pid; quit with 'ctrl + c' in the xterm window"
   xterm -title "'strace' checks '$1'" 2> /dev/null -e sudo strace -f -p $pid
  else
   echo "Please install 'xterm' for this function to work"
   exit
  fi
 fi
else
 inpath=$(which "$1")
 if [ "$inpath" == "" ]
 then
  echo -e "$redback no path found to '$1' $resetvid"
 else
  echo -e "$blueback '$1' is not running $resetvid"
 fi
fi
rm -r "$tmpdir"

dimostrazione

Controllo delle finestre dei terminali in Lubuntu (LXTerminal avviato come x-terminal-emulatore gnome-terminalfinestre personalizzate ),

$ running -v -s term 
----- try with: ----------------------------------------------------------------
UID        PID  PPID  C STIME TTY          TIME CMD
sudodus   2087  1384  0 13:33 ?        00:00:00 x-terminal-emulator
sudodus   2108  1269  0 13:33 ?        00:00:17 /usr/lib/gnome-terminal/gnome-terminal-server
--------------------------------------------------------------------------------
 no path found to 'term' 

$ running -v -s x-terminal-emulator
ps -ef: active:
UID        PID  PPID  C STIME TTY          TIME CMD
sudodus   2087  1384  0 13:33 ?        00:00:00 x-terminal-emulator
 'x-terminal-emulator' is running 
/usr/bin/xterm
checking pid=2087; quit with 'ctrl + c' in the xterm window

C'è molta attività non appena il cursore si trova nella finestra del terminale.

inserisci qui la descrizione dell'immagine

Avvio grep(in attesa di input da /dev/stdin)

$ grep -i --color 'hello'
asdf
Hello World    
Hello World

Controllandolo

$ running -s grep
ps -ef: active:
 'grep ...' is running 
/usr/bin/xterm
checking pid=14982; quit with 'ctrl + c' in the xterm window

Non c'è molta attività e puoi identificare cosa sta succedendo.

inserisci qui la descrizione dell'immagine


Buona menzione iotop, sebbene l'utilizzo della CPU potrebbe non essere necessariamente un indicatore se un processo è occupato. Un programma scritto in C e ottimizzato potrebbe utilizzare una CPU minima. Alcuni degli indicatori che ho scritto in Python pianificano l'esecuzione ripetuta di un'attività, quindi potrebbe utilizzare la CPU per aggiornare il menu degli indicatori per un breve momento e quindi rimanere semplicemente lì.
Sergiy Kolodyazhnyy,

@SergiyKolodyazhnyy, Sì, hai ragione. Il stracemetodo è migliore, ma forse non necessario o non disponibile.
sudodus,

Concordato. Non penso che sia preinstallato con Ubuntu e potrebbe essere eccessivo.
Sergiy Kolodyazhnyy,

1

Non sono sicuro se ne hai ancora bisogno, ma comunque un trucco utile da sapere: se il programma sembra uscire senza alcun output, puoi verificare se è in esecuzione in background eseguendo

ps -efa | grep "program_name"

Saluti!


1

Se si esegue la shell in un terminale, ad esempio un emulatore di terminale o una tipica sessione ssh, la shell ha quasi sicuramente abilitato il controllo dei lavori. Questo rende la risposta alla tua domanda super facile nella maggior parte dei casi.

Digitare Ctrl+Zper sospendere il processo e quindi bgper continuare in background, quindi digitare una riga vuota nella shell in modo da verificare se il programma è stato arrestato da un segnale.

Se il processo sta provando a leggere dal terminale, riceverà immediatamente un SIGTTINsegnale e verrà sospeso. (Quando il controllo dei processi è abilitato, il sistema consente solo un processo alla volta di leggere dal terminale.) La shell segnalerà questo. È quindi possibile digitare fgper continuare il processo in primo piano e quindi digitare l'input da leggere normalmente dal programma.

mp@ubuntu:~$ sleep 30 # a program that is not reading from the terminal
^Z
[1]+  Stopped                 sleep 30
mp@ubuntu:~$ bg
[1]+ sleep 30 &
mp@ubuntu:~$ 
mp@ubuntu:~$ 


mp@ubuntu:~$ cat - # a program that is reading from the terminal
^Z
[1]+  Stopped                 cat -
mp@ubuntu:~$ bg
[1]+ cat - &
mp@ubuntu:~$ 
[1]+  Stopped                 cat -
mp@ubuntu:~$ jobs -l
[1]+  3503 Stopped (tty input)     cat -
mp@ubuntu:~$ fg
cat -
hi
hi

Alcuni programmi, come gli editor, intercettano o ignorano il segnale generato Ctrl+Zo mettono il terminale in una modalità in cui i caratteri di controllo non generano nemmeno segnali. Avrete bisogno di utilizzare tecniche più avanzate in questo caso, come l'utilizzo stracedi vedere se il processo sta facendo read, select, poll, etc.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.