web-dev-qa-db-ja.com

ファイルをゼロにするためのcatと '>'の違い

これらの2つのコマンドは、ファイルのゼロ消去についてどのように異なるのですか?後者は前者を行うより短い方法ですか?舞台裏で何が起こっているのですか?

両方とも

$ cat /dev/null > file.txt

$ > file.txt 

産出

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

cat /dev/null > file.txt猫の無駄な使用 です。

基本的にcat /dev/nullは単にcatに何も出力しない結果になります。はい、動作しますが、必要のない外部プロセスを呼び出す結果となるため、多くの人が不満を抱いています。
それが一般的であるという理由だけで一般的であるものの1つです。

> file.txtだけを使用すると、ほとんどのシェルで機能しますが、完全に移植可能ではありません。完全にポータブルにする場合は、次の方法が適しています。

true > file.txt
: > file.txt

:trueはどちらもデータを出力せず、シェルの組み込み関数です(catは外部ユーティリティです)。したがって、これらはより軽量でより適切です。

更新:

タイラーが彼のコメントで述べたように、>| file.txt構文もあります。

ほとんどのシェルには、>を使用して既存のファイルを切り捨てないようにする設定があります。代わりに>|を使用する必要があります。これは、実際に>>を追加するつもりであった場合の人的エラーを防ぐためです。 set -Cで動作をオンにできます。

したがって、これを使用すると、ファイルを切り捨てる最も簡単で適切な、移植可能な方法は次のようになると思います。

:>| file.txt
28
Patrick

移植性の観点から:

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

ノート:

  1. shまたはkshエミュレーションを除いて、コマンドのないリダイレクトの場合、zshではデフォルトのコマンドが想定されます(標準のリダイレクトのみのページャー、それ以外の場合はcat)。 NULLCMDおよびREADNULLCMD変数で調整する。これは(t)cshの同様の機能から発想を得たものです
  2. :はコメントリーダーとnullコマンドの間の途中で解釈されたため、UnixV7では:のリダイレクトは最初は実行されませんでした。後でそれらはすべてのビルトインと同じようになり、リダイレクトが失敗した場合、シェルを終了します。
  3. :およびevalは特別な組み込みであり、リダイレクトが失敗した場合、シェルを終了します(bashはPOSIXモードでのみ実行されます)。
  4. 興味深いことに、(t)cshでは、(gotoの)nullラベルを定義しているため、goto ''がそこに分岐します。リダイレクトが失敗した場合は、シェルを終了します。
  5. 対応するコマンドが$PATH:は一般に使用できない場合を除いて、truecatcpおよびprintfは一般的にあります(POSIXではそれらが必要です)。
  6. リダイレクトが失敗した場合は、シェルを終了します。
  7. ただし、fileが存在しないファイルへのシンボリックリンクである場合、GNUのような一部のcp実装はそのファイルの作成を拒否します。
  8. Bourne Shellの初期バージョン ただし、組み込みのリダイレクトはサポートしていません

読みやすさの点で:

(このセクションは非常に主観的です)

  • > file。その>は、プロンプトやコメントのように見えます。また、それを読んだときに私が尋ねる質問(そしてほとんどのシェルは同じことについて不平を言うでしょう)はどの出力を正確にリダイレクトしていますか?です。
  • : > file:は、no-opコマンドとして知られています。つまり、空のファイルを生成するとすぐに読み取れます。ただし、ここでも、その:は簡単に見落とされたり、プロンプトとして表示されたりする場合があります。
  • true > fileリダイレクトまたはファイルコンテンツとブール値はどう関係していますか?ここで何を意味するのでしょうか?それを読んだときに最初に思い浮かぶのは.
  • cat /dev/null > file/dev/nullfileに連結しますか?catは、ファイルのコンテンツをダンプするコマンドとしてよく見られますが、センス:the空のファイルの内容をfileにダンプします。 cp /dev/null fileの複雑な表現ですが、それでも理解できます。
  • cp /dev/null file空のファイルの内容をfileにコピーします。理にかなっていますが、cpがデフォルトでどのように機能するかを知らない人は、filenullデバイスにしようとしていると思うかもしれません。
  • eval > fileまたはeval '' > file。何も実行せず、その出力をfileにリダイレクトします。私には理にかなっています。それが一般的なイディオムではないことは奇妙です。
  • printf '' > file:明示的にprints何もファイルに出力しません。私にとって最も意味のあるもの。

パフォーマンスに関して

違いは、組み込みのシェルを使用しているかどうかです。そうでない場合、プロセスをフォークして、コマンドをロードして実行する必要があります。

evalは、すべてのシェルでビルドされることが保証されています。 :は、利用可能な場所に組み込まれています(Bourne/cshが好き)。 trueはBourneのようなシェルにのみ組み込まれています。

printfは、組み込みの最新のBourneのようなシェルとfishです。

cpcatは通常、組み込みではありません。

現在、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を使用しており、最近ではボーンのようなシェル以外は使用していません。

24

あなたはtruncateを見たいかもしれません、それはまさにそれをします:ファイルを切り捨てます。

例えば:

truncate --size 0 file.txt

これはおそらくtrue > file.txtを使用するよりも遅くなります。

ただし、私の主なポイントは次のとおりです。truncateはファイルの切り捨てを目的としていますが、>を使用するとファイルが切り捨てられるという副作用があります。

5
Fabian

答えは、file.txtが何であるか、およびプロセスがそれにどのように書き込むかによって多少異なります。

一般的なユースケースを引用します。file.txtというログファイルが増えており、それをローテーションしたいとします。

したがって、たとえば、file.txtfile.txt.saveにコピーしてから、file.txtを切り捨てます。

このシナリオでは、[〜#〜] if [〜#〜]ファイルがanother_processによって開かれていない(例:another_processはプログラムである可能性があります)そのファイル、たとえば何かをログに記録するプログラム)に出力する場合、2つの提案は同等であり、両方が適切に機能します(ただし、最初の「cat/dev/null> file.txt」は猫の無用な使用なので2番目が推奨されます)また、/ dev/nullを開いて読み取ります)。

しかし、実際の問題は、other_processがまだアクティブで、file.txtへのオープンハンドルがまだある場合です。

次に、other processがファイルを開いた方法に応じて、2つの主なケースが発生します。

  • other_processがそれを通常の方法で開いた場合、ハンドルはファイル内の以前の場所、たとえばオフセット1200バイトを指しています。したがって、次の書き込みはオフセット1200から開始されるため、1200バイト(+ other_processが書き込んだもの)のファイルがあり、1200の先行ヌル文字があります。 あなたが望むものではない、私は推測します。

  • other_processfile.txtを「追加モード」で開いた場合、書き込みを行うたびに、ポインタはファイルの最後までアクティブにシークします。したがって、それを切り捨てると、バイト0まで「シーク」し、悪影響はありません。 これはあなたが望むものです(...通常!)

これは、ファイルをトランケートするときに、その場所への書き込み中のすべてのother_processが「追加」モードでファイルを開いていることを確認する必要があることを意味することに注意してください。それ以外の場合は、これらのother_processを停止してから再起動する必要があるため、以前の場所ではなくファイルの先頭からポイントを開始します。

参照: https://stackoverflow.com/a/16720582/18415 より明確な説明、および https:// stackoverflow .com/a/984761/18415

2
Olivier Dulac

見た目がすっきりしていて、誰かが誤ってReturnキーを押してしまったのではないため、私はこれが好きで頻繁に使用しています。

echo -n "" > file.txt

組み込みも必要ですか?

1
awsm