20

On command line, I typed a command and hit enter. It doesn't output anything . How do I tell if it's running and not yet output, or it's asking for user input?

Gqqnbig
  • 699

5 Answers5

20

There's several approaches:

  1. Try signalling end of input:Without superuser privileges it is hard to know what is going on underneath the hood. What can be done is to press Ctrl+d. Terminals and utilities in canonical mode send all available text to read() syscall upon receiving EOT signal bound to this key combination, and if there's no input - read() returns negative exit status which most utilities accept as signal to exit. Therefore, if a utility is waiting for input it will exit upon receiving the key combination. Otherwise, the utility is either running tasks or is not written properly.

  2. Spying on syscalls:If you do have superuser privilege, you can run strace in another terminal to see what is currently being done. For that you need to find out PID of the program. For instance, in another terminal tab run pgrep -f firefox which may 1234 as example and then sudo strace -f -p 1234. If the output you see is stuck on read() syscall, it means the command probably is waiting for input. Otherwise, if you see syscalls running by, then command is doing something else. See a related question for usage of strace to also figure out if the long running command has exited.

  3. Use command's own methods: Among other things, such utilities as dd use signals. For instance, if you use kill -USR1 1234 (where 1234 is PID of the running dd command), it will print to stdout the amount of bytes currently processed. Of course, this requires knowing about such behavior of the command in the first place. The above two methods are more general, and don't require deep knowledge of each command's behavior ( though it's always best to know what you're actually executing - otherwise you risk running a command which may do damage ).

6

How to tell if a program is running or wanting user input

It depends on the program and how you invoke it.

  • Often but not always there will be a prompt, that indicates that the program is asking for input.

  • If you are not sure, you can check if the program's process is busy

    • uses CPU - use top or htop

    • reads or writes - use sudo iotop -o

  • And when the program has finished, you will see the shell's prompt.

Shellscript running

I had a shellscript that checks if a program is running, and now I have added the option -s to make it run sudo strace -f -p <PID> (according to Sergiy Kolodyazhnyy's answer) when a ... is found.

The shellscript uses

  • ps -ef to find the majority of programs
  • systemctl is-active --quiet to find some programs
  • and if you wish strace in an xterm window.

    Install xterm if you want to use strace to watch the activity of a program.

Usage

$ ./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

You can install the shellscript running into a directory in PATH if you want easy access to it.

The shellscript code

#!/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"

Demo

Checking terminal windows in Lubuntu (LXTerminal started as x-terminal-emulator and custom gnome-terminal windows),

$ 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

There is a lot of activity as soon as the cursor is in the terminal window.

enter image description here

Starting grep (waiting for input from /dev/stdin)

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

Checking it

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

There is not much activity, and you can identify what is happening.

enter image description here

sudodus
  • 47,684
2

If you're running the shell in a terminal, for example a terminal emulator or a typical ssh session, your shell has almost certainly enabled job control. This makes getting an answer to your question super easy in most cases.

Type Ctrl+Z to suspend the process and then bg to continue it in the background, then type an empty line to the shell so it'll check whether the program got stopped by a signal.

If the process is trying to read from the terminal, it will immediately get a SIGTTIN signal and will get suspended. (When job control is enabled, the system allows only one process at a time to read from the terminal.) The shell will report this. You can then type fg to continue the process in the foreground, and then type input to be read by the program as normal.

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

Some programs, such as editors, will either trap or ignore the signal generated by Ctrl+Z or put the terminal into a mode where control characters don't even generate signals. You'll need to use more advanced techniques in this case, such as using strace to see if the process is doing read, select, poll, etc.

1

Not sure if you still need this, but still a useful trick to know: if the program seems to exit without any output you can check if it is running in background by executing

ps -efa | grep "program_name"

Cheers!

0

Why not simply look at the column S (State) of the top command. If your program is waiting for input, there is a great chance it is sleeping and not running meaning top will output a S (for Sleeping this time) and not a R (for Running). Try this command as an example:

top -b -n 1 | sed -n '7,12p' | awk '{printf "%6s %-10s %-4s %-s\n",$1,$2,$8,$NF}'