Разница между cat и '>', чтобы обнулить файл

Являются ли эти две команды отличными от того, как они обходят нулевые файлы? Является ли последний более коротким способом сделать первое? Что происходит за кулисами?

И то и другое

$ cat /dev/null > file.txt $ > file.txt 

Уступать

 -rw-r--r-- 1 user wheel 0 May 18 10:33 file.txt 

cat /dev/null > file.txt – бесполезное использование cat .

В принципе cat /dev/null просто приводит к тому, что cat ничего не выводит. Да, это работает, но многие недовольны, потому что это приводит к вызову внешнего процесса, который не нужен.
Это одна из тех вещей, которая распространена просто потому, что она распространена.

Использование just > file.txt будет работать на большинстве оболочек, но оно не полностью переносимо. Если вы хотите полностью переносить, то это хорошие альтернативы:

 true > file.txt : > file.txt 

Оба : и true выводят никаких данных, а также встроенные оболочки (в то время как cat – внешняя утилита), таким образом, они более легкие и более «правильные».

Обновить:

Как упоминал в своем комментарии tylerl, существует также >| file.txt Синтаксис >| file.txt .

Большинство оболочек имеют параметр, который предотвратит их обрезку существующего файла через > . Вы должны использовать >| вместо. Это делается для предотвращения человеческой ошибки, когда вы действительно хотите добавить с помощью >> . Вы можете включить поведение с помощью set -C .

Поэтому с этим, я думаю, самый простой, самый правильный и переносимый метод обрезания файла:

 :>| file.txt 

Что касается переносимости:

  Bourne POSIX zsh csh/tcsh rc/es fish > file YYN(1) N(1) NN : > file N/Y(2) Y(3) YY(4) N(5) N(5) true > file Y(5) YYY(5) Y(5) Y(5) cat /dev/null > file Y(5) YY(5) Y(5) Y(5) Y(5) eval > file Y(3,8) Y(3) YY(6) YY cp /dev/null file (7) Y(5) YY(5) Y(5) Y(5) Y(5) printf '' > file Y(5) YYY(5) Y(5) Y 

Заметки:

  1. кроме эмуляции sh или ksh , для перенаправления без команды, в zsh, предполагается команда по умолчанию (пейджер только для перенаправления stdin, cat противном случае), который может быть настроен с помощью переменных NULLCMD и READNULLCMD. Это вызвано аналогичной особенностью в (t)csh
  2. Первоначально перенаправления не выполнялись для : в UnixV7 как : интерпретировалось на полпути между лидером комментария и нулевой командой. Позже они были и, как и для всех встроенных, если перенаправление не удалось, что выходит из оболочки.
  3. : и eval – это специальные встроенные модули, если перенаправление не выполняется, что выходит из оболочки ( bash делает это только в режиме POSIX).
  4. Интересно, что в (t)csh это определяет нулевую метку (для goto ), поэтому goto '' там будет ветвь. Если перенаправление выходит из строя, выход из оболочки.
  5. Если / если соответствующая команда доступна в $PATH ( : обычно это не так: true , cat , cp и printf обычно (POSIX требует их)).
  6. Если перенаправление выходит из строя, выход из оболочки.
  7. Если file является символической ссылкой на несуществующий файл, некоторые реализации cp такие как GNU, откажутся его создать.
  8. Исходные версии оболочки Bourne не поддерживают перенаправление встроенных функций, хотя

С точки зрения удобочитаемости:

(этот раздел очень субъективен)

  • > file . Это > слишком похоже на подсказку или комментарий. Также вопрос, который я задам при чтении (и большинство оболочек будет жаловаться на то же самое), является то, что именно вы перенаправляете? ,
  • : > file . : известен как команда no-op. Так что сразу читается как создание пустого файла. Однако, опять же, это : можно легко пропустить и / или увидеть как подсказку.
  • true > file : что делать с перенаправлением или содержимым файла? Что здесь имеется в виду? это первое, что приходит мне на ум, когда я это читаю.
  • cat /dev/null > file . Включить /dev/null в file ? cat часто рассматривается как команда для сброса содержимого файла, что все еще имеет смысл: выгрузить содержимое пустого файла в file , немного похоже на запутанный способ сказать cp /dev/null file но все еще понятный.
  • cp /dev/null file . Копирует содержимое пустого файла в file . Имеет смысл, хотя кто-то, не зная, как cp должен делать по умолчанию, может подумать, что вы пытаетесь сделать file null устройством.
  • eval > file или eval '' > file . Не запускает ничего и перенаправляет свой вывод в file . Имеет смысл для меня. Странно, что это не обычная идиома.
  • printf '' > file : явно не печатает ничего в файл. Тот, который имеет для меня больше всего смысла.

