Это, в основном, дополнение к этому вопросу: перенаправить КОПИЮ stdout в файл журнала из самого скрипта bash
Итак, используя этот тестовый скрипт:
#!/bin/bash
echo 'bash version:'
bash --version|grep release
echo '';
echo '----------------'
rm /tmp/logfile 2>/dev/null;
function testCommands() {
local mode="$1"
echo "testCommands(): mode == $mode";
# Link file descriptor #6 with stdout to save stdout, #7 for stderr
exec 6>&1;
exec 7>&2;
if [[ 'both' == "${mode}" ]]; then
# log to file and stdout
exec > >(tee -ia /tmp/logfile);
elif [[ 'file' == "${mode}" ]]; then
# log to file only
exec 1>> /tmp/logfile
elif [[ 'quiet' == "${mode}" ]]; then
# be quiet
exec 1> /dev/null
#else - use normal stdout
fi
if [[ 'true' != "${separate_stderr}" ]]; then
#by default, merge stderr to stdout for simple logging
exec 2>&1
#else - keep stderr separate like it normally is
fi
echo "fee";
echo "fye";
echo "foh";
echo "fum";
# Restore stdout/stderr and close file descriptors #6/#7
exec 1>&6 6>&-;
exec 2>&7 7>&-;
}
testCommands 'file'
echo '----------------'
echo ''
echo 'check /tmp/logfile'
ls -acl /tmp/logfile
echo ''
echo 'check output'
cat /tmp/logfile
rm /tmp/logfile 2>/dev/null;
echo '----------------'
testCommands 'stdout'
echo '----------------'
echo ''
echo 'check /tmp/logfile'
ls -acl /tmp/logfile
echo ''
echo 'check output'
cat /tmp/logfile
rm /tmp/logfile 2>/dev/null;
echo '----------------'
testCommands 'both'
echo '----------------'
echo ''
echo 'check /tmp/logfile'
ls -acl /tmp/logfile
echo ''
echo 'check output'
cat /tmp/logfile
rm /tmp/logfile 2>/dev/null;
echo '----------------'
testCommands 'quiet'
echo '----------------'
echo ''
echo 'check /tmp/logfile'
ls -acl /tmp/logfile
echo ''
echo 'check output'
cat /tmp/logfile
echo '----------------'
Я получаю следующий вывод:
bash version:
GNU bash, version 4.4.20(1)-release (x86_64-pc-linux-gnu)
----------------
testCommands(): mode == file
----------------
check /tmp/logfile
-rw-rw---- 1 testuser testuser 16 Sep 20 16:10 /tmp/logfile
check output
fee
fye
foh
fum
----------------
testCommands(): mode == stdout
fee
fye
foh
fum
----------------
check /tmp/logfile
ls: cannot access '/tmp/logfile': No such file or directory
check output
cat: /tmp/logfile: No such file or directory
----------------
testCommands(): mode == both
----------------
check /tmp/logfile
fee
fye
foh
fum
-rw-rw---- 1 testuser testuser 16 Sep 20 16:10 /tmp/logfile
check output
fee
fye
foh
fum
----------------
testCommands(): mode == quiet
----------------
check /tmp/logfile
ls: cannot access '/tmp/logfile': No such file or directory
check output
cat: /tmp/logfile: No such file or directory
----------------
Здесь есть немало выводов, так что, если вы не увидели его в первый раз, то часть, которая выглядит странно, находится в разделе testCommands (): mode == both .
То, что я ожидал увидеть здесь, это то, что сначала выводятся все выходные данные функции, а затем выходные данные echo / ls / cat, определенные после вызова.Вместо этого вывод функции отображается между выводом от 2 команд, которые должны быть запущены после завершения функции.Другими словами, вот что я ожидаю, что должно произойти (примечание: ниже не фактический вывод - я его придумал):
----------------
testCommands(): mode == both
fee
fye
foh
fum
----------------
check /tmp/logfile
-rw-rw---- 1 testuser testuser 16 Sep 20 16:10 /tmp/logfile
check output
fee
fye
foh
fum
Я запускаю это из Linux Mint v19.2 x64 Cinnamon (на основес Ubuntu 18.04) на моем домашнем компьютере.Я искал, чтобы адаптировать ответ exec из другого поста к общему сценарию functions.sh, который я планирую вызывать из других сценариев оболочки bash, моего .bash_aliases и т. Д. У меня есть несколько сценариев, в которых я хотел бы вызвать ту же функциюв различных сценариях с различными требованиями к ведению журнала: файл + стандартный вывод, только файл, только стандартный вывод и без вывода сообщений.Я предпочитаю вводить stderr в стандартный вывод для всех моих сценариев.
1) При вызове testCommands 'both'
я вижу вывод после функции, отображаемой перед выводом из самой функции.Любопытно, есть ли способ подтвердить это на самом деле из-за буферизации в тройнике, из-за чего-то совершенно другого или из-за какой-то комбинации.
2) Есть ли способ исправить это из bash, кроме использования «unbuffered»версия tee 'упоминается в другом вопросе?например, даже если это буферизация, могу ли я отключить или даже принудительно распечатать буферизованный вывод до завершения функции с помощью команд bash / other posix?Я бы предпочел избегать внешних зависимостей, но не вижу, чтобы я переключался на любые дистрибутивы, которые не используют bash в качестве оболочки по умолчанию.
3) Есть ли более элегантный / гибкий / более простой в обслуживании способидти об управлении выводом при использовании Bash?(например, управление различными перестановками отображения / скрытия вывода stdout / stderr для консоли / файла журнала)