Чому ви б "cat / dev / null> / var / log / messages"?


77

На цій прикладі баш сценаріїв автор представляє цей сценарій:

# 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}?). Але автор називає це «Нічого незвичайного».

Відповіді:


41

Зазвичай, cat /dev/null > [something]коли ви хочете стерти вміст файлу, гарантуючи, що існує абсолютно нульовий ризик переривання фактичного стану файлу. Вміст файлу буде чітко стертий cat /dev/nullще самим файлом - як він існує, так і відомий файловій системі, на якій він перебуває - все ще буде там з тим самим номером inode, правом власності та дозволами.

У випадку з файлом журналу може бути, що сам файл журналу позначений "використовується" іншим процесом. Так що, наприклад, - rm /var/log/messages && touch /var/log/messagesможе бути руйнівним для інших процесів і може призвести до задушення запущених процесів. Це означає, що процес, який якимось чином заблокований у певному номері inode, підключеному до файлу, /var/log/messagesможе раптом панікувати і сказати: "Ей! Що трапилось /var/log/messages! ”Навіть якщо файл все ще є. Не кажучи вже про можливі проблеми з неправильним відтворенням прав власності та дозволів.

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

Також у контексті сторінки, яку ви посилаєтесь на автора, зазначено наступне:

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

Отже, "нічого незвичайного" автор згадує, що стосується цілого поняття, що таке конкретний скрипт bash: Це лише набір простих команд, які так само легко можна запустити з командного рядка, але розмістити у текстовому файлі для уникати повторного введення їх знову і знову.


10
@jlliagre Єдине, що "зберігається в живих" - це контекст питання, який зосереджений на тому, чому саме так поступив би автор-автор. Якщо ви захоплюєтесь тим, що розповсюджуєте "міф", будь ласка, опублікуйте відповідь, яка містить контекст для оригінального методу кодування оригіналу автора, а також питання про те, чому ви вважаєте, що його можна замінити іншими методами.
JakeGould

7
@jlliagre Кіра відповідь не стосується основного питання, чому оригінальний автор використовував би цей метод, ані міркування за ним. Згаданий підручник досить старий і розумно прийнятий. Це невірно і не увічнює передбачувану "міську легенду". Скоріше, це спосіб кодування однієї людини проти того, як кодує інша людина. Так просто. Це питання стилю, який не має негативного впливу на надійність чи продуктивність.
JakeGould

3
truncate -s 0зробив би те саме і був би менш ідіоматичним. Однак програмісти оболонок - це консервативний набір, і можна зустріти системи, досить старі або досить дурні, щоб не вистачало цієї команди.
Шверн

5
@skift cat /dev/null > /foo/barобрізає файл; echo "" > /foo/barобрізає його, а потім записує єдиний символ нового рядка.
Девід

2
Ще одна перевага цього методу перед rm & touch полягає в тому, що зберігаються права власності та дозволи.
jjmontes

121

Чому б ти котів / dev / null ні на що?

Ви зробите це для врізання вмісту файлу, зберігаючи inode недоторканою. Усі програми, у яких цей файл відкритий для читання чи запису, не впливатимуть поза тим, що розмір файлу буде скинутий до нуля.

Часто зустрічається хибна альтернатива - це видалити файл, а потім створити його знову:

rm file
touch file

або подібне:

mv file file.old
gzip file.old
touch file

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

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

Перший метод - cat /dev/null > fileдосягти мети належним чином, проте, незважаючи на завзяту міську легенду, його cat /dev/nullчастина не робить нічого корисного. Він відкриває псевдофайл, який порожній за дизайном, не вдається прочитати з нього нічого і, нарешті, просто виходить. Використання цієї команди - це марно натискання клавіш, байтів, системних викликів та циклів процесора, і його можна без будь-яких функціональних змін замінити, безсумнівно, швидшою командою без операції :або навіть, з більшості оболонок, зовсім не командою.

Дозвольте спробувати метафору, щоб пояснити, наскільки це марно 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
  • Наступний варіант, заснований на BSD- shопції, не є портативним, POSIX не вказує жодних дозволених параметрів для відлуння, тому, можливо, ви отримаєте файл, що містить рядок з " -n":

    echo -n > file
  • Той, що не є портативним, також використовуючи shпослідовність аварійної системи System V. Деякі оболонки створять файл, що містить рядок з " \c":

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

    truncate -s 0

Нарешті, ось кілька альтернативних варіантів, які є портативними та належним чином виконають роботу:

  • Явно друкує порожній рядок у файл:

    printf "" > file
  • Використання trueкоманди, яка суворо еквівалентна no-op, :хоч і читабельніше:

    true > file

1
@JonathanLeffler Я вважаю, що це частина всіх поточних cshреалізацій, хоча це не обов'язково документується. На csh сторінці керівництва Solaris : Null command. This command is interpreted, but performs no action.. Я не знайшов жодної згадки ні на tcshсторінці керівництва, ні на оригінальних BSD csh, але цей синтаксис завжди працював.
jlliagre

6
Однією з причин написання cat /dev/nullє ясність ваших намірів.
Давідм

1
@Davidmh Це було б розумно, але ваше твердження не протистоїть перевірки фактів. Я спостерігав цю ідіому оболонки, мабуть, пару десятків років. Коли в мене була можливість запитати автора в міркуваннях, то я завжди мав невірні теорії щодо використання /dev/nullефективного способу введення нульових байтів, у будь-якому разі більш надійного, ніж використання :або нічого. На цій самій сторінці Кіра відповідь була короткою, але прямо до суті мала нульові голоси, тоді як той, хто оскаржував факт ДжейкГулда, був невідповідним cat /dev/null(див. Наші коментарі) вже мав принаймні чотири голоси.
jlliagre

2
@jlliagre мої знання про оболонку досить основні, тому я, мабуть, не найкраща цільова група населення; але голий >чи :незрозумілий. Я погоджуюся, прикро, що міфи поширюються завдяки його використанню.
Девідм

4
@Davidmh Якщо ви дійсно хочете чогось явного перед перенаправленням, я б рекомендував, printf "" > fileякий є як портативним (POSIX), так і легким, так часто, як реалізований як оболонка вбудований.
jlliagre

6

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

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

Цей синтаксис працюватиме не в кожній оболонці.
reinierpost

2
Правильно. Питання позначене лише "баш".
Кіра

@reinierpost Він буде працювати у всіх оболонках у стилі Борна, чи не так? Не будемо хвилюватися csh.
Бармар

: > messagesтакож працює. :або trueє більш очевидним вибором команд, які нічого не друкують та повертають true.
Пітер Кордес

-3

Щоб урізати відкритий файл. Це рівнозначно і зрозуміліше:

echo -n > /var/log/messages

(Додано -n, щоб уникнути нового рядка)


3
Це дійсно більш зрозуміло, але, на жаль, не рівнозначно. Це навіть порушить функціональність, як у wtmpвипадку. Дивіться мою оновлену відповідь.
jlliagre

echo -n уникає нового рядка.
bbaassssiiee

6
Дійсно, якщо ви впевнені в застосуванні bash, -nінакше не гарантовано працювати у всіх оболонках Борна.
jlliagre
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.