Dengan bash, atur pengaturan glob sehingga kecocokan yang hilang tidak memicu kesalahan:
shopt -u failglob # avoid failure report (and discarding the whole line).
shopt -s nullglob # remove (erase) non-matching globs.
ls ?c c?
Tanda tanya adalah karakter glob yang mewakili satu karakter. Karena Anda menginginkan nama file dua karakter, salah satunya harus berupa c
, dan jadi itu adalah karakter pertama atau karakter terakhir.
Dengan shopt -s dotglob
ini juga akan menampilkan file bernama .c
.
Jika tidak ada file yang cocok, menyetel opsi shell ini menyebabkan semua argumen dihapus, menghasilkan ls
kosong -- mencantumkan apa saja/semuanya secara default.
Gunakan ini sebagai gantinya:
shopt -s nullglob ## drop any missing globs
set -- ?c c? ## populate the [email protected] array with (any) matches
if [ $# -gt 0 ] ## if there are some, list them
ls -d "[email protected]"
fi
Saya pikir cara yang lebih baik adalah dengan menggunakan find
:
find . -type f -name '*c*' -name '??'
Itu akan mencari secara rekursif. Untuk mencantumkan hanya file di direktori saat ini:
find . ! -name . -prune -type f -name '*c*' -name '??'
Jika file ada (dan tidak ada karakter yang lolos seperti \c
), Anda dapat menggunakan glob:
echo ?c c?
yang akan mencocokkan file yang memiliki satu karakter (?
) diikuti dengan c
atau yang memiliki c
diikuti oleh satu karakter (?
).
Tetapi akan gagal dengan nama file yang dimulai dengan tanda hubung seperti -n
atau -e
atau dengan karakter backslash seperti \c
atau \n
dengan echo
sebagai -e
dan -n
khusus untuk (beberapa shell) echo
dan \c
atau \n
akan ditafsirkan sebagai urutan pelarian (\c
mengakhiri output dan \n
mencetak baris baru, bukan karakter verbatim \n
dalam beberapa implementasi shell gema dan dengan bash ketika opsi shopt -s xpg_echo
diatur). Aplikasi atau utilitas lain (seperti ls
) akan memiliki beberapa opsi lain dan mungkin gagal dengan banyak tanda hubung lain yang dimulai atau menginterpretasikan karakter escape lain dalam nama file.
Juga akan mencantumkan file bernama cc
dua kali.
-
Jika file dapat dimulai dengan tanda hubung (seperti -n), gunakan:
$ ls -d -- ?n -n
Atau, lebih baik:
$ ls -d ./?n ./-n
Peringatan
-
Glob tidak cocok dengan file.
-
Jika file tidak ada, glob tidak akan diperluas dan glob akan dicetak dalam bentuk aslinya.
$ echo ?m m? ?m m?
-
Kecuali di zsh.
$ zsh -c 'echo ?m m?' zsh:1: no matches found: ./m?
Shell akan keluar dengan kesalahan.
Perilaku ini dikendalikan olehnomatch
Zsh opsi.$ zsh -c 'setopt +o nomatch; echo ?m m?' ?m m?
Atau:
$ zsh -c 'echo ?m(N) m?(N)' ?m m?
Tapi itu akan mencetak
mm
dua kali. -
Di bash Anda bisa mendapatkan hasil yang mirip dengan zsh jika opsi shell
failglob
diatur:$ bash -c 'shopt -s failglob; echo ?m m?' bash: no match: ?m
Tetapi skrip tidak akan berhenti, shell tidak akan keluar. Yah, secara teknis, baris di mana glob digunakan tidak dieksekusi lebih lanjut tetapi eksekusi dilanjutkan pada baris skrip berikutnya.
-
Di bash Anda bisa mengatur opsi
nullglob
untuk menghapus gumpalan yang tidak cocok:$ bash -c 'shopt -s nullglob; echo ?m m? done' done
-
-
Menggunakan ls (mirip dengan program lain)
-
Dengan file yang cocok tidak akan ada masalah, tetapi juga akan cocok (dan mencantumkan) direktori:
$ ls ?c c? bc cz sc ac: hjk
Lebih baik gunakan
-d
denganls
(direktori akan disertakan tetapi tidak diperluas).$ ls -d ?c c? ac bc cz sc
-
Gumpalan gagal mencocokkan file (atau direktori)
Lalu
ls
akan melaporkan kegagalan$ ls ?m m? ls: cannot access '?m': No such file or directory
Program lain mungkin (mungkin) melakukannya tidak lakukan pemeriksaan serupa.
-
Menggunakan
nullglob
dengan bash akan memberikan daftar kosong ke ls, jadi, itu akan mencantumkan konten atau pwd seolah-olah hanyals
dieksekusi:$ ls ?m m? ac a.out cz 3 b sc ab bc
Itu bisa dihindari menggunakan
./
$ ls -d ./?m ./m? ls: cannot access './?m': No such file or directory ls: cannot access './m?': No such file or directory
-
Atau Anda dapat menggunakan regex find (tetapi akan melintasi subdirektori dengan prune
hilang) (Perhatikan bahwa ini tidak akan mengulangi file bernama cc):
$ find . ! -name . -prune -regex '.*/\(.c\|c.\)'
./ac
./cc
./sc
./bc
./cz