Shell: Usando a função com parâmetros em if

8

Estou tentando executar o código abaixo, mas quando tento usar minha função na instrução if, recebo o -bash: [: too many argumentserro. Por que isso está acontecendo?

Agradeço antecipadamente!

notContainsElement () {
  local e match="$1"
  shift
  for e; do [[ "$e" == "$match" ]] && return 1; done
  return 0
}

list=( "pears" "apples" "bananas" "oranges" )
blacklist=( "oranges" "apples" )
docheck=1

for fruit in "${list[@]}"
do
    if [ notContainsElement "$fruit" "${blacklist[@]}" -a $docheck = 1 ]
    then
        echo $fruit
    fi
done
Andrea Silvestri
fonte
1
Use shellcheck.net (ou sua versão offline). Ele encontra o problema mencionado nas respostas, embora com uma explicação muito menos detalhada e sem solução.
David Foerster

Respostas:

14

Ao usar, if [ ... ]você está realmente usando o [utilitário (que é o mesmo que, testmas requer que o último argumento seja ]).

[não entende para executar sua função, espera seqüências de caracteres. Felizmente, você não precisa usar [nada aqui (pelo menos para a função):

if [ "$docheck" -eq 1 ] && notContainsElement "$fruit" "${blacklist[@]}"; then
  ...
fi

Observe que também estou verificando o número inteiro primeiro, para que possamos evitar chamar a função se $dochecknão for 1.

Isso funciona porque ifrecebe um comando arbitrário e decide o que fazer a partir do status de saída desse comando. Aqui, usamos um [ ... ]teste juntamente com uma chamada para sua função &&, criando um comando composto. O status de saída do comando composto seria verdadeiro se o [ ... ]teste e a função retornassem zero como status de saída, sinalizando sucesso.

Como uma nota de estilo, eu não teria o teste de função se a matriz não não contêm o elemento, mas se se faz contêm o elemento e, em seguida,

if [ "$docheck" -eq 1 ] && ! contains "$fruit" "${blacklist[@]}"; then ...

Ter um teste de função uma bagunça vontade negativa a lógica em casos onde você fazer quer testar se a matriz contém o elemento ( if ! notContainsElement ...).

Kusalananda
fonte
Muito obrigado pela resposta e pelos outros conselhos!
Andrea Silvestri
3

tentar

if notContainsElement "$fruit" "${blacklist[@]}" && test "$docheck" = 1
then
  • -aopção não é um shell ou uma testopção

aqui você tem teste em duas partes

notContainsElement "$fruit" "${blacklist[@]}"
test $docheck = 1 ## or [ $docheck = 1 ]

você liga então ifusando

if cmd1 && cmd2

como indicado -aé uma opção de teste, mas só pode ser usado com outra opção de teste, portanto, você pode usar

if [ "$a" -lt "$b" -a "$a" -lt "$c" ]

para testar que $aé menor que ambos $be $c, mas você não pode usar outro comando no escopo de teste.

Archemar
fonte
arg, @Kusalananda foi gatilho mais rápido no mundo web selvagem outra vez;)
Archemar
RSI é o preço que pago por isso.
Kusalananda
-aé uma opção de teste , significa AND.
Hyde
@hyde Exceto que foi marcado como obsoleto no padrão POSIX.
Kusalananda
1
@Archemar, ... considerar corrigir os erros citando ainda presente em seus exemplos (sem aspas $docheck, unquoted $a/ $b/ etc no último exemplo).
Charles Duffy
0

Aqui está uma alternativa que algumas pessoas podem não gostar. Converta sua matriz da lista negra em uma sequência e veja se a sequência com uma fruta removida é a mesma. Editado para preencher as strings com espaços. Agradecemos a Scott por apontar o problema da maçã / abacaxi.

badlist=" ${blacklist[@]} "
for f in "${list[@]}"
do
    if [[ "${badlist/" $f "/}" == "$badlist" ]]
    then
        echo "$f"
    fi
done

Eu acho que isso é mais simples, mas falta a lógica && que muitos preferem.

Wastrel
fonte
(1) Isso falha no caso de uma das listfrutas estar contida em uma delas blacklist. Por exemplo, se mudarmos blacklistpara ( "oranges" "pineapples" ), a saída do seu script não mudará. ... (continua)
Scott
(Continua) ... (2) Não entendo bem o que você quer dizer com "acho que isso é mais simples, mas não possui a lógica && que muitos preferem". Muitas vezes, é mais fácil simplificar as coisas, deixando de fora a funcionalidade. Como Albert Einstein pode ou não ter dito, "tudo deve ser feito o mais simples possível, mas não mais simples". Por que você deixou de fora o &&? (3) Quando você publicar um código, identifique-o adequadamente.
Scott
Bem, tentei usar o recuo de 4 espaços, mas parece que não funcionou. Entendo o que você quer dizer com abacaxi.
Wastrel
Também não é possível distinguir entre uma única entrada da lista two wordse dois itens subsequentes twoe words. E se sua lista continha *como uma entrada, ela corresponderia a tudo. (E porque você não está citando o $fno que deveria ser echo "$f", se você se tentar repetir tal elemento, seria substituída por uma lista de nomes de arquivos no diretório atual).
Charles Duffy
Eu fiz algumas edições. Isso não é trivial quando os dados nas matrizes são arbitrários. Suponha que "maçãs" esteja na lista negra e "maçãs Granny Smith" seja um elemento da outra matriz. Eu acho que o código do OP tem problemas semelhantes. As matrizes devem ser feitas de elementos que "funcionam".
Wastrel