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 _echofungsi untuk melengkapi argumen ke echoperintah (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 -Gdapat 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 -Ghanya melakukan globbing nama file, tetapi compgen -Wmemberi Anda semua perluasan default bash, meskipun mungkin terlalu banyak ekspansi (termasuk ``dan $()). Tidak seperti -Gitu-W adalah aman dikutip (saya tidak bisa menjelaskan perbedaan tersebut). Karena tujuannya -Wadalah 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 %quntuk 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_COLLATEdan mungkin atau mungkin tidak melipat kasing), tetapi sebaliknya palu yang agak besar untuk masalah kecil ;-)