ТЛ; др
По >>
сути, «всегда ищет конец файла», в то время как >
поддерживает указатель на последнее записанное местоположение.
Полный ответ
(Примечание: все мои тесты сделаны на Debian GNU / Linux 9).
Еще одно отличие
Нет, они не эквивалентны. Есть еще одно отличие. Он может проявляться независимо от того, существовал ли ранее целевой файл или нет.
Чтобы наблюдать это, запустите процесс, который генерирует данные и перенаправьте в файл с помощью >
или >>
(например pv -L 10k /dev/urandom > blob
). Пусть он запустится и измените размер файла (например, с помощью truncate
). Вы увидите, что >
сохраняет свое (растущее) смещение, при этом >>
всегда добавляясь к концу.
- Если вы урежете файл до меньшего размера (это может быть нулевой размер)
>
не волнует, он напишет с желаемым смещением, как будто ничего не произошло; сразу после того, как усечение смещения выходит за пределы конца файла, это приведет к тому, что файл вернется к своему старому размеру и будет расти дальше, пропущенные данные будут заполнены нулями (разреженным, если это возможно);
>>
добавится в новый конец, файл вырастет из усеченного размера.
- Если вы увеличите файл
>
не волнует, он напишет с желаемым смещением, как будто ничего не произошло; просто после изменения размера смещение находится где-то внутри файла, это приведет к тому, что файл на некоторое время перестанет расти, пока смещение не достигнет нового конца, тогда файл будет расти нормально;
>>
добавится в новый конец, файл увеличится в увеличенном размере.
Другой пример - добавить (с отдельным >>
) что-то дополнительное, когда запущен процесс генерации данных и запись в файл. Это похоже на увеличение файла.
- Процесс генерации с
>
запишет с желаемым смещением и перезапишет дополнительные данные в конце концов.
- Процесс генерации с
>>
пропустит новые данные и добавит их после (может возникнуть условие гонки, два потока могут быть чередованы, но данные не должны быть перезаписаны).
пример
Имеет ли это значение на практике? Есть такой вопрос :
Я запускаю процесс, который выдает большой объем вывода на стандартный вывод. Отправка всего этого в файл [...] Могу ли я использовать какую-нибудь программу ротации журналов?
Этот ответ говорит, что решение logrotate
с copytruncate
опцией, которая действует так:
Усечение исходного файла журнала на месте после создания копии, вместо перемещения старого файла журнала и, при необходимости, создания нового.
Согласно тому, что я написал выше, перенаправление с помощью >
сделает усеченный журнал большим в кратчайшие сроки. Разреженность спасет день, не нужно тратить значительное дисковое пространство. Тем не менее, в каждом последующем журнале будет все больше и больше ведущих нулей, которые совершенно не нужны.
Но если logrotate
создавать копии без сохранения разреженности, этим ведущим нулям потребуется все больше и больше дискового пространства при каждом создании копии. Я не исследовал поведение инструмента, оно может быть достаточно умным с разреженностью или сжатием на лету (если сжатие включено). Тем не менее, нули могут только создавать проблемы или быть нейтральными в лучшем случае; ничего хорошего в них нет.
В этом случае использование >>
вместо >
значительно лучше, даже если целевой файл еще не создан.
Представление
Как мы видим, два оператора действуют по-разному не только в начале, но и позже. Это может вызвать некоторую (незначительную?) Разницу в производительности. Пока у меня нет значимых результатов тестов, чтобы поддержать или опровергнуть их, но я думаю, что вы не должны автоматически предполагать, что их производительность в целом одинакова.
>>
сути, это «всегда искать в конце файла», в то время как>
поддерживает указатель на последнее записанное местоположение. Кажется, что в их работе может быть и>>
используетO_APPEND
флаг дляopen()
. И на самом деле,>
используетO_TRUNC
, а>>
не делает. КомбинацияO_TRUNC | O_APPEND
также была бы возможна, язык оболочки просто не предоставляет эту функцию.O_APPEND
сlseek()
перед тем, как каждый изwrite()
них будет отличаться, потребует дополнительных системных вызовов. (И, конечно, это не сработает, посколькуwrite()
между ними может