Shell: Uso de la función con parámetros en if

8

Estoy tratando de ejecutar el código a continuación, pero cuando trato de usar mi función en la instrucción if obtengo el -bash: [: too many argumentserror. Por que esta sucediendo?

¡Gracias de antemano!

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
fuente
1
Utilice shellcheck.net (o su versión sin conexión). Encuentra el problema mencionado en las respuestas, aunque con una explicación mucho menos detallada y sin solución.
David Foerster

Respuestas:

14

Cuando se usa if [ ... ], en realidad está usando la [utilidad (que es igual testpero requiere que el último argumento sea ]).

[no entiende ejecutar su función, espera cadenas. Afortunadamente, no es necesario utilizarlo [aquí (al menos para la función):

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

Tenga en cuenta que también estoy comprobando el número entero primero, para que podamos evitar llamar a la función si $docheckno es 1.

Esto funciona porque iftoma un comando arbitrario y decide qué hacer desde el estado de salida de ese comando. Aquí usamos una [ ... ]prueba junto con una llamada a su función, con &&un intermedio, creando un comando compuesto. El estado de salida del comando compuesto sería verdadero si tanto la [ ... ]prueba como la función devolvieran cero como sus estados de salida, indicando éxito.

Como una nota de estilo, que no tendría la prueba de funcionamiento si la matriz no no contiene el elemento, pero si, si lo hace contener el elemento, y luego

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

Tener una prueba de función un lío voluntad negativa a la lógica en los casos en que se haga quiere probar si la matriz contiene el elemento ( if ! notContainsElement ...).

Kusalananda
fuente
¡Muchas gracias por la respuesta y los otros consejos!
Andrea Silvestri
3

tratar

if notContainsElement "$fruit" "${blacklist[@]}" && test "$docheck" = 1
then
  • -ala opción no es ni un shell ni una testopción

aquí tienes una prueba de dos partes

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

luego vinculas al ifusar

if cmd1 && cmd2

como se señaló -aes una opción de prueba, pero solo se puede usar con otra opción de prueba, por lo tanto, puede usar

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

para probar que $aes inferior a ambos $by $c, pero no puede usar otro comando dentro del alcance de la prueba.

Archemar
fuente
arg, @Kusalananda fue nuevamente el arma más rápida en la web salvaje del mundo;)
Archemar
RSI es el precio que pago por eso.
Kusalananda
-aes la opción de prueba , significa AND.
hyde
@hyde Excepto que se ha marcado como obsoleto en el estándar POSIX.
Kusalananda
1
@Archemar, ... considere corregir los errores de citas que todavía están presentes en sus ejemplos (sin comillas $docheck, sin comillas $a/ $b/ etc en el último ejemplo).
Charles Duffy
0

Aquí hay una alternativa que a algunas personas puede no gustarles. Convierta su matriz de lista negra en una cadena y vea si la cadena con una fruta eliminada es la misma. Editado para rellenar las cadenas con espacios. Gracias a Scott por señalar el problema de la manzana / piña.

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

Creo que esto es más simple, pero carece de la lógica && que muchos prefieren.

Derrochador
fuente
(1) Esto falla en el caso de que una de las listfrutas esté contenida dentro de una de las blacklistfrutas. Por ejemplo, si cambiamos blacklista ( "oranges" "pineapples" ), la salida de su script no cambia. ... (Continúa)
Scott
(Continúa) ... (2) No entiendo lo que quieres decir con "Creo que esto es más simple, pero carece de la lógica && que muchos prefieren". A menudo es más fácil simplificar las cosas al dejar de lado la funcionalidad. Como Albert Einstein pudo o no haber dicho, "Todo debe hacerse lo más simple posible, pero no más simple". ¿Por qué dejaste fuera el &&? (3) Cuando publique el código, sangra correctamente.
Scott
Bueno, intenté usar la sangría de 4 espacios, pero parece que no funcionó. Sin embargo, veo lo que quieres decir con las piñas.
Wastrel
Tampoco puede distinguir entre una sola entrada de lista two wordsy dos elementos posteriores, twoy words. Y si su lista contenía *como una entrada, coincidiría con todo. (Y porque no se está citando el $fen lo que debería ser echo "$f", si qué intenta hacer eco de un elemento tal, sería reemplazado con una lista de nombres de archivos en el directorio actual).
Charles Duffy
He hecho algunas ediciones. Esto no es trivial cuando los datos en las matrices son arbitrarios. Supongamos que "manzanas" está en la lista negra y que "manzanas Granny Smith" es un elemento de la otra matriz. Creo que el código del OP tiene problemas similares. Las matrices tienen que estar hechas de elementos que "funcionan".
Wastrel