Як я можу досягти
cmd >> file1 2>&1 1>>file2
Тобто, stdout та stderr повинні перенаправлятись до одного файлу (file1), а лише stdout (file2) повинен перенаправлятись на інший (обидва в режимі додавання)?
Як я можу досягти
cmd >> file1 2>&1 1>>file2
Тобто, stdout та stderr повинні перенаправлятись до одного файлу (file1), а лише stdout (file2) повинен перенаправлятись на інший (обидва в режимі додавання)?
Відповіді:
Проблема полягає в тому, що коли ви перенаправляєте свій вихід, він вже не доступний для наступного переадресації. Ви можете підключити до 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-san)
З zsh
:
cmd >& out+err.log > out.log
У режимі додавання:
cmd >>& out+err.log >> out.log
В zsh
і за умови, що mult_ios
опція не була вимкнена, коли дескриптор файлу (тут 1) перенаправляється кілька разів для запису, тоді оболонка реалізує вбудований модуль tee
для дублювання виводу на всі цілі.
cmd >& file1 > file2
Ви можете: тег stdout (використовуючи UNBUFFERED sed, тобто:), sed -u ...
також stderr також перейти до stdout (без тегів, оскільки він не пройшов цей тег sed) і, таким чином, мати можливість диференціювати 2 в отриманому лог-файлі.
Наступне: повільно (Це може бути серйозно оптимізовано, використовуючи для primeple скрипт perl замість часу ...; do ...; done, for exampleple, який буде нерестувати підрозділи та команди в кожному рядку!), Дивно (здається, мені потрібні 2 {} етапи, щоб в одному перейменувати stdout, а потім в іншому додати до нього "провалився" stderr) і т. д. Але це: " доказ концепції ", який намагатимуться зберегти замовлення виводу максимально 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
ls unknown
), щоб надрукувати щось на stderr? >&2 echo "error"
було б добре. (2) tee
може додавати одночасно до декількох файлів. (3) Чому б не просто cat
замість grep "^"
? (4) ваш сценарій вийде з ладу, коли починається більш жорсткий вихід _stdout_
. (5) Чому?
ls loop
буде виводитись як на stdout, так і на stderr, змішану (альтернативно), у контрольованому порядку; так що ми можемо перевірити, чи зберігали ми впорядкування stderr / stdout, незважаючи на теги 2 stdout): gnu tail, можливо, але звичайний хвіст (напр., aix.). 3): grep "^" також показує обидві назви файлів. 4): це може бути змінено змінною. 5): зведений приклад працює на старих осах (колишній, старий акс), де я перевіряв це (відсутність перл).
uniquetag="banaNa11F453355B28E1158D4E516A2D3EDF96B3450406
...)
Якщо порядок виведення повинен бути: stdout then stderr ; немає рішення тільки з перенаправленням.
Stderr повинен бути збережений у тимчасовому файлі
cmd 2>>file-err | tee -a file1 >>file2
cat file-err >> file1
rm file-err
Опис:
Єдиний спосіб перенаправити один вихід (fd як stdout або stderr) на два файли - це відтворити його. Команда tee
є правильним інструментом для відтворення вмісту дескриптора файлу. Отже, початковою ідеєю мати один вихід на два файли було б використовувати:
... | tee file1 file2
Це відтворює stdin tee в обох файлах (1 і 2), залишаючи вихід tee ще не використаним. Але нам потрібно додати (використовувати -a
) і потрібен лише один примірник. Це вирішує обидва питання:
... | tee -a file1 >>file2
Щоб забезпечити tee
stdout (той, який потрібно повторити), нам потрібно споживати stderr безпосередньо з команди. Один із способів, якщо порядок не важливий (порядок виводу буде (найімовірніше) зберігатися як генерований, залежно від того, що буде виведено, буде збережено першим). Або:
cmd 2>>file1 | tee -a file2 >>file1
cmd 2>>file1 > >( tee -a file2 >>file1 )
( cmd | tee -a file2 ) >> file1 2>&1
Варіант 2 працює лише в деяких оболонках. Варіант 3 використовує додатковий підшалл (повільніше), але використовуйте імена файлів лише один раз.
Але якщо stdout повинен бути першим (залежно від того, який згенерований результат замовлення), нам потрібно зберегти stderr, щоб додати його до файлу наприкінці (перше розміщене рішення).
sponge
це робить:(cmd | tee -a out >> out+err) 2>&1 | sponge >> out+err
В інтересах різноманітності:
Якщо ваша система підтримує /dev/stderr
, то
(cmd | tee -a /dev/stderr) 2>> file1 >> file2
буду працювати. Стандартний вихід вихідного сигналу cmd
направляється як на stdout, так і на stderr трубопроводу. Стандартна похибка cmd
обходу tee
і виходить жорсткіше трубопроводу.
Так
cmd
, іcmd
, змішані.Тоді це проста справа надсилання цих потоків у правильні файли.
Як і при майже будь-якому такому підході (включаючи відповідь Стефана ),
file1
лінії можуть вийти з ладу.
out+err
іout
що тут мається на увазі. Імена файлів? Потоки для переадресації?