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 bashvez de sh. Seu linha de hashbang na parte superior ( #!/bin/bash) especifica, bashmas só é efetiva se você executar o script, como o heemayl explicou . Se você passar o nome do script para sh, shnão será chamado automaticamente bash, 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:
- Uma matriz . Isso ocorreu primeiro, e foi isso que produziu o erro quando você tentou executar seu script com o shell Dash . A expressão entre parênteses
( {a..z} ), à qual você atribui chars, cria uma matriz e ${chars[i]}, que aparece no seu loop, é indexada nela.
- Expanda a cinta. No Bash, e também em muitas outras conchas,
{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, esse não é um recurso universal (ou padronizado) dos shells no estilo Bourne, e o Dash não o suporta.
- O C-estilo alternativo
forsintaxe -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), o forloop 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 forloop 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:
#!/bin/sh
for i in $(seq 97 122); do
printf "\\$(printf %o $i)\n"
done
- O
seqcomando gera sequências numéricas. $( )executa substituição de comando , $(seq 97 122)sendo substituído pela saída de seq 97 122. Estes são os códigos de caracteres para athrough z.
- O
printfcomando poderoso pode transformar códigos de caracteres em letras (por exemplo, printf '\141'impressões a, seguidas por uma nova linha ), mas os códigos devem estar em octal , enquanto as seqsaídas são decimais . Então, eu usei printfduas vezes: o interior printf %o $iconverte números decimais (fornecidos por seq) em octal e é substituído pelo printfcomando externo . (Embora também seja possível usar hexadecimal , não é mais simples e parece ser menos portátil .)
printfinterpreta \seguido por um número octal como o caractere com esse código e \ncomo 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 \antes nnão precisa ser escapado porque, ao contrário \$, \nnã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 a barra invertida são usadas na programação de shell, consulte a seção sobre citações no padrão internacional . Consulte também 3.1.2 Citação no Manual de Referência do Bash , especialmente 3.1.2.1 Caractere de escape e 3.1.2.3 aspas duplas . (Aqui está a seção inteira , no contexto.) Observe que aspas simples (
') 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 seqinstalados por padrão (eles tendem a usar jot, o que não é instalado por padrão na maioria dos sistemas GNU / Linux). Você pode usar um loop com exprsubstituição aritmética ou 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 loop whilecom o [comando para continuar fazendo loop apenas quando $iestiver dentro do alcance.
Em vez de imprimir o alfabeto inteiro, seu script define uma variável ne imprime as primeiras $nletras 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 seq:
#!/bin/sh
n=3 start=97
for i in $(seq $start $((start + n - 1))); do
printf "\\$(printf %o $i)\n"
done
Ajustar o valor das nalterações quantas letras são impressas, como no seu script.
Aqui está uma versão que não requer seq:
#!/bin/sh
n=3 i=97 stop=$((i + n))
while [ $i -lt $stop ]; do
printf "\\$(printf %o $i)\n"
i=$((i + 1))
done
Existe $stopum 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 criar stop=$((i + n - 1))e usar [ $i -le $stop ]).