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

36

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

Что я понимаю

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

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

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

Ответы:

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

grawity
источник
Я понятия не имел, что выполнение 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
i.imgur.com/x3fnN.jpg
благодарность
Извините, если вы не собирались учить меня указаниям, я не буду следовать тому заявлению, которое вы сделали ранее.
PeanutsMonkey
1
Возьмите перенаправления каждого дескриптора файла по одному слева направо и примените эти правила в указанном порядке. Если вы сначала направите stdout в файл, а затем перенаправите stderr туда, куда сейчас указывает stdout, тогда stderr и stdout перейдут в один и тот же файл. Если поменять местами эти два переадресовывает вокруг, то вы получите разные результаты (Перенаправление STDERR, где стандартный вывод будет в настоящее время , а затем перейти к STDOUT точку в другой файл, в то время как STDERR продолжается , где это было указано в).
Джейсон
2

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

strace -p $pid 2>&1 | less
jpalecek
источник
Что вы имеете в виду 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>&-
Zaz
источник
1

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

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

soandos
источник
Что вы подразумеваете под манипулированием? Насколько я понимаю, все, что перенаправлено, >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
umläute
источник