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 de sh
. 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 para sh
, sh
nã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
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), o for
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:
#!/bin/sh
for i in $(seq 97 122); do
printf "\\$(printf %o $i)\n"
done
- O
seq
comando 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 a
through z
.
- O
printf
comando 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 seq
saídas são decimais . Então, eu usei printf
duas vezes: o interior printf %o $i
converte números decimais (fornecidos por seq
) em octal e é substituído pelo printf
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 \
antes n
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.
- 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 seq
instalados 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 expr
substituiçã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 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 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 n
alteraçõ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 $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 criar stop=$((i + n - 1))
e usar [ $i -le $stop ]
).