bash
. Действительно, вроде всё понятно, но...Например, было непонятно, почему работает команда, перенаправляющая
stderr
в stdout
:ls *.txt *.err >file 2>&1
Но при этом не работает вот так:
ls *.txt *.err 2>&1 >file
И уж совсем китайской грамотой казалась строка:
cat file 3>&2 2>&1 1>&3
Да, мне понятно, что эта команда меняет местами потоки вывода
stderr
и stdout
. То, что выводилось в stdout
, теперь будет выводиться в stderr
и наоборот. Но почему именно так и никак иначе?..Всё оказалось не просто, а очень просто :) Спасибо замечательной книге "Unix Power Tools" издательства O'Reilly.
Дело в том, что оболочка, при разборе параметров командной строки, читает параметры строго слева направо. Этот факт кажется совсем неудивительным, но оказывается именно это правило оказывает влияние на результат обработки командной строки.
Разберем, как интерпретируется строка "
ls *.txt *.err >file 2>&1
":- параметр "
>file
" — означает "перенаправить стандартный поток вывода (stdout
) в файл c именемfile
"; - параметр "
2>&1
" — означает "перенаправить стандартный поток ошибок (2) в стандартный поток вывода (1). Но, так как стандартный поток вывода уже перенаправлен в файл, то и стандартный поток ошибок перенаправляется туда же.
А как интерпретируется строка "
ls *.txt *.err 2>&1 >file
"?- параметр "
2>&1
" — означает "перенаправить стандартный поток ошибок в стандартный поток вывода". На этот момент поток вывода (1) направляется в терминал, а значит, что поток ошибок тоже перенаправится в терминал. - параметр "
>file
" — означает "перенаправить стандартный поток вывода (stdout
) в файл c именемfile
".
После этого совсем не трудно понять, как работает команда "
cat file 3>&2 2>&1 1>&3
". Тут тоже все просто:- поток вывода 3 перенаправить туда же, куда выводится поток вывода 2 — в
stderr
; - поток вывода 2 перенаправить туда же, куда выводится поток 1 — в
stdout
; - поток вывода 1 перенаправить туда же, куда выводится поток 3 — в
stderr
stderr
и stdout
как будто меняются местами — поток 1 идет в stderr
, а поток 2 идет в stdout
.
спасибо, хороший пост.
ОтветитьУдалитьПожалуйста :) Рад, что понравилось :)
ОтветитьУдалитьДобрый день. а Вы не подскажете, можно ли сделать так, чтобы если при выполнении действия, если ошибки есть, то они записывались во вновь содаваемый файл, а если ошибок нет, то файл не создавался вообще? сейчас do_something.sh > error.log 2>&1 файл содается всегда, если нет ошибок, то он пустой. Заранее спасибо:) Вера.
ОтветитьУдалитьЧестно говоря, не знаю. Если узнаете как, напишите, плз. Мне тоже интересно.
ОтветитьУдалитьспасибо, пригодилось. Гуглил по "2>&1", пытаясь понять, почему оно не работает :)
ОтветитьУдалитьпожалуйста :)
ОтветитьУдалитьспасибо, пригодилось! :)
ОтветитьУдалитьСпасибо)понятно и полезно!
ОтветитьУдалитьАнонимный: Просто в любом случае создается файл,а вы напишите условие,например ошибки загружайте в переменную,и проверяйте ее,если переменная не пустая - создать файл и вкинуть туда ошибки,иначе вывести какое-то сообщение и если файлик есть - то удалить его:
ОтветитьУдалить#!/bin/sh
if [ -n "$err" ]
then
echo $err > /else/path/err
else
echo "Nothing to del" 2>&1
rm /else/path/err
fi
а не проще ли удалить вконце файл, если он пустой?
ОтветитьУдалитьсам долго не въезжал, после твоего объяснения на "пальцах" сразу стало все пучком, спс
ОтветитьУдалитьпжлст :)
ОтветитьУдалитьЯ бы переформулировал:
ОтветитьУдалить-----------------------
параметр "2>&1" — означает "перенаправить стандартный поток ошибок (2) в стандартный поток вывода (1).
-----------------------
в
параметр "2>&1" — означает "перенаправить стандартный поток ошибок (2) туда, куда сейчас направлен стандартный поток вывода (1).