Hasil dari ls *, ls ** dan ls ***

86

Saya tahu menggunakan perintah lsakan mencantumkan semua direktori. Tetapi apa yang dilakukan ls *perintah itu? Saya menggunakannya dan itu hanya daftar direktori. Apakah bintang di depan lsberarti seberapa dalam ia dapat mendaftar direktori?

Andy M
sumber

Jawaban:

155

lsdaftar file dan isi direktori yang dilewatkan sebagai argumen, dan jika tidak ada argumen yang diberikan, daftar direktori saat ini. Itu juga dapat melewati sejumlah opsi yang memengaruhi perilakunya (lihat man lsdetailnya).

Jika lssedang melewati argumen yang disebut *, itu akan mencari file atau direktori yang dipanggil *dalam direktori saat ini dan daftar seperti yang lain. lstidak memperlakukan *karakter dengan cara lain selain yang lain.

Namun jika ls *adalah baris perintah shell , maka shell akan memperluas yang *sesuai dengan globbing shell yang sesuai (juga disebut sebagai Generasi Nama File atau Perluasan Nama File ).

Sementara cangkang yang berbeda mendukung operator globbing yang berbeda, kebanyakan dari mereka menyetujui yang paling sederhana *. *sebagai pola berarti jumlah karakter, sehingga *sebagai globakan memperluas ke daftar file dalam direktori saat ini yang cocok dengan pola itu. Namun ada pengecualian bahwa karakter titik ( .) di nama file harus dicocokkan secara eksplisit, jadi *sebenarnya diperluas ke daftar file dan direktori yang tidak dimulai dengan .(dalam urutan leksikografis).

Misalnya, jika direktori saat ini berisi file yang disebut ., .., .foo, -ldan foo bar, *akan diperluas oleh shell untuk dua argumen untuk lolos ke ls: -ldan foo bar, sehingga akan menjadi seperti jika Anda telah mengetik:

ls -l "foo bar"

atau

'ls' "-l" foo\ bar

Yang mana tiga cara untuk menjalankan perintah yang persis sama. Dalam semua 3 kasus, lsperintah (yang mungkin akan dieksekusi dari /bin/lspencarian direktori yang disebutkan dalam $PATH) akan melewati 3 argumen: "ls", "-l" dan "foo bar".

Kebetulan, dalam hal ini, lsakan memperlakukan yang pertama (secara tegas kedua ) sebagai pilihan.

Sekarang, seperti yang saya katakan, shell yang berbeda memiliki operator globbing yang berbeda. Beberapa dekade yang lalu, zshmemperkenalkan **/operator¹ yang berarti untuk mencocokkan setiap tingkat subdirektori, kependekan dari (*/)#dan ***/yang sama kecuali bahwa ia mengikuti symlinks saat turun direktori.

Beberapa tahun yang lalu (Juli 2003, ksh93o+), ksh93memutuskan untuk menyalin perilaku itu tetapi memutuskan untuk menjadikannya opsional, dan hanya membahas **kasus (tidak ***). Juga, sementara **sendirian tidak istimewa zsh(hanya berarti sama *seperti di shell tradisional lainnya karena **berarti sejumlah karakter diikuti oleh sejumlah karakter), di ksh93, **berarti sama dengan **/*(sehingga file atau direktori di bawah yang sekarang) (tidak termasuk file tersembunyi).

bashdisalin ksh93beberapa tahun kemudian (Februari 2009, bash 4.0), dengan sintaksis yang sama tetapi perbedaan yang disayangkan: bash's **seperti zsh's ***, yaitu mengikuti symlink ketika berulang ke sub-direktori yang umumnya tidak seperti yang Anda inginkan dan dapat memiliki efek samping yang buruk. Itu sebagian diperbaiki di bash-4.3 bahwa symlink masih diikuti, tetapi rekursi berhenti di sana. Itu sepenuhnya diperbaiki di 5.0.

yashditambahkan **dalam versi 2.0 pada 2008, diaktifkan dengan extended-globopsi. Implementasinya lebih dekat dengan zshitu **saja tidak istimewa. Dalam versi 2.15 (2009), ia menambahkan ***seperti dalam zshdan dua ekstensi sendiri: .**dan .***untuk memasukkan dir tersembunyi ketika berulang (dalam zsh, D kualifikasi glob (seperti dalam **/*(D)) akan mempertimbangkan file dan direktori tersembunyi, tetapi jika Anda hanya ingin melintasi tersembunyi dir tetapi tidak memperluas file tersembunyi, Anda perlu ((*|.*)/)#*atau **/[^.]*(D)).

