76

На этой странице примера сценария bash автор представляет следующий сценарий:

# Cleanup
# Run as root, of course.

cd /var/log
cat /dev/null > messages
cat /dev/null > wtmp
echo "Log files cleaned up."

Зачем вам cat /dev/null на что-нибудь? Я не могу понять, что здесь задумано (это как использовать while TRUE; sleep 1; elihw для {some busy program}?). И все же автор называет это «Ничего необычного».

4 ответа4

121

Зачем вам кататься /dev /null на что-нибудь?

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

Часто встречается фиктивная альтернатива - удаление файла, а затем его создание:

rm file
touch file

или подобное:

mv file file.old
gzip file.old
touch file

Проблема заключается в том, что эти методы не предотвращают запись старого файла какими-либо процессами, у которых удаленный файл открыт во время удаления. Причина заключается в том, что в файловых системах Unix при удалении файла вы только отсоединяете его имя (путь) от его содержимого (inode). Индод сохраняется, пока существуют процессы, в которых он открыт для чтения или записи.

Это приводит к нескольким негативным последствиям: журналы, записанные после удаления файла, теряются, поскольку не существует простого / портативного способа открыть удаленный файл. Пока процесс выполняет запись в удаленный файл, его содержимое все еще использует пространство в файловой системе. Это означает, что если вы удалите / создадите файл, потому что он заполнил ваш диск, диск останется заполненным. Один из способов решения этой последней проблемы - перезапустить процессы регистратора, но вы, возможно, не захотите этого делать, поскольку критически важные службы и промежуточные журналы будут окончательно потеряны. Существуют также побочные эффекты, связанные с тем, что создаваемый файл может не иметь таких же прав доступа, владельца и группы, как у исходного. Это, например, может помешать анализатору журналов читать вновь созданный файл, или, что еще хуже, запретить процессу журналирования записывать собственные журналы.

Первый метод, cat /dev/null > file достигает цели должным образом, однако, несмотря на упорную городскую легенду, его часть cat /dev/null не делает абсолютно ничего полезного. Он открывает псевдо-файл, который пуст по своей структуре, он не может ничего прочитать из него и, наконец, просто завершается. Использование этой команды в таком случае является пустой тратой нажатий клавиш, байтов, системных вызовов и циклов ЦП, и ее можно заменить без каких-либо функциональных изменений несомненно более быстрой командой no-op : или даже, с большинством оболочек, вообще никакой командой.

Позвольте мне попробовать метафору, чтобы объяснить, насколько бесполезен cat /dev/null . Допустим, ваша цель - опустошить стакан.

  • Сначала вы удалите из него любую жидкость. Этого достаточно, и это именно то, что (> file) делает, учитывая, что перенаправления факта всегда обрабатываются первыми.

  • Затем вы выбираете пустую бутылку (/dev/null) и выливаете ее в пустой стакан (cat). Это бессмысленный шаг ...

Если вы прочитаете связанный документ до конца, вы можете заметить комментарии в этой строке от расширенной версии скрипта:

    cat /dev/null > wtmp  #  ': > wtmp' and '> wtmp'  have the same effect.

Они действительно есть; очень плохой cat /dev/null был сохранен в коде.

Это означает, что следующий код будет работать со всеми распространенными оболочками (семейства csh и sh ):

cd /var/log
: > messages
: > wtmp
echo "Log files cleaned up."

и это будет работать со всеми оболочками, использующими синтаксис Борна, такими как ash , bash , ksh , zsh и подобные:

cd /var/log
> messages
> wtmp
echo "Log files cleaned up."

Однако обратите внимание, что в древних оболочках Борна до POSIX любая из этих команд, в том числе cat /dev/null , не будет обрезать файл, если впоследствии он будет записан все еще работающим сценарием оболочки, добавляющим его. Вместо файла нулевого байта это будет разреженный файл с неизменным размером. То же самое произойдет, если файл будет записан процессом, ищущим позицию, которую он считает текущей, перед записью.

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

  • Оба из следующих просто не делают работу. Полученный файл не пустой, но содержит пустую строку. Это сломало бы файлы журнала, такие как wtmp которые хранят записи фиксированной ширины.

    echo > file
    echo "" > file
    
  • Следующий, основанный на опции BSD sh не является переносимым, POSIX не указывает никаких разрешенных опций для echo, поэтому вы можете получить файл, содержащий строку с « -n »:

    echo -n > file
    
  • Это тоже не переносимо с помощью escape-последовательности System V sh . Некоторые оболочки создают файл, содержащий строку с « \c »:

    echo "\c" > file
    
  • Тот использует команду, предназначенную для работы. Проблема в том, что truncate не является переносимым, поскольку эта команда, не указанная в POSIX, может отсутствовать в системе Unix/Linux.

    truncate -s 0
    

Наконец, вот пара альтернатив, которые являются портативными и будут правильно выполнять свою работу:

  • Явная печать пустой строки в файл:

    printf "" > file
    
  • Использование команды true которая строго эквивалентна команде no-op : хотя и более читабельной:

    true > file
    
41

Вы обычно cat /dev/null > [something] когда вы хотите стереть содержимое файла, гарантируя при этом абсолютно нулевой риск прерывания к реальному состоянию файла. Содержимое файла будет явно удалено командой cat /dev/null но сам файл, поскольку он существует и известен файловой системе, в которой он находится, все равно будет там с тем же номером инода, владельцем и правами доступа.

В случае файла журнала может оказаться, что сам файл журнала помечен как «используемый» другим процессом. Такие действия, например, rm /var/log/messages && touch /var/log/messages будут иметь негативные последствия для других процессов и могут вызвать удушение запущенных процессов. Это означает, что процесс, который каким-то образом привязан к определенному номеру инода, связанному с файлом /var/log/messages может внезапно запаниковать и сказать: «Эй! Что случилось с /var/log/messages ! ” даже если файл все еще там. Не говоря уже о потенциальных проблемах с владельцем и неправильно воссозданными разрешениями.

Из-за этой неопределенности в использовании / состоянии файла использование cat /dev/null > [something] предпочитают системные администраторы, которые хотят очистить журнал, но не хотят потенциально вмешиваться в работу уже существующих процессов.

Также в контексте страницы, на которую вы ссылаетесь, автор заявляет следующее:

Здесь нет ничего необычного, только набор команд, которые так же легко можно было бы вызывать по одной из командной строки на консоли или в окне терминала. Преимущества размещения команд в сценарии выходят далеко за пределы необходимости повторного их ввода.

Таким образом, «ничего необычного», о котором упоминает автор, касается всей концепции того, что представляет собой этот конкретный сценарий bash: это просто набор простых команд, которые можно так же легко запускать из командной строки, но помещать в текстовый файл для Избегайте необходимости перепечатывать их снова и снова.

6

Это громоздкий способ довести файл до нулевого размера.

cd /var/log
> messages
> wtmp
echo "Log files cleaned up."
-3

Обрезать открытый файл. Это эквивалентно и более понятно:

echo -n > /var/log/messages

(Добавлен -n, чтобы избежать новой строки)

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