, Как я нахожу номер строки в Bash, когда ошибка произошла?

Команду lsof нужно запускать от имени пользователя root, иначе она покажет только прослушиваемые порты, принадлежащие вашему пользователю.

# lsof -i:25
COMMAND PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
master  844 root   12u  IPv4   6975      0t0  TCP *:smtp (LISTEN)
master  844 root   13u  IPv6   6976      0t0  TCP *:smtp (LISTEN)

Команда systemctl знает только об услугах, но не о номерах портов или именах протоколов. т.е. вам нужно знать, какой конкретный пакет (например, sendmail , exim , postfix и т. д.) предоставляет услугу smtp. например

# systemctl | grep -E 'postfix|exim|sendmail|qmail'
postfix.service

другой вариант - быть более универсальным в том, что вы ищете. например grep для mail , а не smtp

# systemctl --all | grep -i mail
  postfix.service                 loaded    active   running   LSB: Postfix Mail Transport Agent
  mail-transport-agent.target     loaded    active   active    Mail Transport Agent
22
13.08.2018, 04:46
4 ответа

Вместо вашей функции я бы использовал этот метод:

$ cat yael.bash
#!/bin/bash

set -eE -o functrace

file1=f1
file2=f2
file3=f3
file4=f4

failure() {
  local lineno=$1
  local msg=$2
  echo "Failed at $lineno: $msg"
}
trap 'failure ${LINENO} "$BASH_COMMAND"' ERR

cp -- "$file1" "$file2"
cp -- "$file3" "$file4"

Это работает путем перехвата ERR и последующего вызова функции failure()с текущим номером строки + командой bash, которая была выполнена.

Пример

Здесь я не позаботился о создании файлов f1, f2, f3или f4. Когда я запускаю вышеуказанный скрипт:

$./yael.bash
cp: cannot stat ‘f1’: No such file or directory
Failed at 17: cp -- "$file1" "$file2"

Сбой, сообщает номер строки плюс команда, которая была выполнена.

44
27.01.2020, 19:42

Bash имеет встроенную переменную -$LINENO, которая заменяется текущим номером строки в операторе, поэтому вы можете сделать

in_case_fail $? "at $LINENO: cp $file1 $file2"

Вы также можете попробовать использовать trap... ERR, который запускается при сбое команды (, если результат не проверен ). Например:

trap 'rc=$?; echo "error code $rc at $LINENO"; exit $rc' ERR

Затем, если команда типа cp $file1 $file2не удалась, вы получите сообщение об ошибке с номером строки и выходом. Вы также обнаружите команду с ошибкой в ​​переменной $BASH_COMMAND(, но без каких-либо перенаправлений и т. д. ).

15
27.01.2020, 19:42

В дополнение к LINENO, содержащему номер текущей строки, существуют массивы BASH_LINENO,FUNCNAMEBASH_SOURCE), которые содержат имена функций и номера строк, из которых они вызываются.

Так что вы можете сделать что-то вроде этого:

#!/bin/bash

error() {
        printf "'%s' failed with exit code %d in function '%s' at line %d.\n" "${1-something}" "$?" "${FUNCNAME[1]}" "${BASH_LINENO[0]}"
}

foo() {
        ( exit   0 ) || error "this thing"
        ( exit 123 ) || error "that thing"
}

foo

Запуск для печати

'that thing' failed with exit code 123 in function 'foo' at line 9.

Если вы используете set -eили trap... ERRдля автоматического обнаружения ошибок, обратите внимание, что они имеют некоторые оговорки. Также сложнее включить описание того, что скрипт делал в момент (, как вы сделали в своем примере ), хотя обычному пользователю это может быть полезнее, чем просто номер строки.

См., например,. это для проблем с set -eи другими:

18
27.01.2020, 19:42

Я решил использовать следующее, которое включает трассировку стека как list of fns [list of line numbers], если скрипт находится в функции, или номер строки скрипта в противном случае. Спасибо также за предыдущие ответы, которые я расширил после некоторых экспериментов, чтобы обрабатывать сценарии как на основе fn, так и не на основе fn.

set -eE -o functrace

failure() {
  local lineno=$2
  local fn=$3
  local exitstatus=$4
  local msg=$5
  local lineno_fns=${1% 0}
  if [[ "$lineno_fns" != "0" ]] ; then
    lineno="${lineno} ${lineno_fns}"
  fi
  echo "${BASH_SOURCE[1]}:${fn}[${lineno}] Failed with status ${exitstatus}: $msg"
}
trap 'failure "${BASH_LINENO[*]}" "$LINENO" "${FUNCNAME[*]:-script}" "$?" "$BASH_COMMAND"' ERR

Итак, простой сбой команды выглядит как:

/tmp/b:script[32] Failed with status 1: cp fred john

И вложенные функции (, где hello1 вызывает hello2):

/tmp/b:hello2 hello1 main[24 19 29] Failed with status 1: cp john 22

Я сообщаю статус выхода в тех случаях, когда это дает дополнительную информацию, и, в отличие от всех остальных, мне нужен полный путь к сценарию.

Потребуется дополнительная работа, чтобы сообщить о выходе из-за сигналов.

1
17.05.2021, 14:14

Теги

Похожие вопросы