Зачем вам `cat / dev / null> / var / log / messages`?

77

На этой странице примера сценария 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}?). И все же автор называет это «Ничего необычного».

isomorphismes
источник

Ответы:

40

Вы обычно, 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: это просто набор простых команд, которые можно так же легко запускать из командной строки, но помещать в текстовый файл для избегайте перепечатывать их снова и снова.

JakeGould
источник
10
@jlliagre Единственное, что «сохраняется» - это контекст вопроса, который сфокусирован на том, почему первоначальный автор сделал это. Если вы заинтересованы в том, чтобы развеять «миф», пожалуйста, опубликуйте ответ, который предоставляет контекст для оригинального авторского метода кодирования, а также дает представление о том, почему вы считаете, что его можно заменить другими методами.
JakeGould
7
Ответ @jlliagre Сайруса не затрагивает ключевой вопрос о том, почему первоначальный автор использовал этот метод, ни о его причинах. Упомянутый учебник довольно старый и приемлемый. Это не неверно и не увековечивает предполагаемую «городскую легенду». Скорее, это способ, которым один человек кодирует, а другой человек. Так просто, как, что. Это проблема стиля, которая не оказывает негативного влияния на надежность или производительность.
JakeGould
3
truncate -s 0сделал бы то же самое и был бы менее идиоматичным. Тем не менее, программисты оболочки - консервативная группа, и можно встретить системы, достаточно старые или странные, чтобы не иметь этой команды.
Шверн
5
@skift усекает cat /dev/null > /foo/barфайл; echo "" > /foo/barобрезает его, а затем пишет один символ новой строки.
Дэвид
2
Другое преимущество этого метода перед rm & touch заключается в том, что права собственности и разрешения сохраняются.
14:30
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' и '> wtmp' имеют одинаковый эффект.

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

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

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

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

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

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

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

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

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

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

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

    truncate -s 0

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

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

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

    true > file
jlliagre
источник
1
@JonathanLeffler Я считаю, что это является частью всех текущих cshреализаций, хотя это не обязательно задокументировано. Со csh страницы руководства Solaris : Null command. This command is interpreted, but performs no action.. Я не нашел упоминания об этом ни на tcshстранице руководства, ни в оригинальной BSD csh, но этот синтаксис всегда мог работать.
Jlliagre
6
Одна из причин для написания статьи cat /dev/null- сделать ваши намерения явными.
Davidmh
1
@Davidmh Это было бы разумно, но ваше утверждение не сопротивляется проверке фактов. Я наблюдал эту идиому оболочки, вероятно, пару десятилетий. Когда у меня была возможность задать автору причину, стоящую за этим, у меня всегда возникали несостоятельные теории об использовании /dev/nullэффективного способа ввода нулевых байтов, во всяком случае, более надежного, чем использование :или ничего. На этой самой странице ответ Сайруса, который был лаконичным, но прямо к делу, имел нулевые голоса, в то время как тот, кто оспаривал этот факт, cat /dev/nullбыл Джейком Гулдом, но не участвовал (см. Наши комментарии) и уже набрал по меньшей мере четыре голоса.
Jlliagre
2
@jlliagre мои знания об оболочке довольно просты, поэтому я, возможно, не самая лучшая цель для населения; но голый >или :непонятный. Я согласен, что это позор, что мифы были распространены из-за его использования.
Davidmh
4
@Davidmh Если вы действительно хотите что-то явное до перенаправления, я бы порекомендовал, printf "" > fileчто является как переносным (POSIX), так и легким, что часто реализуется как встроенная оболочка.
Jlliagre
6

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

cd /var/log
> messages
> wtmp
echo "Log files cleaned up."
Кир
источник
Этот синтаксис не будет работать в каждой оболочке.
reinierpost
2
Верный. Вопрос только помечен как "bash".
Сайрус
@reinierpost Это будет работать во всех оболочках в стиле Борна, не так ли? Давай не будем беспокоиться csh.
Бармар
: > messagesтоже работает. :или trueболее очевидный выбор для команд, которые ничего не выводят и возвращают true.
Питер Кордес
-3

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

echo -n > /var/log/messages

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

bbaassssiiee
источник
3
Это действительно более понятно, но, к сожалению, не является эквивалентом. Это даже сломает функциональность как в wtmpслучае. Смотрите мой обновленный ответ.
Jlliagre
echo -n избегает перевода строки.
bbaassssiiee
6
Это действительно, если вы уверены, что использовать bash, -nв противном случае не гарантируется работа во всех оболочках Борна.
Jlliagre