Alfabeli döngü için


12

Bu OSX'de mükemmel çalışır

#!/bin/bash
chars=( {a..z} )
n=3
for ((i=0; i<n; i++))
do
  echo "${chars[i]}"
done

Ama Ubuntu üzerinde çalıştırdığımda, aşağıdaki hatayı alıyorum.

ForLoopAlphabetTest.sh: 2: ForLoopAlphabetTest.sh: Syntax error: "(" unexpected

Sorunu çözemiyorum. Herhangi bir öneri?


2
Bu Ubuntu üzerinde çalışır.
Pilot6

Komut dosyası olarak 16.04 bash 4.3 üzerinde çalışamıyor. Ama terminalden kopyalarsam işe yarar.
denski

Yanıtlar:


25

Muhtemelen, komut dosyasını şu şekilde çalıştırıyorsunuz:

sh ForLoopAlphabetTest.sh

Ubuntu, shsembolik olarak bir dash; olarak dashdiziler kavramı yok, sizin için sözdizimi hatası alıyorsanız (.

Senaryo mükemmel çalışır bash, bu yüzden bashargüman olarak çalıştırırsanız iyi olur :

bash ForLoopAlphabetTest.sh

Şimdi, bashsenaryonun üzerinde bir şey var , böylece senaryoyu yürütülebilir ( chmod u+x ForLoopAlphabetTest.sh) yapabilir ve şu şekilde çalıştırabilirsin:

/path/to/ForLoopAlphabetTest.sh

veya komut dosyasının dizininden:

./ForLoopAlphabetTest.sh

Ayrıca unutmayın, sizin komut ayracı genişletme içermez {a..z}ve C tarzı foryapısı: for (( ... ))Ayrıca tarafından desteklenmeyen hangi dash; hedefiniz taşınabilirlik ise shyalnızca POSIX sözdizimlerine bakmalısınız .


Teşekkür ederim. Dash'in dizi kavramı eksikliğini atlatmanın bir yolu var mı?
denski

3
@denski /bin/shUnix benzeri bir işletim sisteminde çalıştırılabilen taşınabilir komut dosyaları yazmak istiyorsanız, dizileri kullanamazsınız. Bash (ve diğer bazı kabuklar) bunları ekledi çünkü çok kullanışlılar ve her zaman daha taşınabilir kodlarla kolayca değiştirilemezler. Ancak, özellikle betiğiniz için, bunu herhangi bir sorun olmadan ve bash'a özgü özellikler kullanmadan yapabilirsiniz. Bunu nasıl yapacağınızla ilgileniyor musunuz?
Eliah Kagan

Bazı okuma tavsiye varsa yardımcı olacaktır. Teşekkürler.
denski

1
@denski Bazı bağlantılar ve örnekler içeren bir cevap gönderdim . Buradaki önceki yorumumda, döngüler için diziler ve C stili kullandığınızdan bahsetmiştim, ancak küme ayracı genişletme kullanımınızdan bahsetmedim. Cevabım, üçü olmadan nasıl yapılacağını kapsar. Not olduğunu bu cevabı (benim değil yani heemayl var) sorununuza birincil çözümdür; mine, bash'a özgü özelliklere güvenemiyorsanız komut dosyanızı nasıl yeniden yazabileceğinize odaklanır.
Eliah Kagan

@heemayl Kayıt için, ben script çalıştırdığınız varsayımına doğru olduğunu eklemek istedimsh
denski

10

Betiğiniz, Bash kabuğunun tüm Bourne tarzı kabuklar tarafından sağlanmayan üç özelliğini kullanır. Gibi heemayl diyor , sadece birlikte o senaryoyu çalıştırabilirsiniz bashyerine sh. Kişisel hashbang üst (satır #!/bin/bash) belirttiğinden bashsen ama eğer sadece etkilidir yürütmek gibi senaryoyu heemayl açıkladı . Komut dosyasının adını iletirseniz sh, shotomatik olarak çağrılamaz bash, ancak komut dosyasını çalıştırır. Bunun nedeni , komut dosyanız gerçekten çalıştığında, hashbang satırının bir etkisi olmamasıdır .

Bash özelliklerine bağlı olmayan tamamen taşınabilir komut dosyaları yazmanız gerekiyorsa, diğer alternatifiniz komut dosyasını, onlarsız çalışacak şekilde değiştirmektir. Kullandığınız Bash özellikleri:

  • Bir dizi . Bu önce geldi, bu yüzden komut dosyanızı Dash kabuğu ile çalıştırmaya çalıştığınızda hatayı üreten şey buydu . ( {a..z} )Atadığınız parantez içinde ifade charsbir dizi oluşturur ve döngünüzde ${chars[i]}görünen parantez içinde dizine eklenir.
  • Brace genişlemesi. Bash'de ve diğer birçok mermide {a..z}de genişler 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. Ancak, bu Bourne tarzı mermilerin evrensel (veya standartlaştırılmış) bir özelliği değildir ve Dash bunu desteklemez.
  • C stili alternatiffor - döngü sözdizimi . Dayalı olsa da aritmetik genişleme olduğunu Bash özgü olmayan kendisi (bazı olsa çok eski olmayan POSIX uyumlu kabukları ya o yok), C tarzı fordöngü olduğunu bir Bash-izm ve yaygın taşınabilir değildir diğer mermiler.

Bash, özellikle Ubuntu gibi GNU / Linux sistemlerinde yaygın olarak bulunur ve (gördüğünüz gibi) macOS ve diğer birçok sistemde de mevcuttur. Bash'e özgü özellikleri ne kadar kullandığınızı göz önünde bulundurarak, bunları kullanmak isteyebilirsiniz ve komut dosyalarını çalıştırırken Bash'i (veya kullandığınız özellikleri destekleyen başka bir kabuğu) kullandığınızdan emin olun.

Ancak, isterseniz bunları taşınabilir yapılarla değiştirebilirsiniz. Dizi ve C tarzı fordöngü kolayca değiştirilebilir; küme ayracı genişletme olmadan (ve bunları kodunuzda sabit kodlamadan) harf aralığını oluşturmak biraz zor olan tek bölümdür.


İlk olarak, tüm küçük Latin harfleri yazdıran bir komut dosyası:

#!/bin/sh

for i in $(seq 97 122); do
    printf "\\$(printf %o $i)\n"
done

Bu, Unix benzeri sistemlerin çoğunda taşınabilir ve hangi Bourne tarzı kabuğu kullandığınıza bağlı değildir. Bununla birlikte, birkaç Unix benzeri sistem seqvarsayılan olarak yüklenmez ( jotbunun yerine çoğu GNU / Linux sistemi tarafından varsayılan olarak yüklenmeyen). exprGerekirse, taşınabilirliği daha da artırmak için bir döngü veya aritmetik değiştirme kullanabilirsiniz:

#!/bin/sh

i=97
while [ $i -le 122 ]; do
    printf "\\$(printf %o $i)\n"
    i=$((i + 1))
done

Bu, yalnızca whilekapsama alanındayken döngüye devam etmek için [komutla birlikte bir -loop kullanır $i.


Komut dosyanızın tamamını yazdırmak yerine, bir değişken tanımlar nve ilk $nküçük harfleri yazdırır . Komut dosyanızın Bash'a özgü hiçbir özelliğe dayanmayan ve Dash üzerinde çalışan, ancak aşağıdakileri gerektiren bir sürümü seq:

#!/bin/sh

n=3 start=97
for i in $(seq $start $((start + n - 1))); do
    printf "\\$(printf %o $i)\n"
done

Değerini ayarlama nbirçok mektup senin senaryosunda olduğu gibi yazdırılır şeklindeki değişiklikler.

İşte gerektirmeyen bir sürüm seq:

#!/bin/sh

n=3 i=97 stop=$((i + n))
while [ $i -lt $stop ]; do
    printf "\\$(printf %o $i)\n"
    i=$((i + 1))
done

Orada, yazdırılması gereken son harfin karakter kodundan $stopbir daha yüksek , bu yüzden komutla (küçük veya eşit) -ltyerine -le( küçüktür) kullanıyorum [. (Yapmak stop=$((i + n - 1))ve kullanmak da işe yarardı [ $i -le $stop ]).


1
Bu, eğitim için sizden çok detaylı bir cevaptır. Ben çok yeni başlayan biriyim, bu yüzden senaryo yazma yolum, internette bulunan çalışma öğelerini çalışana kadar bir araya getirmektir. Hiç şüphem yok 1) daha iyi ve 2) komut dosyaları ile oluşturduğum şeyleri yapmanın daha basit yolları ve yukarıda bu konuda yardımcı olmak için uzun bir yol gidiyor.
denski

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.