Salah satu cara yang kuat dalam bash adalah memperluas ke array, dan output elemen pertama saja:
pattern="*.txt"
files=( $pattern )
echo "${files[0]}" # printf is safer!
(Anda bahkan bisa saja echo $files
, indeks yang hilang diperlakukan sebagai [0].)
Ini dengan aman menangani spasi / tab / baris baru dan karakter metakarakter lainnya saat memperluas nama file. Perhatikan bahwa pengaturan lokal yang berlaku dapat mengubah apa yang "pertama" itu.
Anda juga dapat melakukan ini secara interaktif dengan fungsi penyelesaian bash :
_echo() {
local cur=${COMP_WORDS[COMP_CWORD]} # string to expand
if compgen -G "$cur*" > /dev/null; then
local files=( ${cur:+$cur*} ) # don't expand empty input as *
[ ${#files} -ge 1 ] && COMPREPLY=( "${files[0]}" )
fi
}
complete -o bashdefault -F _echo echo
Ini mengikat _echo
fungsi untuk melengkapi argumen ke echo
perintah (menimpa penyelesaian normal). "*" Tambahan ditambahkan dalam kode di atas, Anda bisa menekan tab pada nama file parsial dan mudah-mudahan hal yang benar akan terjadi.
Kode sedikit berbelit-belit, daripada disetel atau diasumsikan nullglob
( shopt -s nullglob
) kita periksa compgen -G
dapat memperluas gumpalan ke beberapa kecocokan, kemudian kita memperluas dengan aman ke dalam array, dan akhirnya mengatur KOMPREPLI sehingga kuotasi kuat.
Anda bisa melakukan ini sebagian (secara terprogram memperluas gumpalan) dengan bash compgen -G
, tetapi tidak kuat karena outputnya tidak dikutip ke stdout.
Seperti biasa, penyelesaian agak penuh, hal ini merusak penyelesaian hal-hal lain, termasuk variabel lingkungan (lihat _bash_def_completion()
fungsi di sini untuk detail meniru perilaku default).
Anda juga bisa menggunakan compgen
luar fungsi penyelesaian:
files=( $(compgen -W "$pattern") )
Satu hal yang perlu diperhatikan adalah bahwa "~" bukan glob, itu ditangani oleh bash dalam tahap ekspansi yang terpisah, seperti $ variable dan ekspansi lainnya. compgen -G
hanya melakukan globbing nama file, tetapi compgen -W
memberi Anda semua perluasan default bash, meskipun mungkin terlalu banyak ekspansi (termasuk ``
dan $()
). Tidak seperti -G
itu-W
adalah aman dikutip (saya tidak bisa menjelaskan perbedaan tersebut). Karena tujuannya -W
adalah untuk memperluas token, ini berarti ia akan memperluas "a" ke "a" bahkan jika tidak ada file seperti itu, jadi itu mungkin tidak ideal.
Ini lebih mudah dipahami, tetapi mungkin memiliki efek samping yang tidak diinginkan:
_echo() {
local cur=${COMP_WORDS[COMP_CWORD]}
local files=( $(compgen -W "$cur") )
printf -v COMPREPLY %q "${files[0]}"
}
Kemudian:
touch $'curious \n filename'
echo curious*
tab
Perhatikan penggunaan printf %q
untuk mengutip nilai-nilai secara aman.
Salah satu opsi terakhir adalah menggunakan output yang dibatasi 0 dengan utilitas GNU (lihat bash FAQ ):
pattern="*.txt"
while IFS= read -r -d $'\0' filename; do
printf '%q' "$filename";
break;
done < <(find . -maxdepth 1 -name "$pattern" -printf "%f\0" | sort -z )
Opsi ini memberi Anda sedikit lebih banyak kontrol atas urutan penyortiran (urutan ketika memperluas gumpalan akan tunduk pada lokal Anda / LC_COLLATE
dan mungkin atau mungkin tidak melipat kasing), tetapi sebaliknya palu yang agak besar untuk masalah kecil ;-)