С точки зрения производительности

Разница в том, будем ли мы использовать встроенную оболочку или нет. Если нет, процесс должен быть раздвоен, команда загружена и выполнена.

eval гарантированно будет построен во всех оболочках. : встроен везде, где он доступен (нравится Bourne / csh). Истина встроена только в борновские оболочки.

printf встроен в большинство современных борнеобразных снарядов и fish .

cp и cat вообще не встроены.

Теперь cp /dev/null file не вызывает перенаправления оболочки, поэтому такие вещи, как:

 find . -exec cp /dev/null {} \; 

будут более эффективными, чем:

 find . -exec sh -c '> "$1"' sh {} \; 

(хотя и не обязательно:

 find . -exec sh -c 'for f do : > "$f"; done' sh {} + 

).

Лично

Лично я использую : > file в Bourne-подобных оболочках и в наши дни не использую ничего, кроме Bourne-подобных оболочек.

Вы можете посмотреть на truncate , который делает именно это: обрезать файл.

Например:

 truncate --size 0 file.txt 

Это, вероятно, медленнее, чем использование true > file.txt .

Однако мой главный смысл: truncate предназначен для усечения файлов, а при использовании> имеет побочный эффект обрезания файла.

Ответ немного зависит от file.txt и того, как процесс записывается в него!

Я приведу общий пример использования: у вас есть растущий файл журнала, называемый file.txt , и вы хотите его повернуть.

Поэтому вы копируете, например, file.txt в file.txt.save , а затем обрезаете file.txt .

В этом случае, если файл не открывается another_process (например: another_process может быть программой, выводимой в этот файл, например, программой, регистрирующей что-то), то ваши 2 предложения эквивалентны, и оба работают хорошо (но второй предпочтительнее поскольку первый «cat / dev / null> file.txt» – это бесполезное использование Cat, а также открывает и читает / dev / null).

Но реальная проблема заключается в том, что other_process все еще активен и все еще имеет открытый дескриптор, идущий в файл .txt.

Затем возникают 2 основных случая, в зависимости от того, как other process открыл файл:

  • Если other_process открывает его обычным способом, тогда дескриптор будет по-прежнему указывать на прежнее место в файле, например, со смещением 1200 байт. Поэтому следующая запись начнется со смещения 1200, и, таким образом, вы снова получите файл 1200 байт (+ любой другой файл_процесса) с 1200 ведущими нулевыми символами! Я полагаю, не то, чего вы хотите .

  • Если other_process открыл file.txt в «append mode», то каждый раз, когда он пишет, указатель будет активно искать конец файла. Поэтому, когда вы усекаете его, он будет «искать» до байта 0, и у вас не будет плохого побочного эффекта! Это то, что вы хотите (… обычно!)

Обратите внимание, что это означает, что вам нужно, когда вы other_process файл, чтобы убедиться, что все other_process , все еще записывающие в это место, открыли его в режиме «добавить». В противном случае вам нужно остановить эти other_process и запустить их снова, чтобы они начали указывать в начале файла вместо прежнего местоположения.

Ссылки: https://stackoverflow.com/a/16720582/1841533 для более подробного объяснения, а также хороший краткий пример разницы между обычным и приложением режима регистрации на https://stackoverflow.com/a/984761/1841533

Мне нравится это и часто его использовать, потому что он выглядит чище, а не как кто-то случайно попал в ключ возврата:

 echo -n "" > file.txt 

Должен быть встроенный тоже?