Ini berfungsi sempurna di OSX
#!/bin/bash
chars=( {a..z} )
n=3
for ((i=0; i<n; i++))
do
echo "${chars[i]}"
done
Tetapi ketika saya menjalankannya di Ubuntu, saya mendapatkan kesalahan berikut.
ForLoopAlphabetTest.sh: 2: ForLoopAlphabetTest.sh: Syntax error: "(" unexpected
Sepertinya saya tidak bisa menyelesaikan masalah. Ada saran?
Jawaban:
Agaknya, Anda menjalankan skrip sebagai:
Di Ubuntu,
sh
terhubung kedash
; karenadash
tidak memiliki konsep array, Anda mendapatkan kesalahan sintaksis untuk(
.Script berfungsi dengan baik
bash
, jadi tidak masalah jika Anda menjalankannya sebagaibash
argumen:Sekarang, Anda memiliki
bash
shebang pada skrip, sehingga Anda dapat membuat skrip dapat dieksekusi (chmod u+x ForLoopAlphabetTest.sh
), dan menjalankannya sebagai:atau dari direktori skrip:
Perhatikan juga, skrip Anda berisi brace expansion
{a..z}
, danfor
konstruk C-style :for (( ... ))
yang juga tidak didukung olehdash
; jadi jika tujuan Anda adalah portabilitas, Anda harus melihatsh
sintaks POSIX saja.sumber
/bin/sh
sistem operasi mirip Unix, maka Anda tidak akan dapat menggunakan array. Bash (dan beberapa shell lain) telah menambahkannya karena sangat nyaman dan tidak selalu dapat dengan mudah diganti dengan kode yang lebih portabel. Namun, untuk skrip Anda khususnya, Anda dapat melakukannya tanpa kesulitan dan tanpa menggunakan fitur spesifik bash. Apakah Anda tertarik untuk melakukan itu?sh
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 - alihsh
. Baris hashbang Anda di atas (#!/bin/bash
) menentukanbash
tetapi hanya efektif jika Anda menjalankan skrip, seperti yang dijelaskan heemayl . Jika Anda meneruskan nama skrip kesh
,sh
tidak akan secara otomatis memanggilbash
, 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:
( {a..z} )
, yang Anda tetapkan untukchars
, menciptakan array, dan${chars[i]}
, yang muncul di loop Anda, indeks ke dalamnya.{a..z}
diperluas kea 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.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:
seq
perintah menghasilkan urutan numerik.$(
)
melakukan substitusi perintah , jadi$(seq 97 122)
diganti dengan output dariseq 97 122
. Ini adalah kode karakter untuka
melaluiz
.printf
Perintah yang kuat dapat mengubah kode karakter menjadi huruf (misalnya,printf '\141'
cetakana
, diikuti oleh baris baru ), tetapi kode harus dalam oktal , sementaraseq
output hanya dalam desimal . Jadi saya telah menggunakanprintf
dua kali: bagian dalamprintf %o $i
mengubah angka desimal (disediakan olehseq
) menjadi oktal, dan diganti menjadiprintf
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\
sebelumn
tidak perlu melarikan diri karena, tidak seperti\$
,\n
tidak memiliki arti khusus pada shell dalam string yang dikutip ganda.'
) 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 menggunakanjot
, yang tidak diinstal secara default pada kebanyakan sistem GNU / Linux). Anda dapat menggunakan loop denganexpr
atau substitusi aritmatika untuk meningkatkan portabilitas lebih lanjut, jika Anda perlu: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 mengharuskanseq
:Menyesuaikan nilai
n
perubahan berapa banyak huruf yang dicetak, seperti pada skrip Anda.Ini versi yang tidak memerlukan
seq
: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 ]
).sumber