回答:
$ touch ./-c $ 'a \ n12 \ tb' foo $ du -hs * 0 a 12 b 0 foo 合計0
ご覧のとおり、-c
ファイルはオプションとして使用されたものであり、du
報告されていません(およびのtotal
ために行が表示されますdu -c
)。また、と呼ばれるファイルには、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、その上さらに脱線のため)。
./
可能な場合はプレフィックスを使用することをお勧めします。使用しない場合、および任意のデータの場合は、常に使用する必要があります。
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
不足しています。
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"
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
ハードリンクが記載されていたときにかかわらず、実装がそのように振る舞うをコマンドラインで)。
[a-z0-9.+-]
。
/tmp
)または高価な車がたくさんあるエリア($HOME
)に駐車し、Q&Aサイトにアクセスして、どの条件(ロックされたガレージ、スクリプト内)ネットワークまたはリムーバブルストレージに接続されていないマシンでのみ自分で実行したことを書きました...)
"b "
またはのような"a\bb"
)は端末上のユーザーをだますが、の出力を解析するスクリプトはだましませんdu ./*
。おそらくそれについてのメモを追加する必要があります。明日やります。以前、私は一般的な意味で特権を意味していましたroot
がroot
、もちろんそうではありませんでした。改行は許可されますが、無視することはバグです。バグは悪用される傾向があります。ケースバイケースでリスクを測定する必要があります。適切なコーディングを行うと、多くの場合、問題を回避できます。確かにSEでは、意識を高める必要があります。
リストするファイルに関して、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コマンドへの引数として渡されるときに、拡張ファイル名がファイル名と見なされることを保証するために、の使用が頻繁に使用されます。