Apa perbedaan antara du -sh *
dan du -sh ./*
?
Catatan:Yang menarik bagi saya adalah *
dan ./*
bagian.
Jawaban yang Diterima:
$ touch ./-c $'an12tb' foo $ du -hs * 0 a 12 b 0 foo 0 total
Seperti yang Anda lihat, -c
file diambil sebagai opsi untuk du
dan tidak dilaporkan (dan Anda melihat total
baris karena du -c
). Juga, file bernama an12tb
membuat kami berpikir bahwa ada file bernama a
dan b
.
$ du -hs -- *
0 a
12 b
0 -c
0 foo
Itu lebih baik. Setidaknya kali ini -c
tidak diambil sebagai pilihan.
$ du -hs ./*
0 ./a
12 b
0 ./-c
0 ./foo
Itu lebih baik. ./
awalan mencegah -c
dari diambil sebagai opsi dan tidak adanya ./
sebelum b
di output menunjukkan bahwa tidak ada b
file di sana, tetapi ada file dengan karakter baris baru (tetapi lihat di bawah untuk penyimpangan lebih lanjut tentang itu).
Ini adalah praktik yang baik untuk menggunakan ./
awalan jika memungkinkan, dan jika tidak, dan untuk data arbitrer, Anda harus selalu gunakan:
cmd -- "$var"
atau:
cmd -- $patterns
Jika cmd
tidak mendukung --
untuk menandai akhir opsi, Anda harus melaporkannya sebagai bug kepada pembuatnya (kecuali jika itu karena pilihan dan didokumentasikan seperti untuk echo
).
Ada kasus di mana ./*
memecahkan masalah yang --
tidak. Misalnya:
awk -f file.awk -- *
gagal jika ada file bernama a=b.txt
di direktori saat ini (mengatur variabel awk a
ke b.txt
alih-alih menyuruhnya memproses file).
awk -f file.awk ./*
Tidak ada masalah karena ./a
bukan nama variabel awk yang valid, jadi ./a=b.txt
tidak diambil sebagai tugas variabel.
cat -- * | wc -l
gagal jika ada file bernama -
di direktori saat ini, seperti yang memberitahu cat
untuk membaca dari stdinnya (-
khusus untuk sebagian besar utilitas pemrosesan teks dan untuk cd
/pushd
).
cat ./* | wc -l
tidak apa-apa karena ./-
tidak khusus untuk cat
.
Hal-hal seperti:
grep -l -- foo *.txt | wc -l
untuk menghitung jumlah file yang berisi foo
salah karena menganggap nama file tidak mengandung karakter baris baru (wc -l
menghitung karakter baris baru, yang dihasilkan oleh grep
untuk setiap file dan yang ada dalam nama file itu sendiri). Anda harus menggunakan sebagai gantinya:
grep -l foo ./*.txt | grep -c /
(menghitung jumlah /
karakter lebih dapat diandalkan karena hanya ada satu per nama file).
Untuk grep
rekursif , trik yang setara adalah dengan menggunakan:
grep -rl foo .//. | grep -c //
./*
mungkin memiliki beberapa efek samping yang tidak diinginkan.
cat ./*
menambahkan dua karakter lagi per file, sehingga akan membuat Anda mencapai batas ukuran maksimum argumen+lingkungan lebih cepat. Dan terkadang Anda tidak menginginkan ./
itu untuk dilaporkan dalam output. Seperti:
grep foo ./*
Akan menghasilkan:
./a.txt: foobar
bukannya:
a.txt: foobar
Penyimpangan lebih lanjut
. Saya merasa harus mengembangkannya di sini, mengikuti diskusi di komentar.
$ du -hs ./*
0 ./a
12 b
0 ./-c
0 ./foo
Di atas, ./
. itu menandai awal setiap file berarti kita dapat dengan jelas mengidentifikasi di mana setiap nama file dimulai (di ./
) dan di mana ia berakhir (di baris baru sebelum ./
next berikutnya atau akhir keluaran).
Artinya adalah output dari du ./*
, bertentangan dengan du -- *
) dapat diuraikan dengan andal, meskipun tidak semudah itu dalam skrip.
Namun, ketika output masuk ke terminal, ada banyak cara lain yang dapat menipu Anda dengan nama file:
-
Karakter kontrol, urutan pelarian dapat memengaruhi cara sesuatu ditampilkan. Misalnya,
r
memindahkan kursor ke awal baris,b
memindahkan kursor kembali,e[C
maju (di sebagian besar terminal)… -
banyak karakter yang tidak terlihat di terminal dimulai dengan yang paling jelas:karakter spasi.
-
Ada karakter Unicode yang terlihat sama seperti garis miring di sebagian besar font
$ printf 'u002f u2044 u2215 u2571 u29F8n' / ⁄ ∕ ╱ ⧸
(lihat bagaimana hasilnya di browser Anda).
Contoh:
$ 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
Banyak x
tapi y
hilang.
Beberapa alat seperti GNU
ls akan mengganti karakter yang tidak dapat dicetak dengan tanda tanya (perhatikan bahwa ∕
(U+2215) dapat dicetak) ketika output masuk ke terminal. GNU du
tidak.
Ada beberapa cara untuk membuat mereka menampakkan diri:
$ 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
Lihat caranya ∕
beralih ke ???
setelah kami memberi tahu ls
bahwa set karakter kita adalah ASCII.
$ du -hs ./* | LC_ALL=C sed -n l0t./x$0t./x $0t./x$0t.342210225x$0t./thn0t.
Linux