The shell ikan juga mendukung **. Seperti versi sebelumnya bash, ia mengikuti symlink ketika turun pohon direktori. Namun dalam shell **/*itu tidak sama dengan **. **lebih merupakan perpanjangan dari *yang dapat menjangkau beberapa direktori. Dalam fish, **/*.cakan cocok a/b/c.ctetapi tidak a.c, sementara a**.cakan cocok a.cdan ab/c/d.cdan zsh's **/.*misalnya harus ditulis .* **/.*. Di sana, ***dipahami sebagai **diikuti oleh *sama dengan **.

tcshjuga menambahkan globstaropsi di V6.17.01 (Mei 2010) dan mendukung keduanya **dan ***à la zsh.

Jadi dalam tcsh, bashdan ksh93, (ketika opsi yang sesuai diaktifkan ( globstar)) atau fish, **memperluas semua file dan direktori di bawah satu saat, dan ***adalah sama seperti **untuk fish, symlink melintasi **untuk tcshdengan globstar, dan sama seperti *di bashdan ksh93(meskipun itu bukan tidak mungkin bahwa versi masa depan dari shell tersebut juga akan melintasi symlinks).

Di atas, Anda akan memperhatikan kebutuhan untuk memastikan tidak ada ekspansi yang ditafsirkan sebagai opsi. Untuk itu, Anda akan melakukan:

ls -- *

Atau:

ls ./*

Ada beberapa perintah (tidak masalah untuk ls) di mana yang kedua lebih disukai karena bahkan dengan --beberapa nama file dapat diperlakukan secara khusus. Ini merupakan kasus -untuk sebagian besar utilitas teks, cddan pushddan nama file yang mengandung =karakter awkmisalnya. Bergantung ./pada semua argumen menghilangkan makna khusus mereka (setidaknya untuk kasus yang disebutkan di atas).

Perlu juga dicatat bahwa kebanyakan shell memiliki sejumlah opsi yang memengaruhi perilaku globbing (seperti apakah file dot diabaikan atau tidak, urutan pengurutan, apa yang harus dilakukan jika tidak ada kecocokan ...), lihat juga $FIGNOREparameter dalamksh

Juga, di setiap shell tetapi csh, tcsh, fishdan zsh, jika pola globbing tidak cocok file apapun, pola dilewatkan sebagai argumen unexpanded yang menyebabkan kebingungan dan mungkin bug. Misalnya, jika tidak ada file tidak tersembunyi di direktori saat ini

ls *

Akan benar-benar memanggil lsdengan dua argumen lsdan *. Dan karena tidak ada file sama sekali, sehingga tidak ada yang disebut *baik, Anda akan melihat pesan kesalahan dari ls (bukan shell) seperti:, ls: cannot access *: No such file or directoryyang telah diketahui membuat orang berpikir bahwa itu lssebenarnya yang memperluas gumpalan.

Masalahnya bahkan lebih buruk dalam kasus-kasus seperti:

rm -- *.[ab]

Jika tidak ada *.aatau *.bfile dalam direktori saat ini, maka Anda mungkin berakhir menghapus file yang disebut *.[ab]oleh kesalahan ( csh, tcsh, dan zshakan melaporkan tidak cocok kesalahan dan tidak akan menyebut rm(dan fishtidak mendukung [...]wildcard)).

Jika Anda ingin meneruskan suatu literal *ke ls, Anda harus mengutip *karakter itu dalam beberapa cara seperti dalam ls \*atau ls '*'atau ls "*". Dalam cangkang mirip POSIX, globbing dapat dinonaktifkan sama sekali menggunakan set -o noglobatau set -f(yang terakhir tidak berfungsi zshkecuali dalam sh/ kshemulation).


¹ Meskipun (*/)#selalu didukung, pertama kali menggunakan tangan pendek seperti ..../pada zsh-2.0 (dan berpotensi sebelum), kemudian ****/pada 2.1 sebelum mendapatkan bentuk definitifnya **/di 2.2 (awal 1992)

