Чому поведінка команди `1> file.txt 2> file.txt` відрізняється від команди` команда 1> file.txt 2> & 1`?


20

Коли ви хочете перенаправити як stdout, так і stderr в один і той же файл, ви можете зробити це за допомогою command 1>file.txt 2>&1, або command &>file.txt. Але чому поведінка command 1>file.txt 2>file.txtвідрізняється від зазначених вище двох команд?

Далі йде команда перевірки.

$ cat redirect.sh
#!/bin/bash

{ echo -e "output\noutput" && echo -e "error" 1>&2; } 1>file.txt 2>&1
{ echo -e "output\noutput" && echo -e "error" 1>&2; } 1>file1.txt 2>file1.txt
{ echo -e "error" 1>&2 && echo -e "output\noutput"; } 1>file2.txt 2>file2.txt
{ echo -e "output" && echo -e "error\nerror" 1>&2; } 1>file3.txt 2>file3.txt
{ echo -e "error\nerror" 1>&2 && echo -e "output"; } 1>file4.txt 2>file4.txt

$ ./redirect.sh

$ echo "---file.txt---"; cat file.txt;\
echo "---file1.txt---"; cat file1.txt; \
echo "---file2.txt---"; cat file2.txt; \
echo "---file3.txt---"; cat file3.txt; \
echo "---file4.txt----"; cat file4.txt;
 ---file.txt---
output
output
error
---file1.txt---
error

output
---file2.txt---
output
output
---file3.txt---
error
error
---file4.txt----
output
rror

Що стосується результатів, то виглядає так, що другий рядок ехо замінює першу ехо-рядок під час запуску command 1>file.txt 2>file.txt, але я не знаю, чому це буде. (Чи є десь посилання?)

Відповіді:


43

Вам потрібно знати дві речі:

  • Дескриптор відкритого файлу, відомий стороні в режимі програми процесу, посилається на внутрішній об'єкт ядра, відомий як опис файлу , який є примірником відкритого файлу. На файл може бути кілька описів файлів, а також декілька дескрипторів файлів, що надають опис файлу.
  • Поточна позиція файлу є атрибутом опису файлу . Отже, якщо кілька дескрипторів файлів відображаються в одному описі файлу, всі вони мають одне і те ж поточне положення файлу, і зміна положення файлу, прийняте за допомогою одного такого дескриптора файлу, впливає на всі інші такі дескриптори файлів.

    Такі зміни введені в дію процеси , які закликають до read()/ readv(), write()/ writev(), lseek()і тому подібні системні виклики. У echoкомандних викликів write()/ writev()звичайно.

Отже, що відбувається:

  • command 1>file.txt 2>&1створює лише один опис файлу, оскільки оболонка відкриває файл лише один раз. Оболонка робить, як стандартний вихідний, так і стандартний дескриптори файлів помилок відображає один опис цього файлу. Він дублює стандартний вихід на стандартну помилку. Таким чином, запис через будь-який дескриптор файлу перемістить загальну поточну позицію файлу: кожне записування йде після попереднього запису загального опису файлу. І як ви бачите, результати echoкоманд не перезаписуйте один одного.
  • command 1>file.txt 2>file.txtстворює два описи файлів, оскільки оболонка відкриває один і той же файл двічі у відповідь на два явних перенаправлення. Стандартні вихідні та стандартні дескриптори файлів помилок відображають два різних описи файлів, які згодом відображають один і той же файл. Опис двох файлів має цілком незалежні поточні позиції файлів, і кожне записування негайно переходить до попереднього запису в одному описі файлу. І як ви бачите, результат полягає в тому, що те, що написано через один, може перезаписати те, що написано через інший, різними способами залежно від того, в якому порядку ви виконуєте запис.

Подальше читання


1
Має бути відкритий опис файлу, а не опис файлу . Це більше про запис про те, як файл відкрито більше, ніж сам файл. Ось така термінологія, яка використовується принаймні в документах POSIX, Linux, Solaris та GNU.
Стефан Шазелас

16

Використання >повідомляє йому перезаписати файл. Оскільки у вас є stdout та stderr запис у файл у двох різних операціях, остання для запису замінить першу.

Ви можете зробити:

command 1>>file.txt 2>>file.txt

або

command &>file.txt Тільки bash v4 і вище.

>> каже йому додати файл, щоб він не замінив вихід попередніх операцій.

&> це просто простіший спосіб писати 2>&1


2
чому ls 1>&0і ls 0>&0як і раніше показує вихід ls?
Івен

Я здивований, що використовуючи >>твори. Чому це не має проблеми з двома описами файлів з незалежними зрушеннями? @JdeBP, ти знаєш? Я вважав, що відкриття файлу в режимі додавання еквівалентно відкриттю в режимі запису, пошуку до остаточної позиції, а потім забороненню подальших пошуків.
JoL

4
@jlmg: Файли в додатковому режимі можна шукати, але кожне записування є префіксом, маючи на увазі прагнення до кінця. Чи є це мається на увазі прагнення атомним, мені менш зрозуміло.
Кевін

1
Це повністю залежить від подальшого питання. Такі, які пов'язані з цим, вказують на те, що відповідь є неповною. І навряд чи люди шукатимуть наступні запитання, не бажаючи також знати повну відповідь. Отже, цілком ймовірно, що наступні запитання матимуть відповіді, що дублюють інформацію, і, таким чином, закриваються як копії.
trlkly

1
@Kevin, у файлових системах, повністю сумісних з POSIX, неявна спроба O_APPEND є атомною. Однак, не кожна файлова система належним чином реалізує відповідну семантику - наприклад, NFS (принаймні v3 та попередній - мені не зрозуміло на v4) не має відповідної підтримки, включеної в провідний протокол, тому сервер має жоден спосіб дізнатися, чи відкрив клієнт файл із O_APPEND.
Чарльз Даффі
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.