hasil ? satu akan menunjukkan Anda ./ di depan nama file
Kiwy
Jawaban:
69
$ 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
Penyimpangan lebih lanjut
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:
Mengontrol karakter, urutan pelarian dapat memengaruhi cara hal-hal ditampilkan. Misalnya, \rmemindahkan kursor ke awal baris, \bmemindahkan kursor ke belakang, \e[Cke depan (di sebagian besar terminal) ...
banyak karakter tidak terlihat pada terminal dimulai dengan yang paling jelas: karakter spasi.
Ada karakter Unicode yang terlihat sama dengan garis miring di sebagian besar font
$ 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.
(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
00000000 \t ./ x \n 0 \t ./ x \n 0 \t .0000020/ x \n 0 \t .342210225 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).
+1, Bagus dan teliti (sejauh yang saya tahu ^^). Saya terutama menyukai keuntungan "grep -c /". Juga patut dicatat: keuntungan dari "./*" over "*" muncul di salah satu (banyak) jawaban baik dari FAQ Unix (mungkin di faqs.org. Iirc, itu ada dalam pertanyaan tentang rm-ing file yang dimulai dengan Sebuah "-").
Olivier Dulac
... dan bukan praktik yang buruk untuk memiliki file dengan baris baru dan tab di namanya? Saya tahu saya mencoba membatasi nama [a-z0-9.+-].
Blacklight Shining
5
@BlacklightShining, itu sangat buruk untuk mencuri mobil, tapi itu buruk untuk meninggalkan mobil Anda membuka (mengabaikan baris), terutama ketika itu sebuah mobil mahal (script berjalan sebagai pengguna istimewa, pada server dengan data sensitif ...) atau ketika Anda parkirlah di tempat yang kasar ( /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 ...)
Stéphane Chazelas
1
@ BlacklightShining, baris baru tidak biasa tetapi ruang tertanam sangat umum saat ini, terutama untuk file yang dibuat melalui GUI.
alexis
2
@ BlacklightShining, ya meskipun yang (suka "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.
Stéphane Chazelas
6
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 12288Jan2320:04.
drwxr-xr-x.4 root root 4096Jul82013..-rw-rw-r--.1 saml saml 972Oct620: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.
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!
Jadi mengapa menggunakan ./*?
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.
Jawaban:
Seperti yang Anda lihat,
-c
file diambil sebagai opsi untukdu
dan tidak dilaporkan (dan Anda melihattotal
baris karenadu -c
). Juga, file yang dipanggila\n12\tb
membuat kita berpikir bahwa ada file yang dipanggila
danb
.Itu lebih baik. Setidaknya saat
-c
ini tidak diambil sebagai opsi.Itu lebih baik. The
./
mencegah awalan-c
dari yang diambil sebagai pilihan dan tidak adanya./
sebelumb
di output menunjukkan bahwa tidak adab
file 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:atau:
Jika
cmd
tidak mendukung--
untuk menandai akhir opsi, Anda harus melaporkannya sebagai bug kepada pembuatnya (kecuali jika itu pilihan dan didokumentasikan seperti untukecho
).Ada kasus di mana
./*
memecahkan masalah yang--
tidak. Contohnya:gagal jika ada file yang dipanggil
a=b.txt
di direktori saat ini (set variabel awka
untukb.txt
bukannya mengatakan untuk memproses file).Tidak memiliki masalah karena
./a
bukan nama variabel awk yang valid, jadi./a=b.txt
tidak diambil sebagai penugasan variabel.gagal jika ada file yang dipanggil
-
dalam direktori saat ini, karena ia memerintahkancat
untuk membaca dari stdin-nya (-
khusus untuk sebagian besar utilitas pemrosesan teks dan kecd
/pushd
).tidak masalah karena
./-
tidak khusus untukcat
.Hal-hal seperti:
untuk menghitung jumlah file yang berisi
foo
salah karena mengasumsikan nama file tidak mengandung karakter baris baru (wc -l
menghitung karakter baris baru, yang dihasilkan olehgrep
untuk setiap file dan orang-orang di nama file itu sendiri). Anda sebaiknya menggunakan:(menghitung jumlah
/
karakter lebih dapat diandalkan karena hanya ada satu per nama file).Untuk rekursif
grep
, trik yang setara adalah menggunakan:./*
mungkin memiliki beberapa efek samping yang tidak diinginkan.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:Akan menghasilkan:
dari pada:
Penyimpangan lebih lanjut
1 . Saya merasa harus mengembangkannya di sini, mengikuti diskusi dalam komentar.
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 daridu -- *
) 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:
\r
memindahkan kursor ke awal baris,\b
memindahkan kursor ke belakang,\e[C
ke depan (di sebagian besar terminal) ...Ada karakter Unicode yang terlihat sama dengan garis miring di sebagian besar font
(lihat bagaimana kelanjutannya di browser Anda).
Sebuah contoh:
Banyak
x
tapiy
tidak ada.Beberapa alat seperti
GNU
ls akan menggantikan karakter yang tidak dapat dicetak dengan tanda tanya (perhatikan bahwa∕
(U + 2215) dapat dicetak) ketika output menuju terminal. GNUdu
tidak.Ada cara untuk membuat mereka mengungkapkan diri mereka sendiri:
Lihat bagaimana
∕
menoleh???
setelah kami memberi tahuls
bahwa rangkaian karakter kami adalah ASCII.$
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 GNUsed
, seharusnya sama di semuased
implementasi yang sesuai dengan POSIX tetapi perhatikan bahwa beberapased
implementasi lama hampir tidak membantu.(tidak standar tetapi cukup umum, juga
cat -A
dengan beberapa implementasi). Yang satu itu membantu dan menggunakan representasi yang berbeda tetapi ambigu ("^I"
dan<TAB>
ditampilkan sama misalnya).Itu standar dan tidak ambigu (dan konsisten dari implementasi ke implementasi) tetapi tidak mudah dibaca.
Anda akan melihat bahwa
y
tidak pernah muncul di atas. Itu masalah yang sama sekali tidak terkait dengandu -hs *
yang tidak ada hubungannya dengan nama file tetapi harus dicatat: karenadu
melaporkan penggunaan disk, itu tidak melaporkan tautan lain ke file yang sudah terdaftar (tidak semuadu
implementasi berperilaku seperti itu meskipun ketika tautan keras terdaftar di baris perintah).sumber
[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 daridu ./*
. Saya mungkin harus menambahkan catatan tentang itu. Akan dilakukan besok. Perhatikan bahwa sebelumnya saya maksudkan hak istimewa dalam arti umum, tidakroot
(meskipun berlakuroot
tentu 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.Anda dapat meyakinkan diri sendiri bahwa 2 daftar ini pada dasarnya adalah hal yang sama dengan menggunakan
echo
untuk melihat apa shell akan mengembangkannya.2 perintah ini akan mencantumkan semua file di direktori Anda saat ini.
Contohnya
Kami dapat membuat beberapa data palsu seperti:
Sekarang ketika kita menggunakan
echo
perintah di atas kita melihat output berikut: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!
Jadi mengapa menggunakan ./*?
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.sumber