Как сохранить stdout в файл, stderr в файл, stdout+stderr в файл и получить stdout + stderr в терминал, как обычно для скрипта оболочки

Как сохранить stdout в файл, stderr в файл, stdout+stderr в файл и получить stdout + stderr в терминал, как обычно для скрипта оболочки

Как сохранить stdout в один файл, stderr в другой файл, stdout+stderr в третий файл, а также вывести stdout + stderr на терминал, как обычно для скрипта оболочки?

Я нашел это в другом месте:

exec > >(tee std_out) 2> >(tee err_out >&2)
ls # Should got to std_out
fsdfs # Command not found goes to err_out

Что очень близко. Если я запускаю, bash test.sh 2>&1 | tee outputто это работает, но у меня нет доступа к тому, как выполняется мой скрипт. Это система cicd. Мне нужно иметь возможность делать "комбинированный вывод" изнутри скрипта с помощью exec.

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

решение1

Просто расширенный вариант вашего подхода:

exec 2> >(tee -a stderr stdall) 1> >(tee -a stdout stdall)

Стандартная ошибка будет записана в файл с именем stderr, стандартный вывод — в stdout, а стандартная ошибка и стандартный вывод также будут записаны в консоль (или на то, на что указывают два файловых дескриптора во время execзапуска) и в stdall.
tee -a(добавить) требуется для предотвращения stdallперезаписи вторым файлом tee, который начнет запись в него.

Обратите внимание, чтоприказв котором выполняются перенаправления, имеет значение: вторая подстановка процесса затронута первым перенаправлением, т. е. ошибки, которые она выдала, будут отправлены в >(tee -a stderr stdall). Конечно, вы можете перенаправить стандартную ошибку подстановки второго процесса в , чтобы /dev/nullизбежать этого побочного эффекта. Перенаправление стандартного вывода перед стандартной ошибкой отправит каждую ошибку в stdoutи stdallтоже.

Так как команды в процессе Bash выполняются подстановкиасинхронно, нет способа гарантировать, что их вывод будет отображаться в том порядке, в котором он был сгенерирован. Хуже того, фрагменты из стандартного вывода и стандартной ошибки, скорее всего, окажутся на одной строке.

решение2

Ваш скрипт может выполняться самостоятельно $0(с установкой и проверкой переменной окружения, чтобы избежать бесконечной рекурсии) вместо того, чтобы полагаться на > >(...)конструкцию bash, которая IMLE капризна и ненадежна.

if [ "$REDIRECTED" != 1 ]; then
        export REDIRECTED=1
        set -o pipefail
        { { "$0" | tee stdout >&3; } 2>&1 | tee stderr; } 3>&1 | tee stdboth
        exit
fi
# rest of your script here

Так как teeне использует буферизацию строк (и не может быть принудительно сделана с помощью stdbuf(1)), порядок данных, записанных в stdout и stderr, не будет соблюден в конечном выводе. С командой, которая использует полную буферизацию и пишет как в stdout, так и в stderr, даже буферизация строк teeне поможет и, что еще хуже, вы можете получить в выводе строки, которые наполовину являются stdout и наполовину stderr.

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

решение3

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

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

Связанный контент