du -sh *
とdu -sh ./*
の違いは何ですか?
注:興味があるのは*
と./*
の部分です。
$ touch ./-c $ 'a\n12\tb' foo $ du -hs * 0 a 12 b 0 foo 合計0
ご覧のように、-c
ファイルはdu
のオプションとして取得されたため報告されません(du -c
のためにtotal
行が表示されます)。また、a\n12\tb
というファイルは、a
およびb
というファイルがあると考えさせています。
$ 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 さらなる補足については)。
可能な場合は./
接頭辞を使用することをお勧めします。そうでない場合、および任意のデータの場合は、alwaysを使用する必要があります。
cmd -- "$var"
または:
cmd -- $patterns
cmd
がオプションの終わりを示す--
をサポートしていない場合は、そのバグを作成者にバグとして報告する必要があります(ただし、選択によりecho
のように文書化されている場合は除きます)。
./*
が--
が解決しない問題を解決する場合があります。例えば:
awk -f file.awk -- *
現在のディレクトリにa=b.txt
というファイルがある場合は失敗します(ファイルを処理するように指示するのではなく、awk変数a
をb.txt
に設定します)。
awk -f file.awk ./*
./a
は有効なawk変数名ではないため、問題はありません。したがって、./a=b.txt
は変数の割り当てとして使用されません。
cat -- * | wc -l
現在のディレクトリに-
というファイルがあると失敗します。これは、cat
にstdinから読み取るように指示します(-
は、ほとんどのテキスト処理ユーティリティとcd
/pushd
に特別です)。
cat ./* | wc -l
./-
はcat
にとって特別ではないため、問題ありません。
のようなもの:
grep -l -- foo *.txt | wc -l
foo
を含むファイルの数をカウントするのは間違っています。これは、ファイル名に改行文字が含まれていないと想定しているためです(wc -l
は、改行文字、各ファイルのgrep
によって出力された文字、およびファイル名自体の改行文字をカウントします)。代わりに使用する必要があります:
grep -l foo ./*.txt | grep -c /
(/
文字の数を数えると、ファイル名ごとに1つしか存在できないため、より信頼性が高くなります)。
再帰的な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
がありません。
GNU
lsのような一部のツールは、出力が端末に送信されると、印刷不可能な文字を疑問符に置き換えます(ただし、∕
(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"
と"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
が上に表示されたことはありません。これは完全に無関係ですissue with du -hs *
これはファイル名とは関係ありませんが、注意する必要があります:du
はディスク使用量を報告するため、すでにリストされているファイルへの他のリンクは報告しません(すべてのdu
実装がそのように動作するわけではありませんが、ハードリンクがコマンドラインにリストされている場合)。
*
と./*
は、どちらのファイルをリストするかという点で違いはありません。唯一の違いは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
これら2つのリストは、echo
を使用してシェルが展開する対象を確認することで、基本的に同じものであると確信できます。
$ 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コマンドラインツールに、コマンドラインを介してファイル名を渡すことを保証したい場合があります。
@ Stephaneの回答が指摘 のように、Unixでファイルとディレクトリに名前を付けるときに有効な文字の性質により、さまざまなUnixコマンドに渡されると予期しない副作用が発生する危険なファイル名が作成される可能性がありますコマンドラインで。
したがって、./
の使用は、さまざまなUnixコマンドに引数として渡されたときに、拡張されたファイル名がファイル名と見なされることを保証するために使用されます。