Jawaban:
$ touch ./-c $ 'a \ n12 \ tb' foo $ du -hs * 0 a 12 b 0 foo 0 total
Seperti yang Anda lihat, -cfile diambil sebagai opsi untuk dudan tidak dilaporkan (dan Anda melihat totalbaris karena du -c). Juga, file yang dipanggil a\n12\tbmembuat kita berpikir bahwa ada file yang dipanggil adan b.
$ du -hs -- *
0 a
12 b
0 -c
0 foo
Itu lebih baik. Setidaknya saat -cini tidak diambil sebagai opsi.
$ du -hs ./*
0 ./a
12 b
0 ./-c
0 ./foo
Itu lebih baik. The ./mencegah awalan -cdari yang diambil sebagai pilihan dan tidak adanya ./sebelum bdi output menunjukkan bahwa tidak ada bfile dalam sana, tapi ada file dengan karakter baris baru (tapi lihat di bawah 1 untuk penyimpangan lebih lanjut tentang itu).
Sebaiknya gunakan ./awalan jika memungkinkan, dan jika tidak dan untuk data yang berubah-ubah, Anda harus selalu menggunakan:
cmd -- "$var"
atau:
cmd -- $patterns
Jika cmdtidak mendukung --untuk menandai akhir opsi, Anda harus melaporkannya sebagai bug kepada pembuatnya (kecuali jika itu pilihan dan didokumentasikan seperti untuk echo).
Ada kasus di mana ./*memecahkan masalah yang --tidak. Contohnya:
awk -f file.awk -- *
gagal jika ada file yang dipanggil a=b.txtdi direktori saat ini (set variabel awk auntuk b.txtbukannya mengatakan untuk memproses file).
awk -f file.awk ./*
Tidak memiliki masalah karena ./abukan nama variabel awk yang valid, jadi ./a=b.txttidak diambil sebagai penugasan variabel.
cat -- * | wc -l
gagal jika ada file yang dipanggil -dalam direktori saat ini, karena ia memerintahkan catuntuk membaca dari stdin-nya ( -khusus untuk sebagian besar utilitas pemrosesan teks dan ke cd/ pushd).
cat ./* | wc -l
tidak masalah karena ./-tidak khusus untuk cat.
Hal-hal seperti:
grep -l -- foo *.txt | wc -l
untuk menghitung jumlah file yang berisi foosalah karena mengasumsikan nama file tidak mengandung karakter baris baru ( wc -lmenghitung karakter baris baru, yang dihasilkan oleh grepuntuk setiap file dan orang-orang di nama file itu sendiri). Anda sebaiknya menggunakan:
grep -l foo ./*.txt | grep -c /
(menghitung jumlah /karakter lebih dapat diandalkan karena hanya ada satu per nama file).
Untuk rekursif grep, trik yang setara adalah menggunakan:
grep -rl foo .//. | grep -c //
./* mungkin memiliki beberapa efek samping yang tidak diinginkan.
cat ./*
menambahkan dua karakter lebih per file, sehingga akan membuat Anda mencapai batas ukuran maksimum argumen + lingkungan lebih cepat. Dan kadang-kadang Anda tidak ingin itu ./dilaporkan dalam output. Seperti:
grep foo ./*
Akan menghasilkan:
./a.txt: foobar
dari pada:
a.txt: foobar
1 . Saya merasa harus mengembangkannya di sini, mengikuti diskusi dalam komentar.
$ du -hs ./*
0 ./a
12 b
0 ./-c
0 ./foo
Di atas, yang ./menandai awal setiap file berarti kita dapat dengan jelas mengidentifikasi di mana setiap nama file dimulai (di ./) dan di mana itu berakhir (di baris baru sebelum berikutnya ./atau akhir output).
Artinya adalah bahwa output dari du ./*, berlawanan dengan dari du -- *) dapat diurai dengan andal, meskipun tidak dengan mudah dalam sebuah skrip.
Ketika output masuk ke terminal, ada banyak cara nama file yang bisa menipu Anda:
\rmemindahkan kursor ke awal baris, \bmemindahkan kursor ke belakang, \e[Cke depan (di sebagian besar terminal) ...Ada karakter Unicode yang terlihat sama dengan garis miring di sebagian besar font
$ printf '\u002f \u2044 \u2215 \u2571 \u29F8\n'
/ ⁄ ∕ ╱ ⧸
(lihat bagaimana kelanjutannya di browser Anda).
Sebuah contoh:
$ 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
Banyak xtapi ytidak ada.
Beberapa alat seperti GNUls akan menggantikan karakter yang tidak dapat dicetak dengan tanda tanya (perhatikan bahwa ∕(U + 2215) dapat dicetak) ketika output menuju terminal. GNU dutidak.
Ada cara untuk membuat mereka mengungkapkan diri mereka sendiri:
$ 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 bagaimana ∕menoleh ???setelah kami memberi tahu lsbahwa rangkaian karakter kami adalah ASCII.
$ 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$
$menandai akhir dari baris, sehingga kita dapat melihat "x"vs "x ", semua karakter yang tidak dapat dicetak dan karakter non-ASCII diwakili oleh urutan backslash (backslash sendiri akan diwakili dengan dua backslash) yang berarti tidak ambigu. Itu adalah GNU sed, seharusnya sama di semua sedimplementasi yang sesuai dengan POSIX tetapi perhatikan bahwa beberapa sedimplementasi lama hampir tidak membantu.
$ du -hs ./* | cat -vte
0^I./x$
0^I./x $
0^I./x$
0^I.M-bM-^HM-^Ux$
(tidak standar tetapi cukup umum, juga cat -Adengan beberapa implementasi). Yang satu itu membantu dan menggunakan representasi yang berbeda tetapi ambigu ( "^I"dan <TAB>ditampilkan sama misalnya).
$ 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
Itu standar dan tidak ambigu (dan konsisten dari implementasi ke implementasi) tetapi tidak mudah dibaca.
Anda akan melihat bahwa ytidak pernah muncul di atas. Itu masalah yang sama sekali tidak terkait dengan du -hs *yang tidak ada hubungannya dengan nama file tetapi harus dicatat: karena dumelaporkan penggunaan disk, itu tidak melaporkan tautan lain ke file yang sudah terdaftar (tidak semua duimplementasi berperilaku seperti itu meskipun ketika tautan keras terdaftar di baris perintah).
[a-z0-9.+-].
/tmp) atau area dengan banyak mobil mahal ( $HOME) dan bahkan lebih buruk untuk pergi ke situs T&J dan mengatakan itu selalu baik-baik saja untuk tidak mengunci mobil Anda tanpa menentukan dalam kondisi apa (di garasi yang terkunci, skrip Anda menulis dijalankan sendiri hanya pada mesin yang tidak terhubung ke jaringan apa pun atau penyimpanan yang dapat dilepas ...)
"b "atau "a\bb") akan membodohi pengguna pada terminal tetapi bukan skrip yang mem-parsing output dari du ./*. Saya mungkin harus menambahkan catatan tentang itu. Akan dilakukan besok. Perhatikan bahwa sebelumnya saya maksudkan hak istimewa dalam arti umum, tidak root(meskipun berlaku roottentu saja semua lebih ). baris baru diizinkan, mengabaikannya adalah bug. bug memiliki kebiasaan dieksploitasi. Anda harus mengukur risiko berdasarkan kasus per kasus. Praktek pengkodean yang baik dapat menghindari masalah dalam banyak kasus. Tentu saja di SE, kita harus meningkatkan kesadaran.
Tidak ada perbedaan antara a *dan ./*dalam hal file apa yang akan dicantumkan. Satu-satunya perbedaan adalah dengan bentuk ke-2, setiap file akan memiliki ./awalan titik slash di depannya, yang biasanya berarti direktori saat ini.
Ingat bahwa .direktori adalah notasi singkat untuk direktori saat ini.
$ 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
Anda dapat meyakinkan diri sendiri bahwa 2 daftar ini pada dasarnya adalah hal yang sama dengan menggunakan echountuk melihat apa shell akan mengembangkannya.
$ echo *
$ echo ./*
2 perintah ini akan mencantumkan semua file di direktori Anda saat ini.
Kami dapat membuat beberapa data palsu seperti:
$ 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
Sekarang ketika kita menggunakan echoperintah di atas kita melihat output berikut:
$ echo *
file1 file2 file3 file4 file5
$ echo ./*
./file1 ./file2 ./file3 ./file4 ./file5
Perbedaan ini mungkin tampak tidak perlu tetapi ada situasi di mana Anda ingin menjamin ke berbagai alat baris perintah Unix yang Anda berikan nama file kepada mereka melalui baris perintah, dan tidak lebih!
Seperti yang dijawab oleh @ Stephane , karena sifat karakter apa yang legal ketika menamai file & direktori di Unix, nama file berbahaya dapat dibangun yang memiliki efek samping yang tidak terduga ketika mereka diteruskan ke berbagai perintah Unix di baris perintah.
Begitu sering penggunaan ./akan digunakan untuk membantu menjamin bahwa nama file yang diperluas dianggap sebagai nama file ketika diteruskan sebagai argumen untuk berbagai perintah Unix.