Script Anda menggunakan tiga fitur shell Bash yang tidak disediakan oleh semua shell bergaya Bourne. Seperti yang dikatakan heemayl , Anda bisa menjalankan skrip itu dengan bash
alih - alih sh
. Baris hashbang Anda di atas ( #!/bin/bash
) menentukan bash
tetapi hanya efektif jika Anda menjalankan skrip, seperti yang dijelaskan heemayl . Jika Anda meneruskan nama skrip ke sh
, sh
tidak akan secara otomatis memanggil bash
, tetapi hanya akan menjalankan skrip. Ini karena begitu skrip Anda benar-benar berjalan, garis hashbang tidak berpengaruh .
Alternatif Anda yang lain, jika Anda perlu menulis skrip yang sepenuhnya portabel yang tidak bergantung pada fitur Bash, adalah mengubah skrip Anda agar berfungsi tanpa mereka. Fitur Bash yang Anda gunakan adalah:
- Sebuah Array . Ini yang lebih dulu, jadi inilah yang menghasilkan kesalahan ketika Anda mencoba menjalankan skrip Anda dengan shell Dash . Ekspresi kurung
( {a..z} )
, yang Anda tetapkan untuk chars
, menciptakan array, dan ${chars[i]}
, yang muncul di loop Anda, indeks ke dalamnya.
- Ekspansi penjepit. Di Bash, dan juga di banyak kerang lainnya,
{a..z}
diperluas ke a b c d e f g h i j k l m n o p q r s t u v w x y z
. Namun, ini bukan fitur universal (atau standar) dari shell Bourne-style, dan Dash tidak mendukungnya.
- Sintaks -loop pengganti
for
-gaya-C . Meskipun didasarkan pada ekspansi aritmatika , yang tidak dengan sendirinya spesifik untuk Bash (meskipun beberapa cangkang yang sangat tua, non-POSIX-compliant tidak memilikinya,), for
loop C-style adalah Bash-isme dan tidak banyak portabel untuk digunakan. kerang lainnya.
Bash tersedia secara luas, terutama pada sistem GNU / Linux seperti Ubuntu, dan (seperti yang telah Anda lihat) juga tersedia di macOS dan banyak sistem lainnya. Mengingat seberapa banyak Anda menggunakan fitur spesifik Bash, Anda mungkin hanya ingin menggunakannya, dan cukup pastikan Anda menggunakan Bash (atau beberapa shell lain yang mendukung fitur yang Anda gunakan) ketika Anda menjalankan skrip Anda.
Namun, Anda dapat menggantinya dengan konstruksi portabel jika Anda mau. Array dan for
loop gaya-C mudah diganti; menghasilkan rentang huruf tanpa ekspansi brace (dan tanpa mengkodekannya dalam skrip Anda) adalah bagian yang sedikit rumit.
Pertama, inilah skrip yang mencetak semua huruf latin dengan huruf kecil:
#!/bin/sh
for i in $(seq 97 122); do
printf "\\$(printf %o $i)\n"
done
- The
seq
perintah menghasilkan urutan numerik. $(
)
melakukan substitusi perintah , jadi $(seq 97 122)
diganti dengan output dari seq 97 122
. Ini adalah kode karakter untuk a
melalui z
.
printf
Perintah yang kuat dapat mengubah kode karakter menjadi huruf (misalnya, printf '\141'
cetakan a
, diikuti oleh baris baru ), tetapi kode harus dalam oktal , sementara seq
output hanya dalam desimal . Jadi saya telah menggunakan printf
dua kali: bagian dalam printf %o $i
mengubah angka desimal (disediakan oleh seq
) menjadi oktal, dan diganti menjadi printf
perintah luar . (Meskipun juga mungkin untuk menggunakan heksadesimal , itu tidak sederhana dan tampaknya kurang portabel .)
printf
interpret \
diikuti oleh angka oktal sebagai karakter dengan kode itu, dan\n
sebagai baris baru. Tetapi shell juga digunakan \
sebagai karakter pelarian. A \
di depan $
akan mencegah $
dari menyebabkan ekspansi terjadi (dalam hal ini, substitusi perintah ), tapi saya tidak ingin mencegah itu, jadi saya telah lolos dengan yang lain \
; itulah alasannya \\
. Yang kedua \
sebelum n
tidak perlu melarikan diri karena, tidak seperti \$
, \n
tidak memiliki arti khusus pada shell dalam string yang dikutip ganda.
- Untuk informasi lebih lanjut tentang bagaimana tanda kutip ganda dan garis miring terbalik digunakan dalam pemrograman shell, lihat bagian tentang mengutip dalam standar internasional . Lihat juga 3.1.2 Mengutip dalam Manual Referensi Bash , terutama 3.1.2.1 Karakter Escape dan 3.1.2.3 Kutipan Ganda . (Inilah keseluruhan bagian , dalam konteks.) Perhatikan bahwa tanda kutip tunggal (
'
) juga merupakan bagian penting dari sintaksis mengutip shell, saya hanya tidak menggunakannya dalam skrip itu.
Ini portabel untuk sebagian besar sistem mirip Unix dan tidak bergantung pada shell Bourne-style yang Anda gunakan. Namun, beberapa sistem mirip Unix tidak seq
diinstal secara default (mereka cenderung menggunakan jot
, yang tidak diinstal secara default pada kebanyakan sistem GNU / Linux). Anda dapat menggunakan loop dengan expr
atau substitusi aritmatika untuk meningkatkan portabilitas lebih lanjut, jika Anda perlu:
#!/bin/sh
i=97
while [ $i -le 122 ]; do
printf "\\$(printf %o $i)\n"
i=$((i + 1))
done
Yang menggunakan while
-loop dengan para [
perintah untuk melanjutkan perulangan hanya ketika $i
berada dalam jangkauan.
Alih-alih mencetak seluruh alfabet, skrip Anda mendefinisikan variabel n
dan mencetak $n
huruf kecil pertama. Berikut adalah versi skrip Anda yang tidak mengandalkan fitur khusus Bash dan berfungsi di Dash, tetapi mengharuskan seq
:
#!/bin/sh
n=3 start=97
for i in $(seq $start $((start + n - 1))); do
printf "\\$(printf %o $i)\n"
done
Menyesuaikan nilai n
perubahan berapa banyak huruf yang dicetak, seperti pada skrip Anda.
Ini versi yang tidak memerlukan seq
:
#!/bin/sh
n=3 i=97 stop=$((i + n))
while [ $i -lt $stop ]; do
printf "\\$(printf %o $i)\n"
i=$((i + 1))
done
Di sana, $stop
ada satu yang lebih tinggi dari kode karakter huruf terakhir yang harus dicetak, jadi saya menggunakan -lt
(kurang dari) daripada -le
(kurang dari atau sama) dengan [
perintah. (Ini juga akan berhasil membuatnyastop=$((i + n - 1))
dan menggunakan [ $i -le $stop ]
).