Stéphane Chazelas
sumber
22
Jawaban yang sangat bagus!
Andrea Corbellini
7
Contoh bagus lainnya adalah find -name *. Terutama dengan pola yang lebih kompleks, jika ada satu kecocokan di direktori saat ini, orang-orang akan sering tidak menyadari bahwa mereka tidak memberikan tanda bintang find.
njsg
Saya terus memberi +1, saya sangat senang melihat Stephane Chazelas aktif di sini di unix.stackexchange.com ! Kontribusi luar biasa, Stephane, seperti biasa!
Dimitre Radoulov
1
Pada ikan, *.[ab]akan mencoba untuk menghapus semua yang diakhiri dengan .[ab]. [tidak istimewa pada ikan.
Konrad Borowski
35

Perintah lsdefault untuk ls .: Daftar semua entri dalam direktori saat ini .

Perintah itu ls *berarti 'jalankan ls pada perluasan *pola shell'

The *Pola diproses oleh shell, dan memperluas ke semua entri dalam direktori saat ini, kecuali mereka yang memulai dengan .. Ini akan naik satu level.

Interpretasi *pola double atau triple tergantung pada shell aktual yang digunakan.

*adalah wildcard yang cocok dengan 0 karakter atau lebih. Beberapa shell modern akan muncul kembali menjadi subdirektori saat melihat **polanya.

Dennis Kaarsemaker
sumber
17
Kecuali ekstra * melakukan menambahkan sesuatu, lihat jawaban lain menjelaskan globstar tersebut. Harus juga diperjelas bahwa tidak ada hubungannya dengan tanda bintang, tidak pernah melewati tanda bintang ini sama sekali. Jalankan echo ls *untuk melihat apa yang akan dieksekusi ketika Anda menulis ls *.
njsg
12

Anda dapat menghilangkan mitos seluruh proses dengan mengetik echoalih-alih lsterlebih dahulu, untuk melihat apa yang diperlebar perintah:

$ echo *
Applications Downloads Documents tmp.html

Jadi dalam hal ini, ls *perluasls Applications Downloads Documents tmp.html

$ echo **
Applications Downloads Documents tmp.html

$ echo ***
Applications Downloads Documents tmp.html

Jadi tidak ada perubahan. Ini mengasumsikan Anda menggunakan bashshell Anda - kebanyakan orang, dan shell berbeda memiliki perilaku yang berbeda. Jika Anda menggunakan ashatau cshatau kshatau zsh, Anda mungkin mengharapkan berbagai hal bekerja secara berbeda. Itulah gunanya memiliki cangkang yang berbeda.

Jadi mari kita coba sesuatu yang berbeda (masih dengan bash) sehingga kita mendapatkan gagasan tentang *operator globbing ( ) dapat lakukan untuk kita. Misalnya, kita dapat memfilter berdasarkan nama:

$ echo D*
Downloads Documents

Dan yang menarik, garis miring adalah bagian yang tersirat dari nama direktori. Jadi */hanya akan menghasilkan direktori (dan tautan simbolik ke direktori):

$ echo */
Applications/ Downloads/ Documents/

Dan kita bisa melakukan beberapa penyaringan di beberapa level dengan meletakkan garis miring di tengah:

$ echo D*/*/
Documents/Work/ /Documents/unfinished/

Karena Downloadsdirektori tidak mengandung subdirektori apa pun, itu tidak berakhir pada output. Ini sangat berguna untuk hanya memeriksa file yang Anda inginkan. Saya menggunakan perintah seperti ini setiap saat:

$ ls -l /home/*/public_html/wp-config.php

Daftar ini, jika ada, semua wp-config.phpfile yang ada di tingkat dasar public_htmldirektori pengguna mana pun . Atau mungkin lebih lengkap:

$ find /home/*/public_html/ -name wp-config.php

Ini akan menemukan wp-config.phpfile dalam setiap pengguna public_htmldirektori atau subdirektori mereka, tetapi akan beroperasi lebih efisien daripada hanya find /home/ -name wp-config.phpkarena tidak akan memeriksa apa-apa tapi yang public_htmldirektori untuk masing-masing pengguna.

tylerl
sumber
1
"Ini mengasumsikan Anda menggunakan bashshell Anda" ← dan globstar tidak diaktifkan. shopt -s globstardan coba lagi ...
njsg
Cara lain untuk demistifikasi adalah set -xyang akan mulai mencetak perintah "aktual" yang dijalankan setiap kali (matikan bersama set +x).
ShreevatsaR
10

Dalam beberapa shell, termasuk bash 4.x dengan globstaropsi yang diaktifkan, **akan melakukan gumpalan rekursif, menurun direktori yang cocok. Tanda bintang tambahan tidak mengubah operasi ini lebih jauh.

Ignacio Vazquez-Abrams
sumber
1
Seperti yang saya katakan dalam jawaban saya, waspadalah terhadap hal itu ksh93dan zsh, bashapakah melintasi symlinks pada rekursi yang umumnya tidak diinginkan.
Stéphane Chazelas
Itu sekarang telah diperbaiki di bash 4.3
Stéphane Chazelas
1

Jika Anda ingin "menyelam lebih dalam", gunakan opsi ls -R (rekursif), atau gunakan find, seperti:

find . -ls

"find" akan turun ke bagian bawah pohon direktori (seperti akan 'ls -R'), dan memiliki banyak opsi lain, seperti daftar direktori (-type d), hanya file (-type f) atau menunjukkan file memiliki karakteristik (tidak ada pengguna di / etc / passwd, izin khusus, dan banyak lagi lainnya). "find" juga agak lebih aman dalam skrip (karena aturan globbing yang tidak konsisten antara shell, serta pelarian khusus untuk file yang memiliki garis putus-putus, dll).

shell wildcard globbing tidak akan bekerja hanya dengan tanda bintang '*' di file dot. Untuk daftar dotfiles saja, gunakan:

ls .??*

Razzlephrazz
sumber
-1

Ekstra * tidak menambah level kedalaman. Tetapi jika Anda mencoba

 ls */*/*

- Anda akan mendapatkan daftar subfolder subfolder di folder di folder saat ini ...

VB9-UANIC
sumber
Salah. Bergantung pada shell, *s tambahan akan menambah level kedalaman.
njsg
jadi shell apa yang akan menambah level kedalaman pada bintang tambahan?
VB9-UANIC
Beberapa. Termasuk GNU bashdengan opsi globstar, korn shell dan zsh. Dan mungkin yang lain, kurasa. unix.stackexchange.com/a/62665/14831
njsg
-1

Cengkeraman utama saya adalah gema ** / *. Ext umumnya akan ...

Mungkin atau Mungkin tidak: daftar file .ext di direktori saat ini

Mungkin atau Mungkin tidak: sertakan. *. Ext file

Secara umum saya lebih suka ekspresi glob menjadi '** /' dan yang dapat menghasilkan string nol (tidak ada sub-direktori). Inilah cara saya mengonversi ekspresi glob dalam input program. Tentu saja saya memastikan ada komentar yang menjelaskan hal ini dalam contoh penggunaan.

anthony
sumber