Untuk loop dengan Alphabet

12

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?

denski
sumber
2
Ini berfungsi di Ubuntu.
Pilot6
Saya tidak dapat mengaktifkannya pada 16,04 bash 4.3 sebagai skrip. Tapi itu berhasil jika saya salin melewatinya ke terminal.
denski

Jawaban:

25

Agaknya, Anda menjalankan skrip sebagai:

sh ForLoopAlphabetTest.sh

Di Ubuntu, shterhubung ke dash; karena dashtidak memiliki konsep array, Anda mendapatkan kesalahan sintaksis untuk (.

Script berfungsi dengan baik bash, jadi tidak masalah jika Anda menjalankannya sebagai bashargumen:

bash ForLoopAlphabetTest.sh

Sekarang, Anda memiliki bashshebang pada skrip, sehingga Anda dapat membuat skrip dapat dieksekusi ( chmod u+x ForLoopAlphabetTest.sh), dan menjalankannya sebagai:

/path/to/ForLoopAlphabetTest.sh

atau dari direktori skrip:

./ForLoopAlphabetTest.sh

Perhatikan juga, skrip Anda berisi brace expansion {a..z}, dan forkonstruk C-style : for (( ... ))yang juga tidak didukung oleh dash; jadi jika tujuan Anda adalah portabilitas, Anda harus melihat shsintaks POSIX saja.

heemayl
sumber
Terima kasih. Apakah ada cara untuk menghindari kurangnya konsep dari array?
denski
3
@denski Jika Anda ingin menulis skrip portabel yang dapat dijalankan oleh /bin/shsistem 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?
Eliah Kagan
Jika Anda memiliki beberapa bacaan yang disarankan akan sangat membantu. Terima kasih.
denski
1
@denski Saya telah mengirim jawaban yang mencakup beberapa tautan dan contoh. Dalam komentar saya sebelumnya di sini, saya telah menyebutkan Anda menggunakan array dan C-style untuk loop tetapi tidak menyebutkan penggunaan ekspansi brace. Jawaban saya mencakup bagaimana melakukannya tanpa ketiganya. Perhatikan bahwa jawaban ini (yaitu, heemayl, bukan milikku) adalah solusi utama untuk masalah Anda; Tambang berfokus pada bagaimana Anda dapat menulis ulang skrip Anda jika Anda tidak dapat mengandalkan fitur spesifik bash.
Eliah Kagan
@heemayl Sebagai catatan, saya ingin menambahkan bahwa Anda benar dalam asumsi Anda bahwa saya menjalankan skrip dengansh
denski
10

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 bashalih - alih sh. Baris hashbang Anda di atas ( #!/bin/bash) menentukan bashtetapi hanya efektif jika Anda menjalankan skrip, seperti yang dijelaskan heemayl . Jika Anda meneruskan nama skrip ke sh, shtidak 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:

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 forloop 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

Ini portabel untuk sebagian besar sistem mirip Unix dan tidak bergantung pada shell Bourne-style yang Anda gunakan. Namun, beberapa sistem mirip Unix tidak seqdiinstal secara default (mereka cenderung menggunakan jot, yang tidak diinstal secara default pada kebanyakan sistem GNU / Linux). Anda dapat menggunakan loop dengan expratau 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 $iberada dalam jangkauan.


Alih-alih mencetak seluruh alfabet, skrip Anda mendefinisikan variabel ndan mencetak $nhuruf 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 nperubahan 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, $stopada 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 ]).

Eliah Kagan
sumber
1
Ini adalah jawaban yang sangat fenomenal, daripada Anda untuk pendidikan. Saya sangat pemula, jadi cara saya menulis skrip adalah menyatukan elemen-elemen yang bekerja di internet sampai berfungsi. Saya tidak ragu ada 1) lebih baik dan 2) cara sederhana untuk melakukan hal-hal yang saya buat dengan skrip dan di atas berjalan jauh untuk membantu dengan itu.
denski
Terkait: stackoverflow.com/questions/169511/…
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件