Команду 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
Вместо вашей функции я бы использовал этот метод:
$ 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"
Сбой, сообщает номер строки плюс команда, которая была выполнена.
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
(, но без каких-либо перенаправлений и т. д. ).
В дополнение к LINENO
, содержащему номер текущей строки, существуют массивы BASH_LINENO
,FUNCNAME
(и BASH_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
и другими:
Я решил использовать следующее, которое включает трассировку стека как 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
Я сообщаю статус выхода в тех случаях, когда это дает дополнительную информацию, и, в отличие от всех остальных, мне нужен полный путь к сценарию.
Потребуется дополнительная работа, чтобы сообщить о выходе из-за сигналов.