Shell: utilizzo della funzione con parametri in if


8

Sto cercando di eseguire il codice seguente, ma quando provo a utilizzare la mia funzione nell'istruzione if ottengo l' -bash: [: too many argumentserrore. Perché sta succedendo?

Grazie in anticipo!

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

1
Usa shellcheck.net (o la sua versione offline). Trova il problema menzionato nelle risposte, sebbene con una spiegazione molto meno dettagliata e senza soluzione.
David Foerster,

Risposte:


14

Quando si utilizza if [ ... ]si utilizza effettivamente l' [utilità (che è la stessa testma richiede che sia l'ultimo argomento ]).

[non capisce di eseguire la tua funzione, si aspetta stringhe. Fortunatamente, non è necessario utilizzare [affatto qui (almeno per la funzione):

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

Nota che sto anche controllando prima l'intero, quindi possiamo evitare di chiamare la funzione se $dochecknon è 1.

Questo funziona perché ifaccetta un comando arbitrario e decide cosa fare dallo stato di uscita di quel comando. Qui usiamo un [ ... ]test insieme a una chiamata alla tua funzione, con &&in mezzo, creando un comando composto. Lo stato di uscita del comando composto sarebbe vero se sia il [ ... ]test che la funzione restituissero zero come stati di uscita, segnalando il successo.

Come nota lo stile, non avrei il test funzionale se la matrice non non contiene l'elemento, ma se se lo fa contenere l'elemento, e poi

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

Avere un test di funzionamento un pasticcio volontà negativo fino logica nei casi in cui si fare desidera verificare se l'array contiene l'elemento ( if ! notContainsElement ...).


Grazie mille per la risposta e gli altri consigli!
Andrea Silvestri,

3

provare

if notContainsElement "$fruit" "${blacklist[@]}" && test "$docheck" = 1
then
  • -aL'opzione non è né una shell né testun'opzione

qui hai un test in due parti

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

si collega quindi in ifuso

if cmd1 && cmd2

come sottolineato -aè un'opzione di test, ma può essere utilizzata solo con altre opzioni di test, quindi è possibile utilizzare

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

per verificare che $asia inferiore a entrambi $be $c, ma non è possibile utilizzare altri comandi nell'ambito del test.


arg, @Kusalananda era di nuovo la pistola più veloce del mondo selvaggio;)
Archemar,

RSI è il prezzo che pago per quello.
Kusalananda

-aè un'opzione di test , significa AND.
hyde,

@hyde Tranne il fatto che è stato contrassegnato come obsoleto nello standard POSIX.
Kusalananda

1
@Archemar, ... considerano che fissa i bug citando ancora presenti nei tuoi esempi (non quotate $docheck, non quotate $a/ $b/ etc nell'ultimo esempio).
Charles Duffy,

0

Ecco un'alternativa che ad alcune persone potrebbe non piacere. Converti l'array della blacklist in una stringa e vedi se la stringa con un frutto rimosso è la stessa. Modificato per riempire le stringhe di spazi. Grazie a Scott per aver segnalato il problema mela / ananas.

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

Penso che sia più semplice, ma manca la logica di && che molti preferiscono.


(1) Ciò non riesce nel caso in cui uno dei listfrutti sia contenuto in uno dei blacklistfrutti. Ad esempio, se passiamo blacklista ( "oranges" "pineapples" ), l'output del tuo script non cambia. ... (proseguendo)
Scott,

(Proseguendo) ... (2) Non capisco cosa intendi per "Penso che sia più semplice, ma manca della logica di && che molti preferiscono." Spesso è più semplice semplificare le cose tralasciando la funzionalità. Come potrebbe aver detto Albert Einstein, "Tutto dovrebbe essere reso il più semplice possibile, ma non più semplice". Perché hai lasciato fuori il &&? (3) Quando pubblichi un codice, inseriscilo in modo appropriato.
Scott,

Bene, ho provato a usare il rientro dei 4 spazi ma sembra che non abbia funzionato. Capisco cosa intendi per gli ananas, però.
Wastrel,

Inoltre, non è possibile distinguere tra una singola voce dell'elenco two wordse due voci successive twoe words. E se la tua lista contenesse *una voce, corrisponderebbe a tutto. (E perché non stai citando il $fin quello che dovrebbe essere echo "$f", se si ha tenta di eco un tale elemento, si sarebbe sostituito con un elenco di nomi di file nella directory corrente).
Charles Duffy,

Ho apportato alcune modifiche. Questo non è banale quando i dati negli array sono arbitrari. Supponiamo che "mele" sia nella lista nera e che "mele Granny Smith" sia un elemento dell'altro array. Penso che il codice dell'OP abbia problemi simili. Le matrici devono essere costituite da elementi che "funzionano".
Wastrel,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.