Apa perbedaan antara "du -sh *" dan "du -sh ./*"?


26

Apa perbedaan antara du -sh *dan du -sh ./*?

Catatan: Yang menarik minat saya adalah bagian *dan ./*.


2
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

    $ 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).


+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    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.

Contohnya

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!

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.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.