Jaký je rozdíl mezi du -sh * a du -sh ./* ?
Poznámka:Co mě zajímá, je * a ./* části.
Přijatá odpověď:
$ touch ./-c $'an12tb' foo $ du -hs * 0 a 12 b 0 foo 0 total
Jak můžete vidět, -c soubor byl použit jako možnost du a není hlášeno (a vidíte total řádek kvůli du -c ). Také soubor s názvem an12tb nás nutí si myslet, že existují soubory zvané a a b .
$ du -hs -- *
0 a
12 b
0 -c
0 foo
To je lepší. Tentokrát alespoň -c není brána jako možnost.
$ du -hs ./*
0 ./a
12 b
0 ./-c
0 ./foo
to je ještě lepší. ./ prefix zabraňuje -c z toho, že je brána jako možnost, a absence ./ před b ve výstupu označuje, že není žádné b soubor tam, ale je tam soubor se znakem nového řádku (ale další odbočky k tomu viz níže).
Je dobrým zvykem používat ./ prefix, pokud je to možné, a pokud ne, a pro libovolná data, měli byste vždy použití:
cmd -- "$var"
nebo:
cmd -- $patterns
Pokud cmd nepodporuje -- chcete-li označit konec možností, měli byste to nahlásit jako chybu jejímu autorovi (kromě případů, kdy je to na vlastní žádost a zdokumentováno jako u echo ).
Existují případy, kdy ./* řeší problémy, které -- ne Například:
awk -f file.awk -- *
selže, pokud existuje soubor s názvem a=b.txt v aktuálním adresáři (nastavuje proměnnou awk a do b.txt místo toho, aby mu řekl, aby soubor zpracoval).
awk -f file.awk ./*
Nemá problém, protože ./a není platný název proměnné awk, takže ./a=b.txt se nebere jako přiřazení proměnné.
cat -- * | wc -l
selže, pokud existuje soubor s názvem - v aktuálním adresáři, jak to říká cat číst z jeho stdin (- je speciální pro většinu nástrojů pro zpracování textu a pro cd /pushd ).
cat ./* | wc -l
je v pořádku, protože ./- není speciální pro cat .
Věci jako:
grep -l -- foo *.txt | wc -l
spočítat počet souborů, které obsahují foo jsou chybné, protože předpokládá, že názvy souborů neobsahují znaky nového řádku (wc -l počítá znaky nového řádku, které vypíše grep pro každý soubor a soubory v samotných názvech souborů). Místo toho byste měli použít:
grep -l foo ./*.txt | grep -c /
(počítá se počet / znaků je spolehlivější, protože pro každý soubor může být pouze jeden).
Pro rekurzivní grep , ekvivalentní trik je použít:
grep -rl foo .//. | grep -c //
./* může mít některé nežádoucí vedlejší účinky.
cat ./*
přidá dva další znaky na soubor, takže byste dříve dosáhli limitu maximální velikosti argumentů + prostředí. A to někdy nechcete ./ vykazovat ve výstupu. Jako:
grep foo ./*
Výstup:
./a.txt: foobar
místo:
a.txt: foobar
Další odbočky
. Cítím, že to zde musím rozvést a sledovat diskuzi v komentářích.
$ du -hs ./*
0 ./a
12 b
0 ./-c
0 ./foo
Nad tím ./ označení začátku každého souboru znamená, že můžeme jasně identifikovat, kde každý název souboru začíná (na ./ ) a kde končí (na novém řádku před dalším ./ nebo konec výstupu).
To znamená, že výstup du ./* , na rozdíl od du -- * ) lze spolehlivě analyzovat, i když ne tak snadno ve skriptu.
Když výstup jde do terminálu, existuje mnoho dalších způsobů, jak vás název souboru může oklamat:
-
Ovládací znaky, escape sekvence mohou ovlivnit způsob zobrazení věcí. Například
rpřesune kurzor na začátek řádku,bpřesune kurzor zpět,e[Cvpřed (ve většině terminálů)… -
mnoho znaků je na terminálu neviditelných, počínaje tím nejviditelnějším:znakem mezery.
-
Existují znaky Unicode, které vypadají stejně jako lomítko ve většině písem
$ printf 'u002f u2044 u2215 u2571 u29F8n' / ⁄ ∕ ╱ ⧸
(podívejte se, jak to chodí ve vašem prohlížeči).
Příklad:
$ touch x 'x ' $'ybx' $'xn0t.u2215x' $'yr0t.e[Cx'
$ ln x y
$ du -hs ./*
0 ./x
0 ./x
0 ./x
0 .∕x
0 ./x
0 ./x
Spousta x ‘s but y chybí.
Některé nástroje jako GNU ls by nahradilo netisknutelné znaky otazníkem (všimněte si, že ∕ (U+2215) lze tisknout), když výstup jde na terminál. GNU du ne.
Existují způsoby, jak je přimět, aby se odhalily:
$ 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
Podívejte se, jak ∕ obrátil na ??? poté, co jsme řekli ls že naše znaková sada byla ASCII.
$ du -hs ./* | LC_ALL=C sed -n l0t./x$0t./x $0t./x$0t.342210225x$0t./rok0t.
Linux