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))
).