Как перенаправить stdout в файл, а stdout + stderr - в другой?

При использовании только инструментов POSIX (а в HP-UX не так много других) это сложно, потому что нет удобного способа узнать время модификации файла. С помощью ls -l вам нужно иметь дело с двумя случаями: последние файлы с месяцем, днем, домом и минутами и старые файлы (> 6 месяцев) с месяцем, днем ​​и годом. (Может быть более простой способ - создать соответствующие настройки локали, но я не знаю, можно ли это сделать в HP-UX.)

#!/bin/sh
set -e -f
set -- $(LC_ALL=C ls -dlog -- "$1")
# $1=permissions $2=link_count $3=size $4,$5,$6=date_time $7...=filename
case $4 in
  Jan) month=1;;
  Feb) month=2;;
  Mar) month=3;;
  Apr) month=4;;
  May) month=5;;
  Jun) month=6;;
  Jul) month=7;;
  Aug) month=8;;
  Sep) month=9;;
  Oct) month=10;;
  Nov) month=11;;
  Dec) month=12;;
esac
case $6 in
  *:*) # The timestamp is within the last 6 month, so
       # the year is the current or previous year.
    current_month=$(LC_ALL=C date +%Y%m)
    year=${current_month%??}
    current_month=${current_month#????}
    case $current_month in 0*) current_month=${current_month#0};; esac
    if [ $current_month -lt $month ]; then year=$((year-1)); fi;;
  *) year=$6;;
esac
if [ $month -le 9 ]; then month=0$month; fi
day=$5
if [ $day -le 9 ]; then day=0$day; fi
mkdir $year$month$day

Если вы используете какую-то древнюю версию HP-UX, где / bin / sh - это старая оболочка Bourne, вам может потребоваться заменить / bin / sh в строке shebang на путь к оболочке POSIX, такой как ksh.

33
15.05.2019, 08:23
4 ответа

Проблема в том, что когда вы перенаправляете свой вывод, он больше не доступен для следующего перенаправления. Вы можете подключиться к teeв подоболочке, чтобы сохранить вывод для второго перенаправления:

( cmd | tee -a file2 ) >> file1 2>&1

или если вы хотите увидеть вывод в терминале:

( cmd | tee -a file2 ) 2>&1 | tee -a file1

Чтобы избежать добавления stderr первого teeв file1, вы должны перенаправить stderr вашей команды на какой-либо файловый дескриптор (, например. 3 ), а позже снова добавьте это в stdout:

( 2>&3 cmd | tee -a file2 ) >> file1 3>&1
# or
( 2>&3 cmd | tee -a file2 ) 3>&1 | tee -a file1

(спасибо @fra -Сан)

43
27.01.2020, 19:37

Вы можете :пометить стандартный вывод (с помощью НЕБУФЕРИРОВАННОГО sed, т. е. :sed -u...), сделать так, чтобы stderr также переходил на стандартный вывод (без тегов, поскольку он не проходил через этот тегирующий sed ), и, таким образом, иметь возможность различать 2 в результирующем файле журнала.

Следующее :является медленным(Его можно серьезно оптимизировать, используя, например, сценарий perl вместо while... ; do... ;done, например, это будет порождать подоболочки и команды в каждой строке! ), странно(кажется, мне нужны 2 этапа {}, чтобы в одном переименовать стандартный вывод, а затем в другом добавить к нему "проваленный" стандартный вывод )и т. д. Но это :" доказательство концепции ", которое попытается максимально сохранить порядок вывода stdout и stderr:

#basic principle (some un-necessary "{}" to visually help see the layers):
# { { complex command ;} | sed -e "s/^/TAGstdout/" ;} 2>&1 | read_stdin_and_redispatch

#exemple:
# complex command = a (slowed) ls of several things (some existing, others not)
#  to see if the order of stdout&stderr is kept

#preparation, not needed for the "proof of concept", but needed for our specific exemple setup:
\rm out.file out_AND_err.file unknown unknown2 
touch existing existing2 existing3

#and the (slow, too many execs, etc) "proof of concept":
uniquetag="_stdout_" # change this to something unique, that will NOT appear in all the commands outputs... 
                     # avoid regexp characters ("+" "?" "*" etc) to make it easy to remove with another sed later on.

{
   { for f in existing unknown existing2 unknown2 existing3 ; do ls -l "$f" ; sleep 1; done ;
   } | sed -u -e "s/^/${uniquetag}/" ;
} 2>&1 | while IFS="" read -r line ; do
    case "$line" in
       ${uniquetag}*) printf "%s\n" "$line" | tee -a out_AND_err.file | sed -e "s/^${uniquetag}//" >> out.file ;; 
        *)            printf "%s\n" "$line"       >> out_AND_err.file ;;   
    esac; 
done;

# see the results:
grep "^" out.file out_AND_err.file
3
27.01.2020, 19:37

Сzsh:

cmd >& out+err.log > out.log

В режиме добавления:

cmd >>& out+err.log >> out.log

В zshи при условии, что опция mult_iosне отключена, когда файловый дескриптор (здесь 1 )несколько раз перенаправляется для записи, тогда оболочка реализует встроенный -в tee, чтобы дублировать вывод на все цели.

16
27.01.2020, 19:37

Если порядок вывода должен быть:stdout, то stderr ; нет решения только с перенаправлением.
stderr должен храниться во временном файле

.
cmd 2>>file-err | tee -a file1 >>file2
cat file-err >> file1
rm file-err

Описание:

Единственный способ перенаправить один вывод (fd типа stdout или stderr )в два файла — это воспроизвести его. Команда tee— правильный инструмент для воспроизведения содержимого файлового дескриптора. Таким образом, первоначальная идея иметь один вывод для двух файлов состоит в том, чтобы использовать:

... |  tee file1 file2

Это воспроизводит стандартный ввод tee в оба файла (1 и 2 ), оставляя вывод tee по-прежнему неиспользованным. Но нам нужно добавить (use-a)и нужна только одна копия. Это решает обе проблемы:

... | tee -a file1 >>file2

Чтобы поставить teeс stdout (для повторения ), нам нужно использовать stderr непосредственно из команды. В одном случае, если порядок не важен, (порядок вывода будет (скорее всего )сохранен в том виде, в котором он был сгенерирован, то, что будет выведено первым, будет сохранено первым ). Либо:

  1. cmd 2>>file1 | tee -a file2 >>file1
  2. cmd 2>>file1 > >( tee -a file2 >>file1 )
  3. ( cmd | tee -a file2 ) >> file1 2>&1

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

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

2
27.01.2020, 19:37

Теги

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