Вы можете добавить ловушку на EXIT, которая убивает все процессы в вашем сеансе:
(чтобы добавить в ваш .bashrc
):
killall_on_exit() {
sid=$(ps -o sid= -p "$$")
if [ "$sid" -eq "$$" ]; then
# we're the session leader
(
trap '' TERM
ps -eo pgid= -o sid= |
awk -v sid="$sid" '$2 == sid && !seen[$1]++ {print "-" $1}' |
xargs kill -s TERM --
)
fi
}
trap killall_on_exit EXIT
Это убивает все группы процессов в вашем сеансе. Это не убьет процессы, которые запускаются в новом сеансе, но поскольку новые сеансы обычно запускаются эмуляторами терминала, если вы уберете эмулятор терминала, скорее всего, процесс, который он порождает, также умрет (и его дочерние элементы, если лидер интерактивный bash с той же ловушкой).
nohup
или disown
обычно не делают команды невосприимчивыми к этому.
Вы можете заменить приведенные выше TERM
на HUP
, но тогда обратите внимание, что некоторые команды, такие как xterm
, игнорируют SIGHUP.
Чтобы иммунизировать команду от SIGTERM, запустите ее как:
(trap '' TERM; emacs &)
После дополнительного тестирования я пришел к выводу, что этот переключатель кода имеет красивую оболочку и возвращает код возврата выполненной команды. Код, который опубликовал @Freddy, почти завершен. Код возврата экспортируется внутрь функции, но не за ее пределы.
Использование shopt -s lastpipe было взято с этой страницы:Запись часто задаваемых вопросов Bash #24 :«Я устанавливаю переменные в цикле. Почему они внезапно исчезают после завершения цикла? Или, почему я не могу передать данные для чтения?"
Вот окончательное рабочее решение:
#!/bin/bash
log_path_file="./logs/test.log"
exe_cmd()
{
echo "`date +%Y-%m-%d---%r` [Info]: Command to execute: $@" | tee -a ${log_path_file};
echo "" | tee -a ${log_path_file};
echo "" | tee -a ${log_path_file};
set +m
shopt -s lastpipe
cmdResult=0
{
"$@"
returncode=$?
# save result code
cmdResult=${returncode}
if [ "$returncode" -eq 0 ]; then
echo "`date +%Y-%m-%d---%r` [Info]: successfully executed \"$@\""
else
echo "`date +%Y-%m-%d---%r` [Info]: failed to execute \"$@\", exit code: ${returncode}"
fi
} 2>&1 | tee -a "$log_path_file"
echo "`date +%Y-%m-%d---%r` [Info]: cmdResult result ${#cmdResult[@]}"
return ${#cmdResult[@]};
}
cmd="scp some_user@$some_host:some_path/* a_local_path/sub_path";
exe_cmd ${cmd}
returncode=$?
echo "`date +%Y-%m-%d---%r` [Info]: scp execution result: ${returncode}" | tee -a ${log_path_file};
В данном конкретном случае было бы проще просто выполнить ls -l
и действовать непосредственно на его статус выхода:
if ls -l "$local_path"; then
echo 'success'
else
printf 'failure (code %d)\n' "$?"
fi | tee -a "$log_path_file"
В оболочке bash
вы также можете исследовать значения в массиве PIPESTATUS
:
$ false | true | true | false | false
$ printf '%s\n' "${PIPESTATUS[@]}"
1
0
0
1
1
В вашем случае:
ls -l "$local_path" | tee -a "$log_path_file"
ls_status=${PIPESTATUS[0]}
if [ "$ls_status" -eq 0 ]; then
echo 'success'
else
printf 'failure (code %d)\n' "$ls_status"
fi | tee -a "$log_path_file"
Вы можете использовать функцию, которая принимает команду в качестве аргументов и tee
выводит (stdout и stderr )в файл журнала.
local_path="~/njn"
log_path_file="test.log"
function log_cmd ()
{
{
"$@"
returncode=$?
if [ "$returncode" -eq 0 ]; then
echo "[successfully executed \"$@\"]"
else
echo "[failed to execute \"$@\", exit code: ${returncode}]"
fi
return $returncode
} 2>&1 | tee -a "$log_path_file"
# return exit code of first command in pipeline
return ${PIPESTATUS[0]}
}
log_cmd ls -l "$local_path"
log_cmd echo "hello world"