erros de script DASH: Eu não acho que eu sei como configurar as variáveis corretamente

0
#!/bin/sh

export $REG=0x000000
export $DONE=0x4A9FFF

while $REG -le $DONE
   do  
    (($REG+1))
    printf 'wm8280_reg get 0x'$REG'\r\n' 
    sleep 1 
   done

Isso leva aos erros:

./wm8280_reg_get1.sh: line 3: export: '=000000': not a valid identifier
./wm8280_reg_get1.sh: line 4: export: '=4A9FFF': not a valid identifier
./wm8280_reg_get1.sh: line 6: -le: command not found

Tenho certeza de que dash usa -le para "Menor que ou igual", mas claramente estou errado. Além disso, não sei por que minhas variáveis estão erradas. O que estou fazendo errado?

    
por The Other NumberSix 29.01.2016 / 02:12

3 respostas

3

A sintaxe padrão (POSIX) sh , que deve funcionar em qualquer implementação conforme as versões recentes de dash , seria:

#!/bin/sh -

reg=0x000000
done=0x4A9FFF

while [ "$((reg))" -le "$((done))" ]; do
  reg=$((reg + 1))
  printf 'wm8280_reg get 0x%06X\r\n' "$reg"
  sleep 1 
done

Se você precisar ser portável para versões de dash anteriores a 0.5.5 (2009), será necessário:

#!/bin/sh -

reg=0x000000
done=0x4A9FFF

while [ "$(($reg))" -le "$(($done))" ]; do
  reg=$(($reg + 1))
  printf 'wm8280_reg get 0x%06X\r\n' "$reg"
  sleep 1 
done

A especificação POSIX costumava não ser muito clara sobre como o $((reg)) deveria ser expandido (ainda não está muito claro no texto, mas pelo menos a posição do Open Group foi esclarecida na lista de discussão e no suite de testes de conformidade) e dash usado para não suportar variáveis simples (sem $ ) em suas expressões aritméticas, enquanto a especificação para "$(($ver)) sempre foi muito mais clara.

Observe que $reg será decimal após a primeira invocação de reg=$(($reg + 1)) , portanto você também pode converter as variáveis em decimais no início. Observe também que ele imprimirá números 0 x 1 a 0 x 4AA000 (56 dias depois); uma maneira mais convencional (e legível de IMO) de escrevê-lo seria:

#!/bin/sh -

reg=$((0x000001))  done=$((0x4AA000))

while [ "$reg" -le "$done" ]; do
  printf 'wm8280_reg get 0x%06X\r\n' "$reg"
  sleep 1 
  reg=$(($reg + 1))
done

Além disso, não espere imprimir uma linha exatamente a cada segundo. Haverá um desvio causado pelo tempo gasto na execução desses comandos.

Detalhes:

  • export é exportar variáveis para o ambiente de comandos a serem executados. Não faz sentido usá-lo aqui. Essas variáveis são usadas aqui apenas para passar seu valor como argumento para comandos.
  • Você coloca $ na frente de uma variável quando deseja que o valor seja expandido. export $reg=0x000000 executaria um export value-of-reg=0x000000 .
  • while é seguido por um comando (ou uma lista de comandos) para executar cujo status de saída determina a condição do loop. Aqui, precisamos do comando [ (construído na maioria das shells) que pode ser usado para executar vários tipos de testes, como as comparações de inteiros.
  • esses operadores de comparação aritmética de [ suportam apenas constantes inteiras decimais, portanto usamos as expansões aritméticas do shell (que suportam hexadecimais) para convertê-las em decimais.
  • cosmético: por convenção, geralmente usamos nomes de variáveis maiúsculas para variáveis de ambiente ou variáveis que devem ter um escopo global em um script complexo que usa funções por exemplo.
por 01.02.2016 / 22:42
1

O exemplo

#!/bin/sh

export $REG=0x000000
export $DONE=0x4A9FFF

while $REG -le $DONE
   do  
    (($REG+1))
    printf 'wm8280_reg get 0x'$REG'\r\n' 
    sleep 1 
   done

deve mudar:

  • as duas linhas com export não devem ter $ prefixando as variáveis
  • use [ e ] em torno da expressão $REG -le $DONE (ou use test before)
  • citar variáveis quando elas são read , como na expressão.
  • use printf para formatação, não para string-concatenação

Então você teria algo como

#!/bin/sh

export REG=0x000000
export DONE=0x4A9FFF

while [ "$REG" -le "$DONE" ]
   do  
    (($REG+1))
    printf 'wm8280_reg get 0x%s\r\n' "$REG" 
    sleep 1 
   done

Esta linha

    while [ "$REG" -le "$DONE" ]

também pode ser escrito como

    while test "$REG" -le "$DONE"

(ambos são legais).

Uma rápida leitura da página de manual do painel não indica que ela respeita as constantes hexadecimais. Você pode ter que alterar essas exportações para usar valores decimais, por exemplo,

export REG=0
export DONE=489063

e o printf poderia usar %06X em vez de %s , para imprimir os valores em hexadecimal.

Usando a sugestão do cuonglm, você pode usar

while [ "$((REG))" -le "$((DONE))" ]  

e

REG=$(($((REG))+1))

Isso se refere ao shell POSIX 2.6.4 Expansão aritmética :

Only the decimal-constant, octal-constant, and hexadecimal-constant constants specified in the ISO C standard, Section 6.4.4.1 are required to be recognized as constants.

No entanto, testando dash no Debian 7 e 8, a expressão de incremento provavelmente não funciona como pretendido pelo OP, porque o resultado é decimal, enquanto o printf assume que é hexadecimal. Além disso, REG=((REG+1)) não funciona nessa versão do traço. (bash é uma história diferente, claro).

    
por 29.01.2016 / 02:25
0

Certo, obrigado a todos pela sua contribuição. O script final se parece com:

#!/bin/sh

export REG=0
export DONE=4890632

while [ "$((REG))" -le "$((DONE))" ]
   do  
    wm8280_reg get $REG >> "wm_reg_dump.txt"
    REG=$(($((REG))+1))
   done

Isso é executado no DASH e tem a saída necessária. Claro, o código leva 8 horas para ser executado, mas ei, configure e esqueça:)

    
por 01.02.2016 / 21:00

Tags