Перенаправить bash stdout + stderr в один файл и stderr в другой файл

Вероятно, не рекомендуется хранить большие данные в качестве переменных из соображений переносимости и надежности. Что касается решения, отличного от awk , которое также является POSIX, чтобы быть более портативным, используйте sed .

Пояснение

Для больших объемов данных избегайте сохранения в виде переменных. Хотя Bash сам по себе не налагает ограничений, но ОС может делать это

Предположим, вы говорите: «Это работает в моей ОС». Но,

  • Разные ОС будут иметь разные ограничения
  • , поэтому, если вы хотите максимизировать переносимость, зачем рисковать, что ваш скрипт будет работать в одной ОС и падать на другой только потому, что у них разные ограничения?
  • так что избегайте этой проблемы, в первую очередь не хранить в переменной

Итак, мы сохраняем ее в файле. В частности, разбейте вашу строку на один символ (или любую наименьшую единицу, которую вы хотите), на отдельные строки.

Затем используйте sed :

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

Пример

Имейте данные, по одному символу (или любой другой наименьшей единице, которую вы хотите «пройти») в строке, например, в файле data.lst :

a
b
c
d
e

Имейте свой script.sh содержат:

#!/bin/bash

stop_number="$1"

sed -n "1,${stop_number}p" data.lst

Итак, вы протестируете это в командной строке и увидите:

$ ./script.sh 3
a
b
c
  • он использует sed для печати строки 1 до числа указывается в $ stop_number . Мы выписали $ stop_number вместо $ 1 напрямую, для ясности
  • $ stop_number , конечно, получается с помощью позиционного параметра $ 1 , который равен произвольный ввод числа, который вы хотели
  • , поэтому он успешно прошел через 3 символа data.lst , в той последовательности, в которой он появляется в data.lst
  • в тот момент, если вы вводите число больше, чем фактическое количество строк, он просто покажет все строки.
  • в настоящее время data.lst находится в том же каталоге, что и script.sh , но если вы этого не хотите, если он у вас действительно есть где-то еще, например ~ / some / dir / data.lst , тогда вам просто нужно настроить его так, чтобы он говорил ~ / some / dir / data.lst

Итак, как только ваши фактические данные будут в data.lst вы можете протестировать этот скрипт самостоятельно.

6
23.05.2017, 15:39
1 ответ

С zsh (и только zsh) и его функцией multios:

your-cmd 2> stdout+stderr.log >&2 2> stderr.log

Поскольку fd 2 перенаправляется дважды, zsh реализует внутренний тройник для отправки в оба файла.

В bash (или любой другой оболочке типа Bourne) вы можете выполнить тройниквручную с помощью:

{ your-cmd 2>&1 >&3 3>&- | tee stderr.log 3>&-; } > stderr+stdout.log 3>&1

(хотя вы потеряете статус выхода your-cmd.zsh находится в $pipestatus[1], bash в "${PIPESTATUS[0]}" (при условии, что перенаправление на stderr+stdout.log не завершилось ошибкой)).

Чтобы записать pid your-cmd, вы можете сделать:

{ sh -ec 'echo "$$" > /var/run/pidfile; exec your-cmd' 2>&1 >&3 3>&- |
   tee stderr.log 3>&-; } > stderr+stdout.log 3>&1

С yash и его перенаправлением процесса:

your-cmd > stdout+stderr.log 2>(tee stderr.log)

(но обратите внимание, что yash не будет ждать завершения этой команды tee, поэтому файлы журнала могут быть неполными к тому времени, когда вы выполните следующую команду после этого).

Нечто подобное (и с той же оговоркой) можно сделать с помощью замены процесса в bash, zsh и ksh93:

{ your-cmd 2> >(tee stderr.log); } > stderr+stdout.log

Для запуска в фоновом режиме и получения pid:

(exec your-cmd 2> >(tee stderr.log)) > stderr+stdout.log & pid=$!

С rc:

{your-cmd |[2=0] tee stderr.log} > stdout+stderr.log

каналы rc позволяют указать, какие файловые дескрипторы подключены к каналу. В других оболочках это всегда fd 1 для левой команды и fd 0 для правой (отсюда небольшой танец с fd 3 выше для сдвига файловых дескрипторов). rc сообщит об ошибке, если произойдет сбой либо your-cmd, либо tee, хотя точное число может быть потеряно.

7
27.01.2020, 20:27

Теги

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