С последовательностью команд по конвейеру, например:

$ cat afile | somecommand | tee afile

afile читается (кошкой) и пишется (тройником). Вопрос в том, предположим, что размер файла составляет по крайней мере несколько мегабайт (или достаточно большой, чтобы ОС не полностью буферизировала его). Будут ли затронуты более поздние байты в файле, читаемом cat, когда tee начнет запись в файл?

Другими словами, возможно ли когда-нибудь переписать файл, прежде чем cat закончит с ним?

2 ответа2

1

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

Это потому, что операции записи происходят одновременно с операциями чтения. Обычно это приводит к преждевременному усечению файла. В прошлом это удивляло людей, привыкших к конвейерам DOS, где операционная система сериализировала процессы посредством скрытых временных файлов (или их морального эквивалента)

Решения в основном включают использование временных файлов и переименование их по завершении.

somecommand < infile | tee tempfile; mv tempfile infile

Очевидно, что это может привести к другим проблемам.

Некоторые утилиты (awk, perl и т.д.) Обрабатывают это для вас, если вы даете им соответствующие параметры командной строки.

perl -i -e 'somecommands' infile ... 

Обратите внимание, что проблема, которую вы испытываете, не имеет ничего общего с cat . В моем примере я избегал ненужного использования кошки, частично чтобы прояснить это, частично из-за традиции.

0

Несколько экспериментов для собственного удовольствия (и для всех, кто интересуется этим вопросом). Я сгенерировал afile размером 100 МБ, используя /dev /urandom, и попробовал несколько конвейеров и перенаправлений, используя один и тот же файл.

Большинство следующих команд не имеют логического смысла (поскольку "успешный" результат должен сохранить файл без изменений), и следует также отметить, что если для ввода и вывода указаны разные файлы, все команды приводят к полной копии ввода.

Вот несколько результатов:

$ cat <afile >afile

Определение: cat stdin из afile и перенаправить в afile. Результат: файл обрезан (0 байт)

$ cat afile|cat >afile

Определение: кошачий файл и труба на другую кошку, перенаправленную на файл. Результат: файл обрезан (0 байт)

$ tee afile <afile >/dev/null

Определение: tee stdin из afile и запись в afile (и перенаправление stdout в /dev /null). Результат: файл обрезан (0 байт)

$ cat afile|tee afile >/dev/null

Определение: cat afile и pipe stdout to tee (и перенаправить stdout tee в /dev /null). Результат: файл уменьшен до 128 КБ

Последняя запись наиболее ясно показывает проблему: cat может только буферизовать 128 КБ и направить ее в тэ до того, как файл исчезнет. Так что, если ваш файл небольшой, вам может повезти, но лучше прислушаться к ответу и всегда разделять входные и выходные файлы.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .