Jika saya ingin memeriksa keberadaan satu file, saya dapat mengujinya menggunakan test -e filename
atau [ -e filename ]
.
Andaikata saya memiliki bola dunia dan saya ingin tahu apakah ada file yang namanya cocok dengan bola itu. Glob dapat mencocokkan 0 file (dalam hal ini saya tidak perlu melakukan apa pun), atau dapat mencocokkan 1 file atau lebih (dalam hal ini saya perlu melakukan sesuatu). Bagaimana saya bisa menguji apakah ada gumpalan yang cocok? (Saya tidak peduli berapa banyak pertandingan yang ada, dan akan lebih baik jika saya bisa melakukan ini dengan satu if
pernyataan dan tidak ada loop (hanya karena saya menemukan yang paling mudah dibaca).
( test -e glob*
gagal jika glob cocok dengan lebih dari satu file.)
Jawaban:
Keluar dari pola atau itu akan diperluas menjadi pertandingan.
Status yang keluar adalah:
stdout
adalah daftar file yang cocok dengan glob .Saya pikir ini adalah pilihan terbaik dalam hal keringkasan dan meminimalkan potensi efek samping.
UPDATE : Contoh penggunaan diminta.
sumber
compgen
adalah perintah built-in khusus bash dan bukan bagian dari perintah built-in standar Unix shell standar POSIX. pubs.opengroup.org/onlinepubs/9699919799 pubs.opengroup.org/onlinepubs/9699919799/utilities/... Oleh karena itu, hindari menggunakannya dalam skrip di mana portabilitas ke kulit lain menjadi perhatian.if ls /tmp/*Files 2>&1 >/dev/null; then echo exists; fi
- mungkin berguna untuk kode golf? Gagal jika ada file dengan nama yang sama dengan glob, yang seharusnya tidak cocok dengan glob, tetapi jika itu masalahnya Anda mungkin memiliki masalah yang lebih besar.if ls /tmp/*Files &> /dev/null; then echo exists; fi
compgen
, lihatman bash
atau denganhelp compgen
Opsi shell nullglob memang bashism.
Untuk menghindari perlunya menyimpan dan memulihkan keadaan nullglob yang membosankan, saya hanya akan menyetelnya di dalam subkulit yang memperluas glob:
Untuk portabilitas yang lebih baik dan globbing yang lebih fleksibel, gunakan temukan:
Eksplisit -print -digunakan tindakan untuk menemukan alih-alih tindakan implisit- print default sehingga menemukan akan berhenti segera setelah menemukan file pertama yang cocok dengan kriteria pencarian. Di mana banyak file cocok, ini harus berjalan lebih cepat daripada
echo glob*
atauls glob*
dan juga menghindari kemungkinan melebih-lebihkan baris perintah yang diperluas (beberapa shell memiliki batas panjang 4K).Jika menemukan terasa seperti berlebihan dan jumlah file yang cocok mungkin kecil, gunakan stat:
sumber
find
tampaknya benar sekali. Ia tidak memiliki case corner, karena shell tidak melakukan ekspansi (dan mengirimkan glob yang tidak diekspansi ke beberapa perintah lain), ia bisa dibawa-bawa di antara shell (walaupun tampaknya tidak semua opsi yang Anda gunakan ditentukan oleh POSIX), dan ini lebih cepat daripadals -d glob*
(jawaban yang diterima sebelumnya) karena berhenti ketika mencapai pertandingan pertama.shopt -u failglob
karena opsi-opsi ini tampaknya saling bertentangan.find
solusi akan cocok dengan nama file tanpa karakter segumpal juga. Dalam hal ini, itulah yang saya inginkan. Hanya sesuatu yang harus diperhatikan.-maxdepth
opsi untuk menemukan POSIX.sumber
nullglob
daripada memeriksa untuk melihat apakah satu hasil sama dengan pola itu sendiri. Beberapa pola dapat mencocokkan nama yang persis sama dengan pola itu sendiri (misalnyaa*b
; tetapi tidak misalnyaa?b
atau[a]
).touch '*py'
), tetapi ini memang menunjukkan saya ke arah lain yang baik."$M"
singkatan untuk"${M[0]}"
. Jika tidak, Anda sudah memiliki ekspansi glob dalam sebuah variabel array, jadi Anda harus mengalihkannya ke hal-hal lain sebagai daftar, alih-alih membuatnya mengembangkan kembali glob.[
proses) denganif [[ $M ]]; then ...
saya suka
Ini bisa dibaca dan efisien (kecuali ada banyak file).
Kelemahan utama adalah jauh lebih halus daripada tampilannya, dan kadang-kadang saya merasa harus menambahkan komentar panjang.
Jika ada kecocokan,
"glob*"
diperluas oleh shell dan semua kecocokan diteruskan keexists()
, yang memeriksa yang pertama dan mengabaikan sisanya.Jika tidak ada kecocokan,
"glob*"
diteruskan keexists()
dan ditemukan juga tidak ada.Sunting: mungkin ada positif palsu, lihat komentar
sumber
*.[cC]
(mungkin tidak adac
atauC
file, tetapi file bernama*.[cC]
) atau false negative jika file pertama diperluas dari itu misalnya symlink ke file yang tidak ada atau ke file dalam direktori tempat Anda tidak memiliki akses (Anda ingin menambahkan|| [ -L "$1" ]
).-e
jika ada 0 atau 1 kecocokan. Itu tidak berfungsi untuk beberapa pertandingan, karena itu akan menjadi[ -e file1 file2 ]
dan ini akan gagal. Lihat juga github.com/koalaman/shellcheck/wiki/SC2144 untuk alasan dan solusi yang disarankan.Jika Anda memiliki set globfail Anda dapat menggunakan ini gila (yang Anda benar-benar tidak boleh)
atau
sumber
(shopt -s failglob; : *) 2>/dev/null && echo exists
test -e memiliki peringatan malang yang menganggap tautan simbolis yang rusak tidak ada. Jadi, Anda mungkin ingin memeriksa juga.
sumber
-o
dan-a
ditest
/[
. Misalnya, di sini, itu gagal jika$1
adalah=
dengan sebagian besar implementasi. Gunakan[ -e "$1" ] || [ -L "$1" ]
sebagai gantinya.Untuk menyederhanakan jawaban The MYYN agak, berdasarkan idenya:
sumber
[a]
, memiliki file bernama[a]
, tetapi tidak ada file bernamaa
? Saya masih sukanullglob
untuk ini. Beberapa orang mungkin menganggap hal ini sebagai sesuatu yang tidak masuk akal, tetapi kita mungkin benar sepenuhnya sebagaimana masuk akal.[a]
hanya cocoka
, bukan nama file literal[a]
.Berdasarkan jawaban flabdablet , bagi saya sepertinya paling mudah (tidak harus tercepat) hanya menggunakan find sendiri, sambil meninggalkan ekspansi glob pada shell, seperti:
Atau dalam
if
suka:sumber
find
jawaban flabdablet karena ia menerima jalur di glob dan lebih singkat (tidak memerlukan-maxdepth
dll). Tampaknya juga lebih baik daripadastat
jawabannya karena tidak terus melakukan penambahanstat
pada setiap pertandingan glob tambahan. Saya akan menghargai jika ada yang bisa berkontribusi kasus sudut di mana ini tidak berhasil.-maxdepth 0
karena memungkinkan lebih banyak fleksibilitas dalam menambahkan kondisi. mis. asumsikan saya ingin membatasi hasil hanya untuk file yang cocok. Saya mungkin mencobafind $glob -type f -quit
, tetapi itu akan kembali benar jika glob TIDAK cocok dengan file, tetapi cocok dengan direktori yang berisi file (bahkan secara rekursif). Sebaliknyafind $glob -maxdepth 0 -type f -quit
hanya akan mengembalikan true jika glob itu sendiri cocok dengan setidaknya satu file. Catatan yangmaxdepth
tidak mencegah glob dari memiliki komponen direktori. (FYI2>
sudah cukup. Tidak perlu untuk&>
)find
di tempat pertama adalah untuk menghindari shell menghasilkan dan mengurutkan daftar pertandingan glob yang berpotensi besar;find -name ... -quit
akan cocok dengan paling banyak satu nama file. Jika sebuah skrip bergantung pada mengirimkan daftar pencocokan glob yang dihasilkan oleh shellfind
, memohon untukfind
mencapai apa pun kecuali overhead proses-startup yang tidak perlu. Cukup menguji daftar yang dihasilkan secara langsung untuk non-kekosongan akan lebih cepat dan lebih jelas.Saya punya solusi lain:
Ini bekerja dengan baik untuk saya. Apakah ada beberapa kasus sudut yang saya lewatkan?
sumber
Di Bash, Anda bisa menggumpal ke array; jika glob tidak cocok, array Anda akan berisi satu entri yang tidak sesuai dengan file yang ada:
Catatan: jika Anda telah
nullglob
menetapkan,scripts
akan menjadi array kosong, dan Anda harus menguji dengan[ "${scripts[*]}" ]
atau dengan[ "${#scripts[*]}" != 0 ]
sebagai gantinya. Jika Anda sedang menulis perpustakaan yang harus bekerja dengan atau tanpanullglob
, Anda akan menginginkannyaKeuntungan dari pendekatan ini adalah Anda kemudian memiliki daftar file yang ingin Anda kerjakan, daripada harus mengulangi operasi glob.
sumber
if [ -e "${scripts[0]}" ]...
? Apakah Anda juga memungkinkan untuk kemungkinan setel nounset opsi shell ?nounset
aktif. Juga, mungkin (sedikit) lebih murah untuk menguji string tidak kosong daripada memeriksa keberadaan file. Meskipun demikian, tidak mungkin, mengingat kami baru saja melakukan glob, artinya isi direktori harus segar di cache OS.Kekejian ini tampaknya berhasil:
Mungkin membutuhkan bash, bukan sh.
Ini berfungsi karena opsi nullglob menyebabkan glob mengevaluasi ke string kosong jika tidak ada kecocokan. Jadi setiap output yang tidak kosong dari perintah echo menunjukkan bahwa glob cocok dengan sesuatu.
sumber
if [ "`echo *py`" != "*py"]
*py
.py
,`echo *py`
akan dievaluasi*py
.*py
, yang merupakan hasil yang salah.*py
, skrip Anda akan menggema "Glob cocok"?Saya tidak melihat jawaban ini, jadi saya pikir saya akan meletakkannya di sana:
sumber
Penjelasan
Ketika tidak ada kecocokan untuk
glob*
, maka$1
akan mengandung'glob*'
. Tes-f "$1"
tidak akan benar karenaglob*
file tidak ada.Mengapa ini lebih baik daripada alternatif
Ini bekerja dengan sh dan turunannya: ksh dan bash. Itu tidak membuat sub-shell.
$(..)
dan`...`
perintah membuat sub-shell; mereka melakukan proses, dan karenanya lebih lambat dari solusi ini.sumber
Seperti ini pesta(file uji yang mengandung
pattern
):Ini jauh lebih baik daripada
compgen -G
: karena kita dapat membedakan lebih banyak kasus dan lebih tepatnya.Dapat bekerja dengan hanya satu wildcard
*
sumber
Perhatikan bahwa ini bisa sangat memakan waktu jika ada banyak kecocokan atau akses file lambat.
sumber
[a]
digunakan saat file[a]
ada dan filea
tidak ada. Itu akan mengatakan "ditemukan" meskipun satu-satunya file yang cocok,,a
sebenarnya tidak ada.sumber
nullglob
opsi shell.nullglob
kludge. Membandingkan hasil tunggal dengan pola asli adalah kludge (dan cenderung hasil salah), menggunakannullglob
tidak.nullglob
kludge.sumber
glob*
dan misalnya Anda tidak memiliki tulis untuk mendaftar direktori tersebut.ls | grep -q "glob.*"
Bukan solusi yang paling efisien (jika ada satu ton file di direktori itu mungkin lambat), tapi itu sederhana, mudah dibaca dan juga memiliki keuntungan bahwa regex lebih kuat daripada pola bash glob.
sumber
sumber