Per il ciclo con Alphabet

11

Funziona perfettamente su OSX

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

Ma quando lo eseguo su Ubuntu, ottengo il seguente errore.

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

Non riesco a risolvere il problema. Qualche suggerimento?

    
posta denski 18.01.2017 - 13:22
fonte

2 risposte

25

Presumibilmente, stai eseguendo lo script come:

sh ForLoopAlphabetTest.sh

In Ubuntu, sh è linkato a dash ; poiché dash non ha alcun concetto di array, stai ricevendo l'errore di sintassi per ( .

Lo script funziona perfettamente su bash , quindi andrebbe bene se lo stavi eseguendo come argomento di bash :

bash ForLoopAlphabetTest.sh

Ora hai lo bash shebang sullo script, quindi puoi rendere eseguibile lo script ( chmod u+x ForLoopAlphabetTest.sh ) ed eseguirlo come:

/path/to/ForLoopAlphabetTest.sh

o dalla directory dello script:

./ForLoopAlphabetTest.sh

Si noti inoltre che lo script contiene l'espansione di controvento {a..z} e il costrutto di stile% C co_de%: for che non sono supportati anche da for (( ... )) ; quindi se il tuo obiettivo è la portabilità, dovresti esaminare solo le sintassi POSIX dash .

    
risposta data heemayl 18.01.2017 - 13:31
fonte
8

Il tuo script utilizza tre funzioni della shell Bash che non sono fornite da tutte le shell di tipo Bourne. Come heemayl dice , puoi semplicemente eseguire quello script con bash invece di sh . La tua riga hashbang in alto ( #!/bin/bash ) specifica bash ma è efficace solo se esegui lo script, come ha spiegato spiegando . Se passi il nome dello script a sh , sh non chiamerà automaticamente bash , ma eseguirà semplicemente lo script. Questo perché una volta che lo script è effettivamente in esecuzione, la riga di hashbang non ha alcun effetto .

La tua altra alternativa, se hai bisogno di scrivere script completamente portatili che non dipendono sulle funzionalità di Bash, è quello di cambiare il tuo script in modo che funzioni senza di essi. Le funzioni di Bash che usi sono:

Bash è ampiamente disponibile, specialmente su sistemi GNU / Linux come Ubuntu, e (come hai visto) è anche disponibile su macOS e molti altri sistemi. Considerando quanto stai utilizzando le funzionalità specifiche di Bash, potresti semplicemente usarle e assicurarti semplicemente di utilizzare Bash (o qualche altra shell che supporta le funzionalità che stai utilizzando) quando esegui i tuoi script.

Tuttavia, puoi sostituirli con costrutti portatili, se lo desideri. L'array e il ciclo di tipo for sono facili da sostituire; generare la gamma di lettere senza espansione di parentesi graffe (e senza codificarle nel tuo script) è l'unica parte un po 'complicata.

Per prima cosa, ecco uno script che stampa tutte le lettere latine minuscole:

#!/bin/sh

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

Questo è portatile per la maggior parte dei sistemi simili a Unix e non dipende da quale shell di tipo Bourne usi. Tuttavia, alcuni sistemi di tipo Unix non hanno ' installato di default (tendono a usare seq invece, che non è installato di default sulla maggior parte dei sistemi GNU / Linux). Puoi utilizzare un ciclo con jot o sostituzione aritmetica per aumentare ulteriormente la portabilità, se necessario:

#!/bin/sh

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

Che utilizza un expr -loop con il comando while per continuare il ciclo solo quando [ è nell'intervallo.

Invece di stampare l'intero alfabeto, il tuo script definisce una variabile $i e stampa le prime lettere in minuscolo n . Ecco una versione del tuo script che non si basa su funzioni specifiche di Bash e funziona su Dash, ma richiede $n :

#!/bin/sh

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

La modifica del valore di seq modifica il numero di lettere stampate, come nel tuo script.

Ecco una versione che non richiede n :

#!/bin/sh

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

Lì, seq è un più alto del codice carattere dell'ultima lettera che dovrebbe essere stampata, quindi uso $stop (minore di) piuttosto che -lt (minore di o uguale) con il comando -le . (Avrebbe anche funzionato per rendere [ e usare stop=$((i + n - 1)) ).

    
risposta data Eliah Kagan 18.01.2017 - 17:02
fonte

Leggi altre domande sui tag