Saya memiliki skrip bash yang disederhanakan berikut ini
#!/bin/bash
files=("$@")
if [ "X$files" = "X" ]; then
files=$HOME/print/*.pdf;
fi
for file in "${files[@]}"; do
ls "$file";
done
Jika saya memberikan argumen (nama file) sebagai parameter, skrip ini akan mencetak nama file yang tepat. Di sisi lain, jika saya tidak memberikan argumen, itu akan dicetak
/home/user/print/*.pdf: No such file or directory
Mengapa nama file tidak diperluas dalam kasus ini, dan bagaimana cara memperbaikinya? Perhatikan bahwa saya menggunakan files=("$@")
dan "${files[@]}"
membangun karena saya membaca bahwa itu lebih disukai daripada "files = $ *" yang biasa.
files=$*
pernah biasa ? Itu salah .Jawaban:
Anda menetapkan
files
sebagai variabel skalar alih-alih variabel array .Di
Anda menetapkan beberapa string seperti
/home/highsciguy/print/*.pdf
ke$files
variabel skalar (alias string).Menggunakan:
atau
sebagai gantinya. Shell akan memperluas pola globbing ke daftar path file, dan menetapkan masing-masing ke elemen
$files
array .Perluasan glob dilakukan pada saat penugasan.
Anda tidak harus menggunakan fitur sh non-standar, dan Anda bisa menggunakan sistem Anda
sh
alih - alih dibash
sini dengan menuliskannya:set
adalah untuk menetapkan"$@"
berbagai parameter posisi.Pendekatan lain bisa saja menyimpan pola globbing dalam variabel skalar:
Dan memiliki shell memperluas gumpalan pada saat
$files
variabel diperluas.Di sini, karena
$files
tidak dikutip (yang biasanya tidak Anda lakukan), perluasannya tunduk pada pemisahan kata (yang kami nonaktifkan di sini) dan pembuatan globbing / namafile.Jadi
*.pdf
akan diperluas ke daftar file yang cocok. Namun, jika$HOME
berisi karakter wildcard, mereka dapat diperluas juga, itulah sebabnya mengapa masih lebih disukai untuk menggunakan variabel array.sumber
Anda mungkin telah melihat hal-hal seperti
files=$*
danfiles=~/print/*.pdf
di kulit yang lebih tua tanpa array, dan kemudianls $files
.Substitusi variabel yang tidak berada dalam tanda kutip ganda menafsirkan nilai variabel sebagai daftar pola wildcard shell yang dipisahkan dengan spasi putih yang diganti dengan nama file yang cocok jika ada. Misalnya, setelah
files=~/print/*.pdf
,ls $files
memperluas ke sesuatu sepertils
dengan argumen/home/highsciguy/print/bar.pdf
,/home/highsciguy/print/foo.pdf
dll. Dalam kasusfiles=$*
ini, tugas ini menggabungkan argumen yang diteruskan ke skrip dengan spasi di antaranya, danls $files
membaginya kembali.Semua ini rusak jika Anda memiliki nama file yang mengandung karakter spasi atau globbing, itulah sebabnya Anda tidak boleh melakukan hal-hal seperti ini. Gunakan array sebagai gantinya.
Catat itu
var=(…)
."$files"
kosong ketikafiles
array yang elemennya indeks 0 tidak disetel atau string kosong. Juga[ "X$foo" = "X" ]
merupakan cara usang untuk menguji apakah$foo
kosong: semua shell modern menerapkan[ -n "$foo" ]
dengan benar. Di bash, Anda bisa menggunakan[[ -n $foo ]]
.Dalam shell yang tidak mendukung array, sebenarnya ada satu array: parameter posisi ke shell atau fungsi saat ini. Di sini, Anda tidak benar-benar membutuhkan
files
array, sebenarnya akan lebih mudah untuk menggunakan parameter posisi.sumber