Funciona perfeitamente no OSX
#!/bin/bash
chars=( {a..z} )
n=3
for ((i=0; i<n; i++))
do
echo "${chars[i]}"
done
Mas quando o executo no Ubuntu, recebo o seguinte erro.
ForLoopAlphabetTest.sh: 2: ForLoopAlphabetTest.sh: Syntax error: "(" unexpected
Não consigo resolver o problema. Alguma sugestão?
Respostas:
Presumivelmente, você está executando o script como:
No Ubuntu,
sh
está vinculado adash
; comodash
não tem conceito de matrizes, você está recebendo o erro de sintaxe(
.O script funciona perfeitamente
bash
, por isso seria bom se você o estivesse executando comobash
argumento:Agora, você tem o
bash
shebang no script, portanto, você pode tornar o script executável (chmod u+x ForLoopAlphabetTest.sh
) e executá-lo como:ou do diretório do script:
Observe também que, seu script contém expansão entre chaves
{a..z}
efor
construção no estilo C : asfor (( ... ))
quais também não são suportadasdash
; portanto, se seu objetivo é portabilidade, você deve considerarsh
apenas as sintaxes do POSIX .fonte
/bin/sh
em qualquer sistema operacional parecido com o Unix, não poderá usar matrizes. O Bash (e alguns outros shells) os adicionaram porque são muito convenientes e nem sempre podem ser facilmente substituídos por um código mais portátil. No entanto, para o seu script em particular, você pode fazê-lo sem problemas e sem usar nenhum recurso específico do bash. Você está interessado em como fazer isso?sh
Seu script usa três recursos do shell Bash que não são fornecidos por todos os shells no estilo Bourne. Como o heemayl diz , você pode simplesmente executar esse script com em
bash
vez desh
. Seu linha de hashbang na parte superior (#!/bin/bash
) especifica,bash
mas só é efetiva se você executar o script, como o heemayl explicou . Se você passar o nome do script parash
,sh
não será chamado automaticamentebash
, mas simplesmente executará o script. Isso ocorre porque, quando o script está em execução, a linha hashbang não tem efeito .Sua outra alternativa, se você precisar escrever scripts totalmente portáteis que não dependem dos recursos do Bash, é alterá-lo para que funcione sem eles. Os recursos do Bash que você usa são:
( {a..z} )
, à qual você atribuichars
, cria uma matriz e${chars[i]}
, que aparece no seu loop, é indexada nela.{a..z}
é expandido paraa 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
. No entanto, esse não é um recurso universal (ou padronizado) dos shells no estilo Bourne, e o Dash não o suporta.for
sintaxe -loop . Embora baseado na expansão aritmética , que não é específica do Bash (embora alguns shells muito antigos e não compatíveis com POSIX também não o tenham), ofor
loop do estilo C é um Bash-ism e não é amplamente portátil para outras conchas.O Bash está amplamente disponível, especialmente em sistemas GNU / Linux como o Ubuntu, e (como você viu) também está disponível no macOS e em muitos outros sistemas. Considerando o quanto você está usando recursos específicos do Bash, convém usá-los e simplesmente certifique-se de usar o Bash (ou algum outro shell que suporte os recursos que você está usando) ao executar seus scripts.
No entanto, você pode substituí-los por construções portáteis, se quiser. A matriz e o
for
loop em estilo C são fáceis de substituir; gerar o intervalo de letras sem expansão entre chaves (e sem codificá-las em seu script) é a parte um pouco complicada.Primeiro, aqui está um script que imprime todas as letras latinas em minúsculas:
seq
comando gera sequências numéricas.$(
)
executa substituição de comando ,$(seq 97 122)
sendo substituído pela saída deseq 97 122
. Estes são os códigos de caracteres paraa
throughz
.printf
comando poderoso pode transformar códigos de caracteres em letras (por exemplo,printf '\141'
impressõesa
, seguidas por uma nova linha ), mas os códigos devem estar em octal , enquanto asseq
saídas são decimais . Então, eu useiprintf
duas vezes: o interiorprintf %o $i
converte números decimais (fornecidos porseq
) em octal e é substituído peloprintf
comando externo . (Embora também seja possível usar hexadecimal , não é mais simples e parece ser menos portátil .)printf
interpreta\
seguido por um número octal como o caractere com esse código e\n
como uma nova linha. Mas o shell também usa\
como um caractere de escape. Um\
na frente$
vai impedir$
de causar uma expansão a ocorrer (neste caso, a substituição de comando ), mas eu não quero evitar isso, então eu ter escapado-lo com outro\
; essa é a razão para\\
. O segundo\
antesn
não precisa ser escapado porque, ao contrário\$
,\n
não tem um significado especial para o shell em uma sequência de aspas duplas.'
) também são uma parte importante da sintaxe de citação de shell, por acaso não as usei nesse script.É portátil para a maioria dos sistemas Unix e não depende de qual shell Bourne você usa. No entanto, alguns sistemas tipo Unix não são
seq
instalados por padrão (eles tendem a usarjot
, o que não é instalado por padrão na maioria dos sistemas GNU / Linux). Você pode usar um loop comexpr
substituição aritmética ou para aumentar ainda mais a portabilidade, se precisar:Isso usa um loop
while
com o[
comando para continuar fazendo loop apenas quando$i
estiver dentro do alcance.Em vez de imprimir o alfabeto inteiro, seu script define uma variável
n
e imprime as primeiras$n
letras minúsculas. Aqui está uma versão do seu script que não depende de recursos específicos do Bash e funciona no Dash, mas requerseq
:Ajustar o valor das
n
alterações quantas letras são impressas, como no seu script.Aqui está uma versão que não requer
seq
:Existe
$stop
um maior que o código de caractere da última letra que deve ser impressa; portanto, uso-lt
(menor que) do que-le
(menor ou igual) ao[
comando. (Também teria funcionado para criarstop=$((i + n - 1))
e usar[ $i -le $stop ]
).fonte