「du -sh *」と「du -sh ./*」の違いは何ですか?


回答:


69
$ touch ./-c $ 'a \ n12 \ tb' foo
$ du -hs *
0 a
12 b
0 foo
合計0

ご覧のとおり、-cファイルはオプションとして使用されたものであり、du報告されていません(およびのtotalために行が表示されますdu -c)。また、と呼ばれるファイルには、a\n12\tb私たちが呼ばれるファイルがあると考えて作っているab

$ du -hs -- *
0       a
12      b
0       -c
0       foo

それは良いです。少なくとも今回-cはオプションとして採用されていません。

$ du -hs ./*
0       ./a
12      b
0       ./-c
0       ./foo

それはさらに良いです。./接頭防止-cオプションとして採用との欠如しているから./前にb出力には何もありませんことを示してbそこにファイルが、しかし、改行文字を持つファイルがあります(ただし、下記参照1、その上さらに脱線のため)。

./可能な場合はプレフィックスを使用することをお勧めします。使用しない場合、および任意のデータの場合は、常に使用する必要があります。

cmd -- "$var"

または:

cmd -- $patterns

オプションの終わりをマークするcmdことがサポートさ--れていない場合、そのバグを作成者にバグとして報告する必要があります(選択により、のように文書化されている場合を除くecho)。

./*解決--しない問題を解決する場合があります。例えば:

awk -f file.awk -- *

a=b.txt現在のディレクトリに呼び出されたファイルがある場合は失敗します(ファイルを処理aするb.txtように指示する代わりにawk変数を設定します)。

awk -f file.awk ./*

./a有効なawk変数名ではないため、問題はありません。したがって./a=b.txt、変数の割り当てとは見なされません。

cat -- * | wc -l

-現在のディレクトリでファイルが呼び出されると失敗catします。これは、stdinから読み取るように指示するためです(-ほとんどのテキスト処理ユーティリティおよびcd/に特別pushdです)。

cat ./* | wc -l

./-特別ではないのでOKですcat

次のようなもの:

grep -l -- foo *.txt | wc -l

fooファイル名に改行文字が含まれていないことを前提としているため、含まれるファイルの数をカウントするのは間違っています(wc -l改行文字、grep各ファイルの出力、ファイル名自体のカウント)。代わりに使用する必要があります:

grep -l foo ./*.txt | grep -c /

/ファイル名ごとに1つしか存在できないため、文字数をカウントする方が信頼性が高くなります)。

recursiveのgrep場合、同等のトリックは以下を使用することです:

grep -rl foo .//. | grep -c //

./* しかし、いくつかの望ましくない副作用があります。

cat ./*

ファイルごとにさらに2文字が追加されるため、引数+環境の最大サイズの制限に早く到達します。また./、出力でレポートされたくない場合があります。のような:

grep foo ./*

出力します:

./a.txt: foobar

の代わりに:

a.txt: foobar

余談

1。コメントでの議論に続いて、ここでそれを拡大しなければならないと感じています。

$ du -hs ./*
0       ./a
12      b
0       ./-c
0       ./foo

上記で、./各ファイルの先頭をマークするということは、各ファイル名の開始位置(で./)と終了位置(./出力の次または最後の前の改行で)を明確に識別できることを意味します。

つまり、の出力とdu ./*は反対にdu -- *)の出力は、スクリプトではそれほど簡単ではありませんが、確実に解析できるということです。

出力が端末に送られるとき、ファイル名があなたをだます多くの方法があります:

  • 制御文字、エスケープシーケンスは、表示方法に影響を与える可能性があります。たとえば\r、カーソルを行の先頭に\b移動し、カーソルを\e[C前後に移動します(ほとんどの端末で)...
  • 多くの文字は、最も明らかな文字であるスペース文字から始まるターミナルでは見えません。
  • ほとんどのフォントのスラッシュとまったく同じように見えるUnicode文字があります

    $ printf '\u002f \u2044 \u2215 \u2571 \u29F8\n'
    /    

    (ブラウザでの動作をご覧ください)。

例:

$ touch x 'x ' $'y\bx' $'x\n0\t.\u2215x' $'y\r0\t.\e[Cx'
$ ln x y
$ du -hs ./*
0       ./x
0       ./x
0       ./x
0       .∕x
0       ./x
0       ./x

たくさんxのが、y不足しています。

GNUls などの一部のツールは、出力が端末に送られたときに、非印刷可能文字を疑問符に置き換えます(ただし(U + 2215)は印刷可能です)。GNU duはサポートしていません。

それらを明らかにする方法があります:

$ ls
x  x   x?0?.∕x  y  y?0?.?[Cx  y?x
$ LC_ALL=C ls
x  x?0?.???x  x   y  y?x  y?0?.?[Cx

文字セットがASCIIであると言っ???後、どのようになったかをご覧くださいls

$ du -hs ./* | LC_ALL=C sed -n l
0\t./x$
0\t./x $
0\t./x$
0\t.\342\210\225x$
0\t./y\r0\t.\033[Cx$
0\t./y\bx$

$行の終わりをマークするので、"x"vs を見つけることができます"x "。すべての非印刷可能文字と非ASCII文字はバックスラッシュシーケンスで表されます(バックスラッシュ自体は2つのバックスラッシュで表されます)。これはGNUでしたがsed、すべてのPOSIX準拠のsed実装で同じであるはずですが、一部の古いsed実装はそれほど有用ではないことに注意してください。

$ du -hs ./* | cat -vte
0^I./x$
0^I./x $
0^I./x$
0^I.M-bM-^HM-^Ux$

(標準ではありませんが、かなり一般的で、cat -A実装もいくつかあります)。その一つは有用であり、異なる表現を使用するがあいまいである("^I"および<TAB>表示インスタンスに対して同じです)。

$ du -hs ./* | od -vtc
0000000   0  \t   .   /   x  \n   0  \t   .   /   x      \n   0  \t   .
0000020   /   x  \n   0  \t   . 342 210 225   x  \n   0  \t   .   /   y
0000040  \r   0  \t   . 033   [   C   x  \n   0  \t   .   /   y  \b   x
0000060  \n
0000061

これは標準的で明確なものであり(実装ごとに一貫性があります)、読みやすいものではありません。

y上記に現れなかったことに気付くでしょう。それは全く無関係だ問題du -hs *それはファイル名とは関係ありませんが、注意する必要がありますので、duレポートのディスク使用量は、それがすでに記載されているファイル(すべてではないに他のリンク報告しないduハードリンクが記載されていたときにかかわらず、実装がそのように振る舞うをコマンドラインで)。


+1、ナイスで徹底的(私が知る限り^^)。「grep -c /」の利点が特に気に入っています。また、注目に値する:「*」に対する「./*」の利点は、Unix FAQ(おそらくfaqs.org。iircの)の(多くの)良い回答の1つに現れます。 「-」)。
オリビエデュラック14年

…そして、名前に改行とタブを含むファイルを持っていること悪い習慣ではありませんか?私が知っている、私はに名前を制限しよう[a-z0-9.+-]
ブラックライトシャイニング14年

5
@BlacklightShining、それは非常にです悪い車を盗むために、それはだ、悪い、それは高価な車(スクリプトは、機密データを持つサーバ上で、特権ユーザーとして実行...)またはときだ場合は特に、(改行を無視する)ロック解除あなたの車を残すために荒いエリア(/tmp)または高価な車がたくさんあるエリア($HOME)に駐車し、Q&Aサイトにアクセスして、どの条件(ロックされたガレージ、スクリプト内)ネットワークまたはリムーバブルストレージに接続されていないマシンでのみ自分で実行したことを書きました...)
StéphaneChazelas 14年

1
@BlacklightShining、改行は珍しいですが、特にGUIで作成されたファイルの場合、埋め込みスペースは最近非常に一般的です。
アレクシス14年

2
@BlacklightShining、はい。ただし、そのような("b "またはのような"a\bb")は端末上のユーザーをだますが、の出力を解析するスクリプトはだましませんdu ./*。おそらくそれについてのメモを追加する必要があります。明日やります。以前、私は一般的な意味で特権を意味していましたrootroot、もちろんそうではありませんでした。改行は許可されますが、無視することはバグです。バグは悪用される傾向があります。ケースバイケースでリスクを測定する必要があります。適切なコーディングを行うと、多くの場合、問題を回避できます。確かにSEでは、意識を高める必要があります。
ステファンシャゼル14年

6

リストするファイルに関して、a *とaの間に違いはありません./*。唯一の違いは2番目の形式で、各ファイルの./前にドットスラッシュが付きます。これは通常、現在のディレクトリを意味します。

.ディレクトリは、現在のディレクトリの略記法であることを忘れないでください。

$ ls -la | head -4
total 28864
drwx------. 104 saml saml    12288 Jan 23 20:04 .
drwxr-xr-x.   4 root root     4096 Jul  8  2013 ..
-rw-rw-r--.   1 saml saml      972 Oct  6 20:26 abcdefg

echoシェルがそれらをどのように展開するかを確認するために使用することにより、これら2つのリストは本質的に同じものであると確信できます。

$ echo *
$ echo ./*

これらの2つのコマンドは、現在のディレクトリ内のすべてのファイルをリストします。

次のような偽データを作成できます。

$ touch file{1..5}
$ ll
total 0
-rw-rw-r--. 1 saml saml 0 Jan 24 07:14 file1
-rw-rw-r--. 1 saml saml 0 Jan 24 07:14 file2
-rw-rw-r--. 1 saml saml 0 Jan 24 07:14 file3
-rw-rw-r--. 1 saml saml 0 Jan 24 07:14 file4
-rw-rw-r--. 1 saml saml 0 Jan 24 07:14 file5

上記のechoコマンドを使用すると、次の出力が表示されます。

$ echo *
file1 file2 file3 file4 file5
$ echo ./*
./file1 ./file2 ./file3 ./file4 ./file5

この違いは不要に思えるかもしれませんが、コマンドラインを介してファイル名を渡すことをさまざまなUnixコマンドラインツールに保証したい場合があります。

では、なぜ./*を使用するのですか?

以下のようステファンの答えのポイントアウト@ Unixの内のファイル&ディレクトリに名前を付けるときに文字が法定されているものの性質のために、危険なファイル名は、それらがコマンドラインでさまざまなUnixのコマンドに渡されているときに、予期しない副作用を持って構築することができます。

その./ため、さまざまなUnixコマンドへの引数として渡されるときに、拡張ファイル名がファイル名と見なされることを保証するために、の使用が頻繁に使用されます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.