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 bash em vez de sh . Sua linha hashbang no topo ( #!/bin/bash ) especifica bash , mas só é efetiva se você > execute o script, como heemayl explicou . Se você passar o nome do script para sh , sh não chamará automaticamente bash , mas simplesmente executará o script. Isto porque uma vez que seu script está realmente rodando, a linha hashbang não tem efeito .
Sua outra alternativa, se você precisar escrever scripts totalmente portáteis que não dependam nos recursos do Bash, é mudar seu script para que ele funcione sem eles. Os recursos de Bash que você usa são:
- Uma matriz . Isso veio primeiro, então é isso que produziu o erro quando você tentou executar o script com o shell Dash . A expressão entre parênteses
( {a..z} ) , que você atribui a chars , cria uma matriz e ${chars[i]} , que aparece em seu loop, indexa-a.
-
Expansão de cinta. No Bash, e também em muitos outros shells,
{a..z} é expandido para 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 . No entanto, este não é um recurso universal (ou padronizado) de shells estilo Bourne, e Dash não suporta isso.
- O alternativo da sintaxe
for -loop no estilo C. Embora baseado na expansão aritmética , que é não específico para o Bash (embora alguns shells muito antigos, não compatíveis com POSIX também não o possuem, o% C_de% loop em estilo C é um Bash-ism e não é amplamente portáteis 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, você pode apenas querer 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. / p>
No entanto, você pode substituí-los por construções portáteis, se quiser. A matriz e o loop for do estilo C são fáceis de substituir; Gerar o intervalo de letras sem expansão de chaves (e sem codificá-las em seu script) é a única parte complicada.
Primeiro, aqui está um script que imprime todas as letras latinas em minúsculas:
#!/bin/sh
for i in $(seq 97 122); do
printf "\$(printf %o $i)\n"
done
- O comando
for gera seqüências numéricas. seq $( realiza substituição de comando , portanto ) é substituído pela saída de $(seq 97 122) . Estes são os códigos de caracteres de seq 97 122 a a .
-
O poderoso comando
z pode transformar os códigos de caracteres em letras (por exemplo , printf imprime printf '1' , seguido por uma nova linha ), mas os códigos devem ser em octal , enquanto a produz apenas em . Por isso usei seq duas vezes: o printf interno converte números decimais (fornecidos por printf %o $i ) em octal e é substituted no comando seq externo. (Embora também seja possível usar hexadecimal , não é mais simples e parece ser menos portável .)
-
printf interpreta printf seguido por um número octal como o caractere com esse código e \ como uma nova linha. Mas o shell também usa \n como um caractere de escape. Um \ na frente de \ impedirá $ de fazendo com que uma expansão ocorra (neste caso, substituição de comando ), mas não quero impedir isso, então escapei com outro $ ; essa é a razão para \ . O segundo \ antes de \ não precisa ter escape porque, ao contrário de n , $ não tem um significado especial para o shell em uma sequência de aspas duplas.
- Para obter mais informações sobre como as aspas duplas e as barras invertidas são usadas na programação de shell, consulte a seção citando na norma internacional . Veja também 3.1.2 Citando no Bash Reference Manual , especialmente 3.1.2.1 Caractere de escape e 3.1.2.3 Cotações duplas . (Aqui está toda a seção , no contexto.) Observe que aspas simples (
\n ) também são uma parte importante da sintaxe de citação do shell, por acaso não usei-os nesse script.
Isso é portátil para os sistemas mais Unix e não depende de qual shell estilo Bourne você usa. No entanto, alguns sistemas semelhantes a Unix não têm ' instalado por padrão (eles tendem a usar seq , que não é instalado por padrão na maioria dos sistemas GNU / Linux). Você pode usar um loop com jot ou substituição aritmética para aumentar ainda mais a portabilidade, se precisar:
#!/bin/sh
i=97
while [ $i -le 122 ]; do
printf "\$(printf %o $i)\n"
i=$((i + 1))
done
Isso usa um expr -loop com o comando while para continuar o loop somente quando [ estiver no intervalo.
Em vez de imprimir todo o alfabeto, o script define uma variável $i e imprime as primeiras letras n 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 requer $n :
#!/bin/sh
n=3 start=97
for i in $(seq $start $((start + n - 1))); do
printf "\$(printf %o $i)\n"
done
Ajustar o valor de seq altera quantas letras são impressas, como no seu script.
Aqui está uma versão que não exige 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 é um maior do que o código de caractere da última letra que deveria ser impressa, então eu uso $stop (menor que) em vez de -lt (menor que ou igual) com o comando -le . (Também teria trabalhado para fazer [ e usar stop=$((i + n - 1)) ).