Зачем перенаправлять вывод на 2> & 1 и 1> & 2?


36

Я сталкивался с несколькими командами, которые используют 2>&1и 1>&2, но я совершенно не могу понять, как использовать его и когда мне следует его использовать.

Что я понимаю

Я знаю, что 1представляет стандарт и 2представляет стандартную ошибку. Я понимаю, что 2>&1сочетает в себе вывод 2к 1и наоборот.

Что я не получаю

  1. Когда я должен использовать это?
  2. Какой цели это служит?

Ответы:


39

Иногда вы хотите перенаправить как stdout, так и stderr в одно и то же место. Это когда >&используется - он указывает один дескриптор файла на другой.


Например, если вы хотите записать и stdout, и stderr в один и тот же файл (будь то /dev/nullили output.txt), вы можете перенаправить их отдельно, с помощью

app 1>/dev/null 2>/dev/null

или вы можете перенаправить один файловый дескриптор в файл, а другой файловый дескриптор - в первый:

app 1>/dev/null 2>&1

app 2>/dev/null 1>&2

В первом примере 2>&1указатель дескриптора файла № 2 указывает на то место, где номер 1 уже указывает. Второй пример достигает того же самого, просто вместо этого начинается с stderr.

В качестве другого примера, есть случаи, когда stdout (дескриптор файла # 1) уже указывает на желаемое местоположение, но вы не можете ссылаться на него по имени (это может быть связано с каналом, сокетом или подобным). Это часто происходит, когда используется расширение процесса ( операторы ` `or $( )), которое обычно захватывает только стандартный вывод, но вы можете включить в него stderr. В этом случае вы также >&должны указать stderr на stdout:

out=$(app 2>&1)

Другой распространенный пример - пейджер или grepаналогичная утилита, поскольку канал |обычно работает только на stdout, перед перенаправлением канала stderr перенаправляется на stdout:

app 2>&1 | grep hello

Как узнать, что из 2>&1или 1>&2правильно? Уже настроил дескриптор файла идет справа >&, а файл дескриптора вы хотите редирект идет налево. ( 2>&1означает «указать дескриптор файла № 2 на дескриптор файла № 1».)


Некоторые оболочки имеют ярлыки для общего перенаправления; Вот примеры из Bash:

  • 1> можно сократить до всего >

  • 1>foo 2>&1к >&fooили&>foo

  • 2>&1 | program в |& program


Я понятия не имел, что выполнение app 1>/dev/null 2>&1будет означать, что 2> & 1 будет указывать на файл, на который 1 уже перенаправлял. Я так понимаю, я мог бы так же легко сделать app > /dev/null &>?
PeanutsMonkey

Мне трудно понять the already set up fd goes to the right of >&, and the fd you want to redirect goes to the left. Что вы подразумеваете под уже настроенным файловым дескриптором? Что это означает право?
PeanutsMonkey


Извините, если вы не собирались учить меня указаниям, я не буду следовать тому заявлению, которое вы сделали ранее.
PeanutsMonkey

1
Возьмите перенаправления каждого дескриптора файла по одному слева направо и примените эти правила в указанном порядке. Если вы сначала направите stdout в файл, а затем перенаправите stderr туда, куда сейчас указывает stdout, тогда stderr и stdout перейдут в один и тот же файл. Если поменять местами эти два переадресовывает вокруг, то вы получите разные результаты (Перенаправление STDERR, где стандартный вывод будет в настоящее время , а затем перейти к STDOUT точку в другой файл, в то время как STDERR продолжается , где это было указано в).
Джейсон

2

Одна ситуация, когда вам это нужно, это когда вы хотите отобразить straceвывод в пейджере. straceвыводит свой вывод в стандартную ошибку, и каналы обычно соединяют стандартный вывод со стандартным вводом, поэтому вы должны использовать перенаправление:

strace -p $pid 2>&1 | less

Что вы имеете в виду pipes generally connect standard output to standard input?
PeanutsMonkey

2
Я имею в виду, что pipe ( |) берет стандартный вывод первой команды и подключает его к стандартному вводу второй команды.
jpalecek

2

Иногда вы хотите перенаправить оба stdout( 1) и stderr( 2) в одно и то же место ( /dev/nullнапример). Одним из способов достижения этого будет:

$ program 1>/dev/null 2>/dev/null

Но большинство людей сокращают, перенаправив stderrна stdoutс 2>&1:

$ program 1>/dev/null 2>&1

Еще более короткая версия:

$ program >&- 2>&-

1

2: Это для случаев, когда у вас будут выходные данные как из стандартной ошибки, так и из стандартной ошибки, и вы хотите, чтобы они были объединены в одну строку.

1: когда вы хотите манипулировать выводом как стандартной ошибки, так и стандартной ошибки.


Что вы подразумеваете под манипулированием? Насколько я понимаю, все, что перенаправлено, >2отправляется в / dev / null. Или я совершенно не понял?
PeanutsMonkey

Это не правильно. Под манипулированием я подразумеваю, что это нужно для grep или чего-то подобного Смотрите здесь для примера.
Soandos

0

Я использую это, чтобы начать отдельную работу:

someProgram 2>&1 >& my.log &

тогда я могу выйти из системы, и некоторые программы все еще будут работать. Функциональность обеспечивается GNU Screen, tmux и некоторыми другими программами, но здесь это достигается без каких-либо внешних зависимостей.


1
Это работает только до тех пор, пока SIGHUP не отправлено в программу. Лучше использовать nohupили disownв таких случаях.
Slhck

@slhck: хорошо. Но если я не отправлю SIGHUP в программу - никто не отправит, верно?
Adobe

Нет, управляющий терминал будет предупреждать процессы выхода из системы с помощью SIGHUP. На практике, если вы запустите удаленную оболочку через SSH и выйдете, ваш процесс, например, умрет.
slhck

@slhck: Не может быть правдой: я использую его в течение нескольких лет - я выхожу из системы ssh, и процесс все еще выполняется.
Adobe

Мне нужно будет рассмотреть это более подробно, но простой перевод программ в фоновый режим не работает для меня во всех случаях, и он определенно не работает даже на моей локальной машине. Zsh и Bash, похоже, тоже ведут себя по-разному.
Slhck

0

Представьте, что есть каталог tryс этими тремя файлами:file file1 and file2.

Теперь запустите эту команду:

cat file file1 file2 file3

Первые три файла открываются, но catвыдает ошибку при открытии четвертого, так как он не существует.

Теперь запустите:

cat file file1 file2 file3 1>outfile 2>&1

Вы не увидите никакого вывода на экран: Во - первых , 1>outfileбудет перенаправить вывод команды в , outfileа затем он будет перенаправлять ( 2>&1) ошибка выброшен при попытке открыть file3в outfile.

1>&2 работает аналогично и перенаправляет поток ошибок на стандартный вывод.

Надеюсь это поможет!


0

Альтернативный сценарий: команды терминала показывают вывод в другой терминал

Используйте ttyкоманду в каждом терминале, чтобы идентифицировать их:

$ tty
/dev/pts/0

$ tty
/dev/pts/1

Предполагая, что эти TTY, чтобы перенаправить стандартный вывод первого на второй, запустите это в первом терминале:

exec 1>/dev/pts/1

Примечание: теперь каждый вывод команды будет отображаться в pts / 1

Чтобы восстановить стандартный вывод поведения pts / 0:

exec 1>/dev/pts/0

Смотрите это видео для демонстрации.


0

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

Другой случай - перенаправление stdout в stderr. Обычный вариант использования (по крайней мере, для меня) - отправлять предупреждения / сообщения об ошибках, напечатанные с помощью «echo» (в моих скриптах) в stderr (чтобы они могли легче привлечь внимание пользователя).

Например,

echo "file \"${file\" does not exist..." 1>&2
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.