なぜ `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; elihwfor を使用するようなもの{some busy program}ですか?)。しかし、著者はそれを「異常なものは何もない」と呼んでいます。

回答:


40

通常cat /dev/null > [something]は、実際のファイル状態が中断されるリスクが絶対にゼロであることを確認しながら、ファイルの内容を消去する場合に使用します。ファイルの内容は、ファイルがcat /dev/null存在し、存在するファイルシステムに認識されているため、同じiノード番号、所有権、アクセス許可でファイル自体によって明らかに消去されます。

ログファイルの場合、ログファイル自体が別のプロセスによって「使用中」とマークされている可能性があります。そのため、たとえば、rm /var/log/messages && touch /var/log/messages他のプロセスを妨害し、実行中のプロセスが停止する可能性があります。ファイルに接続されている特定のiノード番号に何らかの形でロックされているプロセスを意味する/var/log/messagesと、突然パニックに陥り、「おい!何が起こったの/var/log/messages!」ファイルがまだそこにある場合でも。所有権とアクセス許可が誤って再作成されるという潜在的な問題は言うまでもありません。

ファイルの使用法/状態の不確実性のためcat /dev/null > [something]、ログを消去したいが、既存のプロセスの操作を潜在的に妨げたくないシステム管理者は、使用を推奨します。

また、著者にリンクするページのコンテキストでは、次のように述べています。

ここでは珍しいことは何もありません。コンソールまたはターミナルウィンドウのコマンドラインから1つずつ簡単に呼び出すことができるコマンドセットのみです。スクリプトにコマンドを配置することの利点は、何度もコマンドを再入力する必要がないことをはるかに超えています。

したがって、著者が言及する「異常なものはありません」とは、その特定のbashスクリプトの概念全体に関するものです。コマンドラインから簡単に実行できるが、それらを何度も再入力する必要はありません。


10
@jlliagre「キープアライブ」されている唯一のことは、元の作者がそれを行う理由に焦点を当てた質問のコンテキストです。「神話」を払拭することに熱中している場合は、元の著者のコーディング方法のコンテキストと、他の方法で置き換えることができると思われる理由の見通しを提供する回答を投稿してください。
JakeGould

7
@jlliagre Cyrusの回答は、元の作者がなぜその方法を使用したのか、またその背後にある理由の核心的な質問には対応していません。上記のチュートリアルはかなり古く、合理的に受け入れられています。それは間違いではなく、想定された「都市伝説」を永続させるものでもありません。むしろ、ある人がコーディングする方法と、別の人がコーディングする方法です。それと同じくらい簡単。これは、信頼性やパフォーマンスに悪影響を与えないスタイルの問題です。
JakeGould

3
truncate -s 0同じことを行い、あまり慣用的ではありません。ただし、シェルプログラマーは保守的な集団であり、そのコマンドを欠くほど古いシステムや奇抜なシステムに遭遇する可能性があります。
シュヴェルン14

5
@skift cat /dev/null > /foo/barはファイルを切り捨てます。echo "" > /foo/barそれを切り捨ててから、単一の改行文字を書き込みます。
デビッド

2
rm&touchに対するこの方法のもう1つの利点は、所有権とアクセス許可が維持されることです。
jjmontes 14

121

なぜ/ dev / nullを何かの上に置くのですか?

iノードをそのままにしながら、ファイルの内容を切り捨てるためにそれを行います。そのファイルを読み取りまたは書き込み用に開いているすべてのプログラムは、ファイルサイズがゼロにリセットされるという事実以外では影響を受けません。

よくある偽の代替策は、ファイルを削除してから再度作成することです。

rm file
touch file

または同様のもの:

mv file file.old
gzip file.old
touch file

問題は、これらの方法では、削除時に削除されたファイルを開いているプロセスによって古いファイルが書き込まれ続けることを妨げないことです。理由は、Unixファイルシステムでは、ファイルを削除するとき、その名前(パス)をそのコンテンツ(inode)からリンク解除するだけです。iノードは、読み取りまたは書き込み用にオープンしているプロセスがある限り、生き続けます。

これはいくつかの悪影響をもたらします。削除されたファイルを開くための簡単で移植性のある方法がないため、ファイルの削除後に書き込まれたログは失われます。プロセスが削除されたファイルに書き込みを行っている限り、そのコンテンツはファイルシステム上のスペースを使用しています。つまり、ファイルがディスクをいっぱいにしていたためにファイルを削除または作成しても、ディスクはいっぱいのままです。この後者の問題を解決する1つの方法は、ロガープロセスを再起動することですが、重要なサービスに対してはこれを行いたくない場合があり、中間ログは完全に失われます。また、作成するファイルには元のファイルと同じ権限、所有者、およびグループがない可能性があるため、副作用もあります。これにより、たとえば、ログアナライザーが新しく作成されたファイルを読み取ることができなかったり、さらに悪いことに、ロギングプロセスが独自のログを書き込むことができなくなったりする可能性があります。

最初の方法cat /dev/null > fileは目標を適切に達成しますが、粘り強い都市伝説にもかかわらず、そのcat /dev/null部分は何の役にも立ちません。設計上空の擬似ファイルを開き、そこから何も読み取れず、最終的に終了します。このコマンドを使用すると、キーストローク、バイト、システムコール、およびCPUサイクルが無駄になり、機能を変更することなく、間違いなく高速な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."

これは次のように、ボーンの構文を使用して、すべてのシェルで動作しますashbashkshzsh同類と:

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

ただし、POSIX Bourne以前の古代のシェルでは、これらのコマンドのいずれも、cat /dev/null実行中のシェルスクリプトによって追加されたファイルが後で書き込まれた場合、ファイルを切り捨てません。ゼロバイトファイルの代わりに、サイズが変更されていないスパースファイルになります。同じことが、書き込み前の現在の位置と考えられる位置をシークするプロセスによってファイルが書き込まれた場合に発生します。

また、ファイルを切り捨てるようにしばしば提案されるいくつかの代替ソリューションには欠陥があることに注意してください。

  • 次の両方は、単に仕事をしません。結果のファイルは空ではありませんが、空の行が含まれています。これによりwtmp、固定幅レコードを保存するようなログファイルが破損します。

    echo > file
    echo "" > file
  • BSD shオプションに基づく次のオプションは移植性がありません。POSIXではエコーの許可オプションが指定されていないため、 " -n"の行を含むファイルが作成される可能性があります。

    echo -n > file
  • System V shエスケープシーケンスを使用しても移植性がない。一部のシェルでは、「\c」を含む行を含むファイルが作成されます。

    echo "\c" > file
  • そのジョブを実行するために設計されたコマンドを使用します。truncateこのコマンドは、POSIXで指定されていないため、Unix / Linuxシステムから欠落している可能性があるため、使用中の移植性はありません。

    truncate -s 0

最後に、移植性があり、適切に仕事をするいくつかの選択肢があります:

  • 空の文字列をファイルに明示的に出力する:

    printf "" > file
  • より読みやすいとはいえtrue、no-op のコマンドと厳密に同等のコマンドを使用し:ます。

    true > file

1
@JonathanLeffler csh必ずしも文書化されているわけではありませんが、現在のすべての実装の一部であると考えています。Solarisのcsh マニュアルページから: Null command. This command is interpreted, but performs no action.。私はtcshマニュアルページや元のBSDのいずれにも同じことについて言及していませんでしたcshが、この構文は常に機能していました。
jlliagre 14

6
書く理由の1つcat /dev/nullは、意図を明確にすることです。
Davidmh 14

1
@Davidmhそれは理にかなっていますが、あなたの声明は事実確認に抵抗しません。私はこのシェルのイディオムをおそらく数十年にわたって観察してきました。著者にその背後にある理由を尋ねる機会があったとき、私は常に/dev/nullゼロバイトを注入する効率的な方法であることについて不健全な理論を得ました:。このページでは、Cyrusの答えは簡潔でありながら、ポイントにまっすぐでしたが、JakeGouldの事実cat /dev/nullに異議を唱えた人はノーオペレーション(コメントを参照)ですでに4票以上ありました。
jlliagre 14

2
@jlliagreシェルに関する私の知識はかなり基本的なものなので、おそらく私は最適な人口ターゲットではありません。しかし、裸>または:明確ではありません。神話がその使用のために広まっているのは残念です。
Davidmh

4
@Davidmhリダイレクトの前に何か明示的にしたい場合printf "" > fileは、シェル組み込みとして実装されることが多いポータブル(POSIX)と軽量の両方をお勧めします。
jlliagre 14

6

ファイルをゼロサイズにするのは面倒な方法です。

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

この構文は、すべてのシェルで機能するわけではありません。
reinierpost 14

2
正しい。質問は「bash」でのみタグ付けされます。
サイラス14

@reinierpostすべてのBourneスタイルのシェルで動作します。心配しないでくださいcsh
バーマー14

: > messages動作します。 :またはtrue、何も出力せずにtrueを返すコマンドのより明白な選択肢です。
ピーターコーデス

-3

開いているファイルを切り捨てます。これは同等であり、よりわかりやすいです:

echo -n > /var/log/messages

(改行を避けるために-nを追加しました)


3
これは実際にはよりわかりやすいですが、残念ながら同等ではありません。wtmp場合のように機能を破壊することさえあります。更新された回答をご覧ください。
jlliagre 14

echo -nは改行を避けます。
bbaassssiiee 14

6
あなたが使用することを確認している場合、確かだろうbash-nそうでない場合は、すべてのBourneシェルでの動作が保証されていません。
jlliagre 14
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.