O que é uma prática recomendada para representar um valor booleano em um script de shell?

12

Eu sei que existem valores booleanos em bash , mas eu nunca os vejo usados em qualquer lugar.

Eu quero escrever um wrapper para algumas informações muitas vezes pesquisadas na minha máquina, por exemplo, se essa unidade USB específica estiver inserida / montada.

Qual seria a melhor prática para conseguir isso?

  • Uma string?

    drive_xyz_available=true
    
  • Um número (0 para verdadeiro, ≠ 0 para falso)?

    drive_xyz_available=0    # evaluates to true
    
  • Uma função?

    drive_xyz_available() { 
        if available_magic; then 
                return 0 
        else 
                return 1 
        fi
    }
    

Eu principalmente me pergunto, o que seria esperado por outras pessoas que gostariam de usar o wrapper. Eles esperariam um valor booleano, um comando como variável ou uma função para chamar?

Do ponto de vista da segurança, acho que a segunda opção é a mais segura, mas adoraria ouvir suas experiências.

    
por Minix 19.02.2015 / 10:57

3 respostas

2
bool(){ return "$((!${#1}))"; }

if bool "$var"
then : do true
else : do false

Basta definir uma variável para qualquer coisa, mas não nula para o acima, para funcionar, embora [ -n "$var" ] seja mais curto, se não tão óbvio.

Em geral, quando um script interpreta uma variável de ambiente como verdadeira ou falsa, ela interpretará qualquer valor como sendo verdadeiro (e às vezes usa o dito valor para configurar alguma opção) ou então um valor nulo como falso.

O acima retorna o valor booleano !not do len do seu primeiro argumento - se o argumento contiver qualquer número de caracteres diferente de 0, ele retorna 0, senão, se nenhum caractere, retorna 1. Este é o mesmo teste você pode executar com [ -n "$var" ] , basicamente, mas apenas envolve em uma pequena função chamada bool() .

Isto é tipicamente como uma variável flag funciona. Por exemplo:

[ -d "$dir" ] || dir=

Onde outras partes de um script precisam apenas procurar por qualquer valor em $dir para avaliar sua utilidade. Isso também é útil quando se trata de substituição de parâmetros - pois os parâmetros podem ser expandidos para valores padrão para preencher os vazios ou não definidos, mas, caso contrário, expandirão para um valor predefinido como ...

for set in yes ''
do echo "${set:-unset or null}"
done

... o que imprimiria ...

yes
unset or null

É claro que também é possível fazer o oposto com :+ , mas isso só pode dar um padrão pré-definido ou nada, enquanto o formulário acima pode lhe dar um valor ou um valor padrão.

E sobre as três opções - qualquer um poderia funcionar dependendo de como você escolhe implementá-lo. O retorno da função é autoteste, mas, se esse retorno precisar ser salvo por qualquer motivo, precisará ser colocado em uma variável. Depende do caso de uso - o valor booleano que você deseja avaliar um teste é feito uma vez e feito? Se assim for, faça a função, senão qualquer um dos outros dois é provavelmente necessário.

    
por 19.02.2015 / 11:43
3

Em bash , cada variável é essencialmente uma string (ou uma matriz ou uma função, mas vamos falar sobre variáveis regulares aqui).

As condições são analisadas com base nos valores de retorno dos comandos de teste - o valor de retorno não é uma variável, é um estado de saída. Quando você avalia if [ ... ] ou if [[ ]] ou if grep something ou qualquer coisa assim, o valor de retorno 0 (não a cadeia 0, mas o status de saída 0 = sucesso) significa verdadeiro e o restante significa falso (portanto, exatamente o oposto do que você está acostumado em linguagens de programação compiladas, mas como há uma maneira de ter sucesso e muitas maneiras de falhar, e o resultado esperado da execução geralmente é sucesso, 0 é usado como o resultado padrão mais comum se nada der errado). Isso é muito útil porque qualquer binário pode ser usado como teste - se falhar, é falso, caso contrário, é verdade.

true e false programs (geralmente substituídos por builtins) são apenas pequenos programas úteis que não fazem nada - true consegue fazer nada e sai com 0, enquanto false tenta não fazer nada e "falha ", saindo com 1. Parece inútil, mas é muito útil para scripts.

Quanto a como passar a veracidade, depende de você. É muito comum usar apenas "y" ou "yes" como verdade e usar if [ x"$variable" = x"yes" ] (anexada a string fictícia x , porque se $variable tiver comprimento zero, isso protege a criação de um comando falso if [ = "yes" ] , que não analisa). Também pode ser útil simplesmente usar uma string vazia para false e usar [ -z "$variable ] para testar se é zero-length (ou -n para ser diferente de zero).

De qualquer forma, é muito raro realmente precisar passar valores booleanos em bash - é muito mais comum simplesmente exit na falha, ou retornar um resultado útil (ou zero se algo der errado, e testar para vazio string), e a maioria dos casos pode testar a falha diretamente do status de saída.

No seu caso, você quer uma função que funcionará como qualquer outro comando (portanto, retorne 0 em caso de sucesso), então sua última opção parece ser a escolha certa.

Além disso, talvez você nem precise da declaração return . Se a função for simples o suficiente, você pode usar o fato de que simplesmente retorna o status do último comando executado na função. Então sua função pode ser simplesmente

drive_xyz_available() {
   [ -e /dev/disk/by-uuid/whatever ]
}

se você está testando a existência de um nó de dispositivo (ou grep /proc/mounts para verificar se ele está montado?).

    
por 19.02.2015 / 11:44
-2

Basicamente, qualquer número que não seja 0 é verdadeiro e 0 é falso. Motivo para retornar valores como 0 para um final bem-sucedido de um script ou qualquer outro número para identificar diferentes tipos de erros.

$? retornará o código de saída do comando / executável anterior, sendo 0 com sucesso e qualquer outro número o erro retornado.

Então, eu usaria esse método para true / false. if (( ! $? ));then OK;else NOOK;fi

    
por 19.02.2015 / 11:54