Как программы выводят в другое место, чем STDOUT / STDERR? Как этого избежать?

15

Видимо, я не знаю всех выходных пунктов назначения, которые доступны для использования. Я знаю о stdout( &1) и stderr( &2). Однако, после перенаправления обоих дескрипторов, я иногда все еще получаю некоторый вывод в моей консоли!

Самый простой пример, который я могу вспомнить - это GNU Parallel; Каждый раз, когда я его использую, я вижу уведомление о цитировании. Даже когда я это делаю &2>1 > file, я все равно вижу уведомление.

emergeТо же самое относится и к : когда я запускаю emerge и возникают некоторые проблемы, некоторые данные не печатаются stdoutни на stdin, так как я перенаправляю их, и они все еще проходят.

Я в основном решаю эти проблемы с помощью script, но мне все еще интересно, что вызывает эту проблему.

MatthewRock
источник
1
Пожалуйста, приведите полный пример.
Кусалананда
какая оболочка? взгляните на mywiki.wooledge.org/BashFAQ/055 и stackoverflow.com/questions/876239/…
Sundeep
8
Вы не получите их всех . Сценарий всегда может написать /dev/tty.
Сат Кацура
1
Что касается GNU parallel: mkdir ~/.parallel; touch ~/.parallel/will-citeотключит раздражающее сообщение. В качестве альтернативы, посмотрите на другие реализации parallel.
Satō Katsura
2
@OleTange Потому что это не проблема - я спрашиваю, почему что-то происходит, и я использую parallelв качестве примера.
MatthewRock

Ответы:

40

Синтаксис, который вы использовали, неверен.

cmd &2>1 >file

будет разделен как

cmd &
2>1 >file

Это будет:

  1. Запускать cmdв качестве фонового задания без перенаправлений
  2. В отдельном процессе (без команды!) Происходит перенаправление stderrв файл, который называется буквально, 1и перенаправление stdoutвfile

Синтаксис, который вы хотите:

cmd >file 2>&1

Порядок операций важен. Это будет:

  1. Перенаправить stdoutнаfile
  2. Перенаправить stderrна &1- т.е. тот же файловый дескриптор, что иstdout

В результате оба stderrи stdoutбудут перенаправлены на file.

В bashболее простом нестандартном (и поэтому я не рекомендую это из-за переносимости) синтаксисе cmd &> fileделает то же самое.

Стивен Харрис
источник
Здорово спасибо Другая проблема может быть /dev/tty, но, надеюсь, это случается не слишком часто (если вообще).
MatthewRock
5
Если у вас есть atкоманда на вашем компьютере и у вас есть права на ее использование, вы можете запустить команду через at now. Смотрите man-страницу для деталей. Это запустит команду через механизм пакетного процесса, и у процесса никогда не будет tty для записи. Но, в общем, я бы не беспокоился об этом крайнем случае. Обычно используются только процессы, требующие взаимодействия и намеренно нуждающиеся в отображении информации пользователям, несмотря на перенаправление /dev/tty.
Стивен Харрис
был там, сделал это
davidbak
10

Есть две проблемы.

Первое, что порядок имеет значение, второе /dev/tty.

Давайте использовать этот сценарий в качестве примера сценария, из которого мы хотим получить выходные данные:

test.sh:

#!/bin/bash

echo dada
echo edada 1>&2
echo ttdada >/dev/tty

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

./testmyscript.sh 2>&1 >/dev/null:

edada
ttdada

Поскольку порядок оценки слева направо, мы сначала получаем «перенаправление stderrтуда, где stdoutвыводится (то есть вывод на консоль)». Затем мы получаем «перенаправление stdoutна /dev/null. Мы в конечном итоге в такой ситуации:

stdout-> /dev/null stderr-> консоль

Итак, мы правильно поняли:

./testmyscript.sh >/dev/null 2>&1

И мы получаем:

ttdada,

Теперь мы делаем «Redirect stdoutto /dev/null», а затем «Redirect stderr туда, куда указывает stdout» (так, /dev/null). Ура!

Тем не менее, у нас все еще есть проблема; Программа печатает в /dev/tty. Сейчас я не знаю, как исправить такое поведение, поэтому вам, скорее всего, это понадобится script, но, надеюсь, такое поведение не будет происходить слишком часто.

MatthewRock
источник