web-dev-qa-db-ja.com

:> filename.txtとは何ですか?

:>filename.txt

例えば:

root@box$ dd if=/dev/zero of=file.txt count=1024 bs=1024
1024+0 records in
1024+0 records out
1048576 bytes (1.0 MB, 1.0 MiB) copied, 0.00536175 s, 196 MB/s
root@box$ ll
total 1024
-rw-r--r-- 1 root root 1048576 Nov 15 14:40 file.txt
root@box$ :>file.txt
root@box$ ll
total 0
-rw-r--r-- 1 root root 0 Nov 15 14:40 file.txt

これはrmとは異なりますか?ファイルをゼロ化したり削除したりする他の同様の方法よりも速く動作しますか?

23
Kahn

ご存じのとおり、これはファイルの内容を空にするだけです(ファイルを切り捨てます)。 rmは実際にファイルを完全に削除するため、rmとは異なります。さらに、:>file.txtは実際にはファイルが存在しない場合はcreateになります。

:は、成功して終了し、出力を生成しない「何もしないコマンド」であるため、ファイルを空にする短い方法です。ほとんどのシェルでは、>file.txtを実行するだけで同じ結果を得ることができます。また、echoが外部コマンドになる可能性があるため、echo >file.txtなどの他のメソッドよりもわずかに高速になる可能性があります。

さらに、echo >file.txtfile.txtに空白行を入れ、:>file.txtはファイルに内容をまったく含まないようにします。

38
jesse_b

はい、rmとは異なります。

rmはファイルを削除します。

:>filename.txtはファイルを空にしてそのままにしますが、サイズは0バイトです。

8
steve

シェルが>filename.txtを呼び出すと、一部の出力がファイル「filename.txt」にリダイレクトされ、完全に置き換えられます。したがって、シェルは出力を書き込む前に、指定されたファイルのすべてのコンテンツをクリアする必要があります。

リダイレクトされる出力は、実行されたコマンドの出力です。お気に入り:

$ echo Hello >filename.txt

Filename.txtという名前のファイルに、文字列Helloを正確に(かつ唯一)含めるようにします。

実行中:

$ echo "New Value" >filename.txt
$ cat filename.txt
New Value

ファイル内のすべてを消去し、New Valueを書き込みます。

コマンドtrueのようにコマンドに出力がない場合、ファイルは空のままになります(切り捨てられます)。

$ true >filename.txt
$ cat filename.txt

シェルの組み込みでもあるコマンドは:(二重ドット(コロン)のみ)であり、出力はありません。組み込みであるため、trueなどの外部コマンド(出力もありません)よりも高速になります。だから、どちらか:

$ :  >  filename.txt
$ :  >filename.txt
$ :>filename.txt

filename.txtという名前のファイルからすべてのコンテンツを削除するか、存在しない場合は空のファイルとして作成します。

これはrmとは異なりますか?

これはrmとは異なります。rmはファイルをlsから消去し、ファイルに0バイトが含まれないようにするためです。

ファイルをゼロにする、またはファイルを削除する他の同様の方法よりも速くまたは遅く動作しますか?

この場合も、ファイルは削除されていません(lsで指定されたリストから消えます)。空のファイル(0バイトを含む)に変換されます。

ファイルを空にするために外部コマンドを呼び出すよりも高速でなければなりません。実行可能ファイルとexecをロードするために子シェルを作成する必要があるため、外部コマンドは組み込みの:よりも遅くなります。

同様の解決策は次のとおりです(一部は$?を1に設定):

[ ]         > filename.txt
builtin     > filename.txt
command     > filename.txt
printf ''   > filename.txt
4
Isaac

re:パフォーマンス:これはシェルで可能な限り効率的です。カーネルに既存のファイルを切り捨てるように要求することは、ファイルのリンクを解除して同じ名前で新しいiノードを再作成するよりも効率的です。あなたがファイルを削除したい場合を除き、その場合はrmまたはunlinkです。

_:_はシェル組み込みなので、fork/execを回避できます。同様に、通常の最新のシェルにおける同等のtrueも同様です。

_>foo_または_true > foo_は、シェルを取得してファイルを切り捨てます。
open(path, O_WRONLY|O_TRUNC|O_CREAT, 0666)システムコール。

または実際にLinuxのDASHで、_strace sh_出力から:
openat(AT_FDCWD, "foo", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3これは同等です。

次に、そのFDをclose()する必要があります。実際、DASHは、_:>_を使用する場合の特別なケースではなく、次のフープをジャンプします。

_openat(AT_FDCWD, "foo", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
fcntl(1, F_GETFD)                       = 0
fcntl(1, F_DUPFD, 10)                   = 10          # save original stdout
fcntl(1, F_GETFD)                       = 0
fcntl(10, F_SETFD, FD_CLOEXEC)          = 0
dup2(3, 1)                              = 1           # redirect stdout to foo
close(3)                                = 0           # then close 3
dup2(10, 1)                             = 1           # then restore original stdout
fcntl(10, F_GETFD)                      = 0x1 (flags FD_CLOEXEC)
close(10)                               = 0
_

DASHで_> foo_を使用すると、同じシステムコールシーケンスが発生し、実際にはfd1をリダイレクトしてから復元します。 bashや他のシェルはチェックしませんでした。

しかし、それは(うまくいけば)単一の truncate("foo", 0)システムコール を実行する_truncate -s 0 foo_を実行する新しいプロセスを作成するよりもはるかに安価です。 open + closeよりも。

Cなどの言語(またはシステムコールバインディングのあるもの)からは、直接開かないtruncate syscallを使用して、開いたくないファイルの切り捨てを最も効率的に行うことができます。

Dashでは、_3>foo_がこのシステムコールのシーケンスにつながります:

_openat(AT_FDCWD, "foo", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
close(3)                                = 0
_

新しいfdを開くと、すでにfd 3になっており、重複を回避できます。これはダッシュで最も効率的な方法であり、おそらく_>foo_と比較して数マイクロ秒を節約します。それが問題なら、シェルスクリプトはあなたの仕事にとって間違った言語です!!しかし、あなたは尋ねました。


Spectre + Meltdownの緩和機能が有効になっていると、_-ENOSYS_の悪いシステムコールでも、最新のIntel x86-64では少なくとも数千クロックサイクル(マイクロ秒)かかります。 syscall命令だけで、ユーザー->カーネル->ユーザーの往復の数百から。もちろん、パスの検索などにはかなりの時間がかかり、ファイルシステムのコードにも時間がかかります。また、カーネルモードに戻って戻ると、キャッシュが削除され、ユーザー空間の実行が遅くなります。

メタデータがディスクに書き戻した後の実際のI/Oコストは、ファイルシステムによって異なります。 FS XFSまたは最新のext4のように、ファイル全体に1つまたはいくつかの大きなエクステントのみを使用すると、O(1)時間で大量のスペースを簡単に解放できますまたはO(n)ここで、nは、バイト単位のサイズではなく、エクステント(フラグメンテーション)の数です。

FSによっては、エクステント情報が間接ブロックではなくiノードに直接格納されている場合、フリーリストに追加する必要のある項目が1つ少なくなります。

I/Oコストはファイルのリンク解除に似ていますが、iノードを解放したり、ディレクトリエントリを変更したりする必要はありません。切り捨ての際にiノードのmtimeとctimeを更新する必要がありますが、サイズが変更された場合はとにかくそれを書かなければなりませんでした。

2
Peter Cordes