В программировании оболочки Unix / Linux: разница между> и> & - PullRequest
0 голосов
/ 01 октября 2011
int main(void)
{

  char buf[] = "standard err, output.\n";

  printf("standard output.\n");

  if (write(STDERR_FILENO,buf, 22) != 22)
      printf("write err!\n");

  exit(0);
}

Компиляция с использованием:

gcc -Wall text.c

Затем выполняется в оболочке:

  1. ./a.out > outfile 2 >& 1

    Результат : outfile´sсодержимое:

    standard err, output.                
    standard output.
    
  2. ./a.out 2 >& 1 >outfile

    Результат:

    Эта первая печать на терминале: standard err, output.
    иСодержание файла: standard output.

Вопросы:

  • Я хочу спросить разницу между 2 >& fd и 2 > file.
    Они все равны функции dup ()?

  • Другой вопрос: почему содержимое outfile:

     standard err, output. 
     standard output.
    

    Я ожидал, что содержимое outfileбыть:

     standard output. 
     standard err, output 
    

Ответы [ 4 ]

3 голосов
/ 01 октября 2011

На самом деле, в bash >& очень похож на dup2. То есть дескриптор файла, к которому он применяется, будет ссылаться на тот же файл, что и дескриптор справа. Итак:

$ ./a.out > outfile 2>& 1

Он перенаправит stdout (1) в файл outfile и после этого dup2 stderr (2) будет ссылаться на тот же файл, что и stdout (1). То есть и stdout, и stderr перенаправляются в файл.

$ ./a.out 2>& 1 >outfile

Он перенаправит stderr (2) для ссылки на тот же файл, что и stdout (1), то есть консоль, и после этого перенаправит stdout (1) для ссылки на файл outfile. То есть stderr будет выводить на консоль, а stdout - в файл.

И это именно то, что вы получаете.

1 голос
/ 01 октября 2011

Смешивание парадигм


Хотя есть причины делать все это преднамеренно, в процессе обучения, вероятно, будет непросто смешивать операции над тем, что я мог бы назвать «границами домена».

Буферизированный или небуферизованный ввод / вывод

printf() буферизован, write() - это прямой системный вызов.Запись происходит немедленно, несмотря ни на что, printf будет (обычно) буферизован построчно, когда вывод является терминалом, и блок-блоком, когда вывод - реальный файл.В случае вывода файла (перенаправление) ваш фактический вывод printf произойдет только тогда, когда вы вернетесь из main () или каким-либо другим способом вызова exit (3), если только вы не напечатаете целую кучу вещей.

Historiccsh redirection vs bash redirection

Теперь забытый (но обычно по-прежнему установленный по умолчанию) csh, который Билл Джой написал в UCB, в то время как у аспиранта было несколько замечательных функций, которые были импортированы в раковины кухонных раковин, которыеИЛИ - вместе каждая функция оболочки когда-либо думала.Да, я говорю о Bash здесь.Таким образом, в csh способ перенаправления как стандартного вывода, так и стандартной ошибки состоял в том, чтобы просто сказать cmd> & file , который был действительно более цивилизованным, чем подход «мешок инструментов», который обеспечивала «официальная» оболочка Bourne.,Но синтаксис Bourne имел свои преимущества в другом месте и в любом случае сохранился как доминирующая парадигма.

Но «родные» функции перенаправления bash довольно сложны, и я бы не стал обобщать их в SO-ответе,хотя другие, кажется, сделали хорошее начало.В любом случае вы используете реальное перенаправление bash в одном тесте и синтаксис legacy-csh, который bash также поддерживает в другом тесте, и с программой, которая сама смешивает парадигмы.Основная проблема с точки зрения оболочки заключается в том, что порядок перенаправления довольно важен в синтаксисе в стиле bash, в то время как синтаксис в стиле csh просто определяет конечный результат.

0 голосов
/ 01 октября 2011

Здесь есть несколько слабо связанных проблем.

Комментарий стиля: я рекомендую использовать 2>&1 без пробелов.Я даже не знал, что размеченная версия работает (я подозреваю, что она не работала в оболочке Bourne в середине 80-х), и сжатая версия - это ортодоксальный способ ее записи.

Файл-дескриптор ввода / вывода нотации не все доступны в оболочке C и производных;они доступны в оболочке Bourne и ее производных (оболочка Korn, оболочка POSIX, Bash, ...).

Разница между >file или 2>file и 2>&1 заключается в том, что должна делать оболочка,Первые два упорядочивают вывод, записанный в дескриптор файла (1 в первом случае, иначе стандартный вывод; 2 во втором случае, стандартная ошибка), чтобы перейти к названному файлу.Это означает, что все, что записано программой в стандартный вывод, вместо этого отправляется в файл.Третья запись обеспечивает 2 (стандартная ошибка) для перехода к тому же дескриптору файла, что и 1 (стандартный вывод);все, что записано в стандартную ошибку, отправляется в тот же файл, что и стандартный вывод.Это тривиально реализовано с использованием dup2().Однако стандартный поток ошибок в программе будет иметь свой собственный буфер, а стандартный поток вывода в программе будет иметь свой собственный буфер, поэтому чередование выходных данных не является полностью определенным, если выходные данные передаются в файл.

Вы запускаете команду двумя разными способами и (что неудивительно) получают два разных результата.

  1. ./a.out > outfile 2>&1

    Перенаправления ввода / вывода обрабатываются слева направо,Первый отправляет стандартный вывод на outfile.Вторая отправляет стандартную ошибку в то же место, что и стандартный вывод, поэтому она также переходит к outfile.

  2. ./a.out 2>&1 >outfile

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

Программа использует функцию printf() и системный вызов write().Когда используется функция printf(), она буферизует свой вывод.Если выходные данные отправляются на терминал, то это обычно «буферизованная строка», поэтому выходные данные появляются, когда в буфер добавляется новая строка.Однако, когда вывод идет в файл, он «полностью буферизуется» и вывод не появляется, пока поток файла не будет очищен или закрыт или буфер не заполнится.Обратите внимание, что stderr не полностью буферизован, поэтому записанные в него выходные данные появляются немедленно.

Если вы запустите свою программу без перенаправления ввода-вывода, вы увидите:

standard output. 
standard err, output

Byнапротив, системный вызов write() немедленно передает данные в дескриптор выходного файла.В примере вы пишете со стандартной ошибкой, и то, что вы пишете, появится сразу.То же самое произошло бы, если бы вы использовали fprintf(stderr, ...).Однако предположим, что вы изменили программу для записи в STDOUT_FILENO;затем, когда выходные данные находятся в файле, выходные данные будут отображаться в следующем порядке:

standard err, output
standard output. 

, поскольку write() небуферизован, а printf() буферизован.

0 голосов
/ 01 октября 2011

Часть 2>&1 заставляет оболочку делать что-то подобное:

dup2(1, 2);

Это делает fd 2 "копией" fd 1.

2> file интерпретируется как

fd = open(file, ...);
dup2(fd, 2);

, который открывает файл и помещает дескриптор файла в слот 2.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...