Как мне узнать, выполняется команда или ожидает ввода пользователя?

В командной строке я набрал команду и нажал ввод. Это ничего не выводит. Как мне узнать, запущен ли он и еще не выводится, или он запрашивает ввод пользователя?

4 ответа

Решение

Есть несколько подходов:

  1. Попробуйте сигнализировать о конце ввода: без привилегий суперпользователя трудно понять, что происходит под капотом. Что можно сделать, это нажать Ctrl+d. Терминалы и утилиты в каноническом режиме отправляют весь доступный текст read() системный вызов при получении сигнала EOT, связанного с этой комбинацией клавиш, и если нет ввода - read() возвращает отрицательный статус выхода, который большинство утилит принимают в качестве сигнала на выход. Поэтому, если утилита ожидает ввода, она выйдет при получении комбинации клавиш. В противном случае утилита либо выполняет задачи, либо написана неправильно.

  2. Следите за системными вызовами: если у вас есть привилегия суперпользователя, вы можете запустить strace в другом терминале, чтобы увидеть, что в настоящее время делается. Для этого вам нужно узнать PID программы. Например, в другой вкладке терминала запустить pgrep -f firefox который может 1234 в качестве примера, а затем sudo strace -f -p 1234, Если вывод, который вы видите, застрял на read() syscall, это означает, что команда, вероятно, ожидает ввода. В противном случае, если вы видите запущенные системные вызовы, тогда команда делает что-то еще. Смотрите связанный вопрос для использования strace также выяснить, вышла ли длительная команда.

  3. Используйте собственные методы команды: среди прочего, такие утилиты, как dd использовать сигналы. Например, если вы используете kill -USR1 1234 (где 1234 - PID работающего dd команда), он выведет на вывод количество обработанных байтов. Конечно, для этого необходимо знать, прежде всего, о таком поведении команды. Вышеупомянутые два метода являются более общими и не требуют глубоких знаний о поведении каждой команды (хотя всегда лучше знать, что вы на самом деле выполняете - в противном случае вы рискуете выполнить команду, которая может нанести ущерб).

Как определить, запущена ли программа или требуется ввод пользователя

Это зависит от программы и от того, как вы ее вызываете.

  • Часто, но не всегда, появляется подсказка, указывающая, что программа запрашивает ввод.

  • Если вы не уверены, можете проверить, занят ли процесс программы

    • использует процессор - использовать top или же htop

    • читает или пишет - используйте sudo iotop -o

  • И когда программа закончится, вы увидите подсказку оболочки.

Shellscript running

У меня был сценарий, который проверяет, запущена ли программа, и теперь я добавил опцию -s заставить его бежать sudo strace -f -p <PID> (согласно ответу Сергея Колодяжного), когда... найден.

Скрипт использует

  • ps -ef найти большинство программ
  • systemctl is-active --quiet найти несколько программ
  • и если вы хотите strace в xterm окно.

    устанавливать xterm если вы хотите использовать strace следить за активностью программы.

использование

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

Вы можете установить скрипт running в каталог в PATH если вы хотите легкий доступ к нему.

Код шеллскрипта

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

демонстрация

Проверка окон терминала в Lubuntu (LXTerminal запущен как x-terminal-emulator и обычай gnome-terminal окна),

$ 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

Когда курсор находится в окне терминала, появляется много активности.

начало grep (ожидание ввода от /dev/stdin)

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

Проверять это

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

Там не так много активности, и вы можете определить, что происходит.

Если вы запускаете оболочку в терминале, например, в эмуляторе терминала или в типичном сеансе ssh, в вашей оболочке почти наверняка включено управление заданиями. Это делает получение ответа на ваш вопрос очень легким в большинстве случаев.

Введите Ctrl+Z, чтобы приостановить процесс, а затем bg чтобы продолжить в фоновом режиме, введите пустую строку в оболочку, чтобы она проверила, была ли программа остановлена ​​сигналом.

Если процесс пытается прочитать с терминала, он сразу же получит SIGTTIN сигнал и будет приостановлено. (Когда контроль заданий включен, система позволяет только одному процессу одновременно считывать данные с терминала.) Оболочка сообщит об этом. Вы можете тогда напечатать fg чтобы продолжить процесс на переднем плане, а затем введите ввод для чтения программой в обычном режиме.

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

Некоторые программы, такие как редакторы, будут либо перехватывать, либо игнорировать сигнал, генерируемый Ctrl+Z, либо переводить терминал в режим, в котором управляющие символы даже не генерируют сигналы. В этом случае вам нужно будет использовать более продвинутые методы, такие как strace чтобы увидеть, если процесс делает read, select, poll, так далее.

Не уверен, что вам все еще нужно это, но все же полезный трюк, чтобы знать: если кажется, что программа завершает работу без вывода, вы можете проверить, работает ли она в фоновом режиме, выполнив

ps -efa | grep "program_name"

Ура!

Почему бы просто не взглянуть на столбец S (Состояние) верхней команды. Если ваша программа ожидает ввода, велика вероятность, что она спит, а не запущена, что означает, что top выведет S (на этот раз для сна), а не R (для выполнения). Попробуйте эту команду в качестве примера:

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

Другие вопросы по тегам