Почему '>' не перенаправляет сообщения об ошибках от gcc?

9

Я сохранил следующую программу в new.c

int main() 
{ 
    a;
    return 0; 
}

Возвращает сообщение об ошибке. Я хочу отправить это сообщение в файл. Поэтому я использовал следующую команду

gcc new.c > temp.txt

Но все же я получал вывод на терминал. Я использую Ubuntu 13.04. Как я могу заставить это работать?

Alex
источник
Для справки см. Также Каковы операторы управления и перенаправления оболочки?
G-Man говорит: «Восстановите Монику»

Ответы:

16

Когда вы компилируете программу gcc, есть разные виды вывода: to stdoutи stderr. Как правило, >будет направлять stdoutпоток в файл (например, результат printf("hello world\n");посылается stdout). Тем не менее, он stderrпродолжает отправляться на экран, поскольку предполагается, что это «нечто исключительное, о чем вам нужно рассказать».

Существует способ перенаправить stderr в файл - вы делаете это с помощью следующей (не очень интуитивно понятной) команды:

gcc new.c &> myFile

где &>"стенограмма bash" для "перенаправить все". Как было отмечено @CharlesDuffy, POSIX-совместимая форма

gcc new.c > myFile 2>&1

Это означает «скомпилировать« new.c »и отправить stdoutв myFile. И отправить stderr(2) в то же место, что и stdout( &1=« в том же месте, что и стандартный вывод »).

Более подробную информацию о различных перенаправлениях вы найдете на http://tldp.org/HOWTO/Bash-Prog-Intro-HOWTO-3.html и http://mywiki.wooledge.org/BashFAQ/055.

Кстати, если вы хотите отправить что-то из вашей программы специально stderr, вы можете сделать это с помощью следующего

fprintf(stderr, "hello world - this is urgent.\n");

Если вы включите это в программу, запустите программу и отправите «нормальный» вывод в файл, он все равно появится на консоли. Так что если вы скомпилируете вышеперечисленное в исполняемый файл urgent, наберите

./urgent > /dev/null

на консоли ваш вывод появится на экране.

Floris
источник
2
mywiki.wooledge.org/BashFAQ/055 , вероятно, является лучшим введением в перенаправление. Кроме того, действительно следует представить POSIX-совместимую форму ( >myFile 2>&1), а также расширение bash ( &>).
Чарльз Даффи
@CharlesDuffy - оба очень хорошие моменты. Я включу их в свой ответ для полноты.
Флорис
11

Поскольку >перенаправляет только стандартный вывод, и ошибки записываются stderr, вам нужно использовать одно из следующих:

gcc new.c &> temp.txt ## redirect both stdout and stderr using bash or zsh only

...или...

gcc new.c >temp.txt 2>&1 ## redirect both stdout and stderr in any POSIX shell

&>расширение BASH, которое перенаправляет stdoutи stderrв файл; в противном случае, самый простой подход к первому перенаправлять стандартный вывод ( >temp.txt), а затем сделать STDERR (FD 2) копия уже перенаправлены дескриптора файла на стандартный вывод (FD 1), например , так: 2>&1.

NIMS
источник
4

Как уже говорили другие, linux предоставляет два разных потока вывода:

stdout , или «стандартный вывод» - это то, куда идет весь обычный вывод.
              Вы можете ссылаться на него, используя файловый дескриптор 1.

stderr , или «стандартная ошибка» - это отдельный поток для внеполосной информации.
              Вы можете ссылаться на него, используя файловый дескриптор 2.

Почему два разных выходных потока? Рассмотрим конвейер воображаемых команд:

 decrypt $MY_FILE | grep "secret" | sort > secrets.txt

Теперь представьте, что decryptкоманда не работает и генерирует сообщение об ошибке. Если бы он отправил это сообщение stdout, он бы отправил в канал, и если бы у него не было слова «секрет», вы бы его никогда не увидели. Таким образом, вы получите пустой выходной файл, не зная, что пошло не так.

Однако, поскольку канал захватывает только stdout, decryptкоманда может отправлять свои ошибки туда stderr, где они будут отображаться на консоли.

Вы можете перенаправить stdoutи stderr, вместе или независимо:

# Send errors to "errors.txt" and output to "secrets.txt"
# The following two lines are equivalent, as ">" means "1>"
decrypt $MY_FILE 2> errors.txt > secrets.txt
decrypt $MY_FILE 2> errors.txt 1> secrets.txt

Вы можете перенаправить ошибки stdoutи обработать их, как если бы они были обычным выводом:

# The operation "2>&1" means "redirect file descriptor 2 to file
# descriptor 1. So this sends all output from stderr to stdout.
# Note that the order of redirection is important.
decrypt $MY_FILE > errors.txt 2>&1 

# This may be confusing.  It will store the normal output in a file
# and send error messages to stdout, where they'll be captured by 
# the pipe and then sorted.
decrypt $MY_FILE 2>&1 > output.txt | sort

Вы также можете использовать сокращенную запись для перенаправления как stdout, так и stderr в один и тот же файл:

decrypt $MY_FILE &> output.txt

И, наконец, >оператор сначала обрезает свой выходной файл перед записью в него. Если вместо этого вы хотите добавить данные в существующий файл, используйте >>оператор:

decrypt $MY_FILE 2>> more_errors.txt >> more_secrets.txt
decrypt $MY_FILE >> more_output.txt 2>&1
Адам Лисс
источник
1
Две придирки: (1) Использование расширений параметров без кавычек ( $FOO) является распространенным источником ошибок, и демонстрация его в примерах не так уж велика. (2) Использование имен переменных в верхнем регистре является основной причиной конфликтов пространства имен между средой и встроенными переменными (прописными буквами по соглашению) и локальными переменными (строчными буквами по соглашению). (3) Поощрение людей к повторному использованию >>(которое открывает файл каждый раз, когда он используется в команде) вместо того, чтобы открывать файл один раз и оставлять дескриптор файла открытым для использования несколькими командами, приводит к неэффективному коду.
Чарльз Даффи
... по последнему пункту, сравните с: exec 4>secrets; echo "this is a secret" >&4; echo "this is another secret" >&4
Чарльз Даффи
+1 Спасибо за честность, @CharlesDuffy. Все хорошие моменты. Я намеренно опущен execдля простоты, хотя на практике это, как правило, лучшая стратегия.
Кроме того, может быть свернуто до или (где должны быть пробелы до и после , и a до ). command₁ > output_file ; command₂ >> the_same_output_file( command₁ ; command₂ )  > output_file{ command₁ ; command₂ ;  }  > output_file{;}
G-Man говорит: «Восстановите Монику»