16

У меня есть сценарий bash с большим количеством выходных данных, и я хотел бы изменить этот сценарий (не создавать новый), чтобы скопировать весь вывод в файл, точно так же, как это произошло бы, если бы я передавал его через тройник.

У меня есть файл script.sh:

#!/bin/bash
init
do_something_that_outputs_stuff_to_STDOUT
launch_applications_that_output_to_STDOUT
fini

и я хотел бы сделать копию STDOUT в файл script.log без необходимости вводить ./script.sh | tee script.log каждый раз.

Спасибо том

7 ответов7

22

Просто добавьте это в начало вашего скрипта:

exec > >(tee -ia script.log)

Это добавит все выходные данные, отправленные на стандартный вывод, в файл script.log , оставив прежнее содержимое на месте. Если вы хотите запускать заново каждый раз, когда запускается скрипт, просто добавьте rm script.log непосредственно перед этой командой exec или удалите -a из команды tee .

-i опция заставляет tee игнорировать сигнал прерывания и может позволить tee поймать более полный набор выходной.

Добавьте эту строку, чтобы также отлавливать все ошибки (в отдельном файле):

exec 2> >(tee -ia scripterr.out)

Пробелы между несколькими символами > важны.

15

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

Как уже упоминалось, вы можете использовать exec для перенаправления стандартной ошибки и стандартной ошибки для всего сценария. Вот так:
exec > $LOGFILE 2>&1 Это выведет все stderr и stdout в $ LOGFILE.

Теперь, так как вы хотите, чтобы это отображалось на консоли, а также в лог-файле, вам также придется использовать именованный канал для exec для записи и для чтения.
(Однострочник Денниса технически тоже делает это, хотя, очевидно, по-другому). Сам канал создается с помощью mkfifo $PIPEFILE . Затем сделайте следующее.

# Start tee writing to a logfile, but pulling its input from our named pipe.
tee $LOGFILE &lt $PIPEFILE &

# capture tee's process ID for the wait command.
TEEPID=$!

# redirect the rest of the stderr and stdout to our named pipe.
exec > $PIPEFILE 2>&1

echo "Make your commands here"
echo "All their standard out will get teed."
echo "So will their standard error" >&2

# close the stderr and stdout file descriptors.
exec 1>&- 2>&-

# Wait for tee to finish since now that other end of the pipe has closed.
wait $TEEPID

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

Для справки, я почерпнул большую часть этого из очень информативного поста в блоге случайного парня: (Архивная версия)

5

Я полагаю, что другой подход выглядит примерно так:

#!/bin/bash

# start grouping at the top
{ 
    # your script goes here
    do_something_that_outputs_stuff_to_STDOUT
    launch_applications_that_output_to_STDOUT

# and at the bottom, redirect everything from the grouped commands
} 2>&1 | tee script.log 
5

Это комбинированная версия ответа, опубликованного Деннисом Уильямсоном ранее. Добавляет оба err & std в script.log в правильном порядке.

Добавьте эту строку в начало вашего скрипта:

exec > >(tee -a script.log) 2>&1

Обратите внимание на пробел между знаками > . У меня работает на GNU bash, версия 3.2.25(1)-релиз (x86_64-redhat-linux-gnu)

3

Если вы хотите получить копию вывода, вы можете использовать tee таким образом:

  #!/bin/bash
  init
  do_something_that_outputs_stuff_to_STDOUT | tee script.log
  launch_applications_that_output_to_STDOUT | tee -a script.log
  fini

Тем не менее, это будет регистрировать только стандартный вывод в script.log. Если вы хотите убедиться, что и stderr, и stdout перенаправлены, используйте:

  #!/bin/bash
  init
  do_something_that_outputs_stuff_to_STDOUT 2>&1 | tee script.log
  launch_applications_that_output_to_STDOUT 2>&1 | tee -a script.log
  fini

Вы могли бы даже сделать это немного лучше с небольшой функцией:

  #!/bin/bash

  LOGFILE="script.log"
  # Wipe LOGFILE if you don't want to add to it at each run
  rm -f "$LOGFILE"

  function logcmd() {
        local cmd="$1" logfile=${LOGFILE:-script.log} # Use default value if unset earlier

        # Launch command, redirect stderr to stdout and append to $logfile
        eval '$cmd' 2>&1 | tee -a "$logfile"
  }

  init
  logcmd "do_something_that_outputs_stuff_to_STDOUT"
  logcmd "launch_applications_that_output_to_STDOUT"
  fini
0
#!/bin/bash
init
do_something_that_outputs_stuff_to_STDOUT > script.log 2>&1
launch_applications_that_output_to_STDOUT >> script.log 2>&1
fini

Вы можете узнать больше о том, как это работает здесь:http://www.xaprb.com/blog/2006/06/06/what-does-devnull-21-mean/

0

Вы бы просто использовали это:

script logfile.txt
your script or command here

Это выводит все в этот журнал, все, а также отображает его на экране. Если вы хотите ПОЛНЫЙ вывод, это как это сделать.

И затем вы можете повторить сценарий, если вы ленивы.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .