Chamando a função no script Shell

5

Eu escrevi uma função simples no shell que retorna 0 ou 1 com base em alguma condição.Deixe-me chamar esse nome de função foo

foo(){

...

...

}

Agora estou tentando chamar foo se a seguinte condição: -

if ( foo $1 )

...

..

Funciona bem.Mas quando eu usei seguir a abordagem para chamar, então eu recebo o erro

if [ foo $1 ]

...

...

Por que isso gera erro como "esperado um operador unário"?

    
por rahul sharma 03.05.2018 / 21:56

3 respostas

5

Quando você usa:

if ( foo $1 )

Você está executando foo $1 em uma subshell e if está agindo em seu status de saída.

Quando você usa:

if [ foo $1 ]

Você está tentando usar o shell test e foo não é um operador de teste válido. Você pode encontrar os operadores de teste válidos aqui .

Não é necessariamente relevante para o seu problema, mas você também deve sempre citar variáveis, especialmente dentro dos colchetes de teste do shell. O teste de shell terá sucesso simplesmente com a presença de algo. Por isso, mesmo quando utiliza um operador de teste válido, pode obter resultados indesejados:

$ unset var
$ [ -n $var ] && echo yes
yes
$ [ -n "$var" ] && echo yes
$ [ -n "" ] && echo yes
$ [ -n ] && echo yes
yes
$ [ foo ] && echo yes
yes
$ [ foo bar ] && echo yes
-bash: [: foo: unary operator expected

A presença de uma única string dentro do teste de shell será avaliada como true quando a presença de duas ou mais strings espera que um deles seja um operador de teste válido.

    
por 03.05.2018 / 22:05
3
As declarações

if lidam com o status de saída dos comandos. Sua função deve return status de saída ou retornar uma string. Para o seu propósito, return parece mais adequado. Retorna 0 para conclusão bem-sucedida da função e qualquer outra coisa se ocorrer um erro. Exemplo:

$ foo(){ [ -e '/etc/passwd' ] && return 0;  }
$ if foo; then echo "/etc/passwd exists"; fi
/etc/passwd exists

De fato, deve-se notar que o que você geralmente vê como if [ ... ]; then... é exatamente igual a if test ...; then... porque [ e test são o mesmo comando e retornam zero ou status de saída diferente de zero para indicar se o erro ocorreu.

    
por 03.05.2018 / 22:15
3

Além do que outros usuários disseram, a sintaxe real do comando if compound é:

if compound_list
then compound_list
[elif compound_list
then compound_list]...
[else compound_list]
fi

Onde compound_list é, basicamente, uma lista de qualquer número de comandos. if verificará o código de saída do último comando do primeiro COMPOUND_LIST para decidir o que executar (o then ... , um dos elif ...; then ... ou else ... ).

Isso significa que você pode reescrevê-lo assim:

if foo "$1"; then
  # Code to execute if foo returns 0
else
  # Code to execute if foo returns 1
fi

Se foo puder retornar muitos outros status ( 2 , 3 , ..., 254 , 255 ), usar case seria melhor:

foo "$1"

case "$?" in
  0) # Code to execute if foo returns 0 ;;
  1) # Code to execute if foo returns 1 ;;
  2) # Code to execute if foo returns 2 ;;
  3) # Code to execute if foo returns 3 ;;
  ...
  254) # Code to execute if foo returns 254 ;;
  255) # Code to execute if foo returns 255 ;;
esac

Editar 1

is ";" after "$1" is defined in syntax?

Sim e, como Kusalananda afirmou, é usado como delimitador de comandos.

POSIX define os seguintes comandos:

  • Comando simples: [assignments] program [arguments] [redirections]
  • Pipeline: [!] command [pipe_operator command]...
  • Lista:
    • lista AND-OR: pipeline [and-or_list_operator pipeline]...
    • Lista composta: and-or_list [compound_list_operator and-or_list]
  • Comando composto:
    • Agrupando comandos:
      • ( compound_list )
      • { compound_list; }
    • Para: for name [in words]; do compound_list; done
    • Caso: case word in [[(] patterns ) compound_list ;;]... esac
    • Se: if compound_list; then compound_list; [elif compound_list; then compound_list;]... [else compound_list;] fi
    • Enquanto: while compound_list; do compound_list; done
    • Até: until compound_list; do compound_list; done
  • Comando de definição de função: name() compound_command [redirections]

Um compound_list_operator pode ser um ponto-e-vírgula ou uma nova linha e é usado em um contexto compound_list / for / case / if / while / until .

Observe que um ponto-e-vírgula também é necessário quando, no comando { compound_list; } , o último comando de compound_list e o colchete de fechamento } estão na mesma linha.

    
por 03.05.2018 / 22:24