Вопрос или проблема
Предположим, у нас есть папка с двумя файлами:
file_empty
, который ничего не содержитfile_in
, содержащий только одну строку: “что-то”
Смотрите результат следующих примеров:
(echo "test" > file_test; < file_empty cat) > file_out
в результате file_out
будет пустым.
(echo "test" > file_test; < file_in cat) > file_test
в результате file_test
будет содержать “что-то”.
Наконец,
(echo "test" > file_test; < file_empty cat) > file_test
в результате file_test
будет содержать “test”.
В последнем примере я ожидал, что file_test
будет пустым,
как в первом примере.
Не могли бы вы объяснить мне, почему он будет содержать “test”?
Две важные вещи:
- В ваших примерах
echo
всегда выполняется передcat
. - Каждое перенаправление
> file_test
создает независимое открытое описание файла.
Ваш первый пример прост: echo
записывает в file_test
, затем cat
копирует содержимое file_empty
в file_out
.
Во втором и третьем примерах file_test
открывается и усекается дважды. Сначала “внешний” > file_test
открывает и усекает файл, затем другое > file_test
открывает и усекает файл для echo
; только потом запускается echo
, и наконец запускается cat
.
В результате echo
записывает в file_test
с начала файла, а cat
записывает в file_test
независимо с начала файла. Эти два инструмента не разделяют открытое описание файла, поэтому действие записи echo
не перемещает позицию в файле для cat
. Последний инструмент (перезаписывает) файл с начала, а не с места, где echo
завершился.
В частности, во втором примере echo
записывает test
в файл, затем cat
помещает что-то
в файл с его начала, перезаписывая test
.
В третьем примере echo
записывает test
в файл, затем cat
помещает пустую строку в файл с его начала, не перезаписывая ничего (поскольку размер пустой строки равен нулю байт).
Чтобы лучше понять, что происходит, рассмотрим это:
(echo "1234567890интересно" > file_test; < file_in cat) > file_test
Сначала echo
записывает 12…
в файл, затем cat
помещает что-то
в файл с его начала, перезаписывая 12…89
на что-то
и 0
на завершающий символ новой строки из file_in
(я предполагаю, что строка, в которой написано что-то
, правильно завершается в file_in
). Содержимое file_test
теперь:
что-то
интересно
(с завершающим символом новой строки после интересно
, добавленным echo
в первую очередь).
Иначе обстоит дело с
(echo "1234567890интересно" > file_test; < file_in cat) >> file_test
потому что >>
по сути означает “всегда перемещаться в конец файла”. На этот раз cat
записывает с того места, где echo
завершился, потому что именно здесь заканчивается файл. Попробуйте. Результат будет:
1234567890интересно
что-то
(с завершающим символом новой строки из file_in
).
Также, если два инструмента действительно разделяют открытое описание файла (созданное с помощью >
), тогда echo
будет перемещать позицию в файле для cat
:
(echo "1234567890интересно"; < file_in cat) > file_test
Результат снова будет
1234567890интересно
что-то
(с завершающим символом новой строки из file_in
).
Ответ или решение
Объяснение работы операторов >
и <
в bash с использованием скобок
В мире Linux и bash-подобных оболочек управление вводом и выводом является важной концепцией, позволяющей управлять данными, которые передаются между процессами и файлами. В данном контексте мы рассмотрим работу операторов перенаправления >
(вывод) и <
(ввод) в сочетании с подстановочными выражениями, которые заключены в скобки.
Описание Примера
Вы рассматриваете два файла:
file_empty
, который не содержит никаких данных.file_in
, содержащий одну строку — "something".
Рассмотрим несколько примеров использования операторов перенаправления и разберем их результаты.
Пример 1
(echo "test" > file_test; < file_empty cat) > file_out
Результат: file_out
остается пустым.
Объяснение:
- Команда
echo "test"
создает файлfile_test
и записывает в него строку "test". - Команда
cat
, которая принимает ввод изfile_empty
, выполняется, но так как файл пустой, вfile_out
ничего не записывается. - Поскольку каждый оператор
>
создает новую файловую дескриптору, операции вывода не влияют друг на друга.
Пример 2
(echo "test" > file_test; < file_in cat) > file_test
Результат: file_test
теперь содержит "something".
Объяснение:
- В первой части выражения команда
echo
запускается и открывает файлfile_test
, в который записывается "test". Однако в этот момент он уже открыт и может быть обрезан. - Затем команда
cat
, которая читает изfile_in
, открываетfile_test
и перезаписывает его содержимое, начиная с начала файла, чем фактически заменяет "test" на "something".
Пример 3
(echo "test" > file_test; < file_empty cat) > file_test
Результат: file_test
будет содержать "test".
Объяснение:
- Сначала команда
echo
записывает "test" вfile_test
. - Затем команда
cat
, которая читает изfile_empty
, открывает файлfile_test
для записи и не находит ничего для записи, следовательно, не дорожит содержимым из-за того, что вfile_empty
нет данных. Это приводит к тому, что существующее содержимое остаётся неизменным.
Ключевые Пункты в Работе с Операторами
-
Временные файловые дескрипторы: Каждый раз, когда вы используете
>
, создается новый временный файловый дескриптор. Это означает, что операции, выполняемые в рамках одной группы команд, могут не взаимодействовать так, как это может ожидаться. -
Порядок выполнения: Ваша логика может ошибаться при ожидании, что записи в файл будут происходить последовательно. Однако, поскольку команды внутри скобок работают одновременно, важно понимать, что вывод разных команд может перезаписывать файл независимо друг от друга.
-
Текущая позиция в файле: Позиция записи в файл при использовании
>
всегда начинается с начала, в отличие от операций с использованием>>
, которые добавляют данные в конец файла. -
Функции
cat
иecho
: Обе эти команды имеют свою специфику работы с файлами, что также влияет на результат выполнения.
Заключение
Понимание работы с операторами перенаправления в bash критично для правильного управления вводом и выводом данных. На примерах выше мы видели, как порядок выполнения команд и создание отдельных дескрипторов файлов может влиять на результат. Запоминайте эти ключевые моменты, чтобы избежать неожиданных результатов в процессе работы с файловыми операциями в bash.