Чому повідомлення про помилки перенаправлення '>' від gcc?


9

Наступну програму я зберігав у new.c

int main() 
{ 
    a;
    return 0; 
}

Він повертає повідомлення про помилку. Я хочу надіслати це повідомлення у файл. Тому я використав таку команду

gcc new.c > temp.txt

Але все ж я отримував вихід на терміналі. Я використовую Ubuntu 13.04. Як я можу змусити його працювати?


Відповіді:


16

Коли ви компілюєте програму gcc, випускаються різні види: до stdoutі stderr. Зазвичай >заповіт направляє stdoutфайл у файл (наприклад, результат а printf("hello world\n");надсилається до stdout). Однак stderrпродовжує надсилатись на екран, оскільки передбачається, що це "щось виняткове, про що вам потрібно розповісти".

Існує спосіб перенаправити stderr у файл - ви робите це за допомогою наступної (не дуже інтуїтивної) команди:

gcc new.c &> myFile

де &>"скоротити скорочення" для "перенаправити все". Як вказував @CharlesDuffy, формою, сумісною з POSIX, є

gcc new.c > myFile 2>&1

Це означає "компілювати" new.c "і відправляти stdoutв myFile. І відправляти stderr(2) на те саме місце, що і stdout( &1=" те саме місце, що і stdout ").

Більш детальну інформацію про різні переадресації ви знайдете на 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

на консолі ваш висновок з’явиться на екрані.


2
mywiki.wooledge.org/BashFAQ/055 - це, мабуть, краще введення до перенаправлення. Крім того, слід запровадити POSIX-сумісну форму ( >myFile 2>&1), а також розширення bash ( &>).
Чарльз Даффі

@CharlesDuffy - обидва дуже хороші моменти. Я включу їх у свою відповідь для повноти.
Флоріс

11

Оскільки >переадресація виконує лише stdout, а помилки записуються 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.


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 каже: "Відновіть Моніку"
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.