Passando um sinalizador booleano para uma função?

4

Eu tenho uma função que depende de um argumento em que a funcionalidade é alterada.
Eu sei que posso fazer:

function foo {  
  PARAM1=$1  
  PARAM2="$2"  
  VAR=$3  
  if[[ -z "$VAR" ]]; then  
   # code here  
  else  
   # other code here  
  fi  
}  

Eu queria saber se existe uma abordagem mais apropriada para o bash. Isso funcionaria, mas eu não gostaria de ter algo parecido com

foo "x" "y" "blah"  
foo "x" "y" "true"  
foo "y" "y" "1"

tudo para ser equivalente.

Existe uma abordagem mais adequada ao Bash?

    
por Jim 17.07.2018 / 09:40

3 respostas

2

Você pode fornecer uma opção de linha de comando para sua função. Usar opções de linha de comando que não usam argumentos é uma maneira comum de fornecer valores binários / booleanos ("on / off", "true / false", "ativar / desativar") para shell scripts, funções de shell e utilitários em geral.

foo () {
    local flag=0

    while getopts 't' opt; do
        case $opt in
            t) flag=1 ;;
            *) echo 'Error in command line parsing' >&2
               exit 1
        esac
    done
    shift "$(( OPTIND - 1 ))"

    local param1=$1
    local param2=$2

    if [ "$flag" -eq 1 ]; then
        # do things for "foo -t blah blah"
    else
        # do things for "foo blah blah"
    fi
}

A opção -t age como um sinalizador booleano para o usuário. Usá-lo definiria flag dentro da função como 1. A opção -t seria usada como o primeiro argumento para a função.

Chamar a função seria feito usando

foo "some value" "some other value"

ou

foo -t "some value" "some other value"

em que a última chamada definiria a variável flag na função como 1.

    
por 17.07.2018 / 10:36
2

Em geral

Em geral, a passagem de booleanos para funções, em qualquer idioma, é ilegível. por exemplo. %código%. O leitor fica imaginando o que é a verdade.

Portanto, use uma enumeração: calculate_interest 5y 4% true . Agora você pode fazer { per_month, per_year } . Isso é mais legível.

No bash

Bash não é estaticamente digitado, (ou strongmente tipado, ou tem muito de um tipo de sistema), então você pode passar muitos valores diferentes. Um liderará dessa maneira, os outros não. Não é desejado ter muitos valores diferentes que levam ao mesmo caminho.

Portanto, adicione código para verificar se a entrada é um dos dois valores aceitáveis. Faça isso no início da função, você não vai querer desistir de fazer algo.

O que fazer se você precisar chamar uma função que usa um booleano

Então alguém não seguiu o meu conselho, e você tem que chamar uma função que usa um booleano. O que você pode fazer para tornar seu código legível?

  • Se o idioma (como o Python) permitir argumentos nomeados, por exemplo calculate_interest 5y 4% per_year , depois use-os. Isso ajudará, mas não informa o significado de calculate_interest 5y 4% per_year=True .
  • Se o idioma não tiver argumentos nomeados, as únicas opções são viver com código ilegível (não uma opção) ou agrupar as funções em funções alfabetizadas.
por 17.07.2018 / 10:26
1

Eu recomendo seguir um formato como este:

foo() {
  # Limit scope of variables
  local 'opt1' 'opt2' 'opt3' 'operands'

  # Default values
  opt1='default1'
  opt2='default2'
  opt3='false'
  operands=()

  # Arguments handling
  while (( ${#} > 0 )); do
    case "${1}" in
      ( '--opt1='* ) opt1="${1#*=}" ;;           # Handles --opt1
      ( '--opt2='* ) opt2="${1#*=}" ;;           # Handles --opt2
      ( '--opt3='* ) opt3="${1#*=}" ;;           # Handles --opt3
      ( '--' ) operands+=( "${@:2}" ); break ;;  # End of options
      ( '-'?* ) ;;                               # Discard non-valid options
      ( * ) operands+=( "${1}" )                 # Handles operands
    esac
    shift
  done

  ...
}

Dessa forma, a função será mais robusta e legível:

$ foo
Options:
  opt1: [default1]
  opt2: [default2]
  opt3: [false]
$ foo --opt1='value1' --opt2='value2' --opt3='true' 'foo' 'bar' 'baz'
Options:
  opt1: [value1]
  opt2: [value2]
  opt3: [true]
Operands:
  1: [foo]
  2: [bar]
  3: [baz]

Prós:

  • Fácil de ler e entender.
  • A sintaxe é semelhante a qualquer utilitário típico de linha de comando.
  • É fácil adicionar mais opções sem quebrar a compatibilidade.

Contras:

  • Pode ser um exagero para scripts pequenos e simples.
  • É difícil escrever um equivalente portátil e compatível com POSIX que também lida com opções longas e operandos.
por 18.07.2018 / 13:32