Compruebe si alguno de los parámetros de un script bash coincide con una cadena

67

Estoy tratando de escribir un script donde quiero verificar si alguno de los parámetros pasados ​​a un script bash coincide con una cadena. La forma en que lo configuro ahora es

if [ "$3" != "-disCopperBld" -a "$4" != "-disCopperBld" -a "$5" != "-disCopperBld" -a "$6" != "-disCopperBld"]

pero puede haber una gran cantidad de parámetros, por lo que me preguntaba si hay una mejor manera de hacer esto.

Gracias

EDITAR: probé este fragmento de código y llamé al script con la opción, -disableVenusBld, pero aún imprime "Iniciando compilación". ¿Estoy haciendo algo mal? ¡Gracias por adelantado!

while [ $# -ne 0 ]
do
    arg="$1"
    case "$arg" in
        -disableVenusBld)
            disableVenusBld=true
            ;;
        -disableCopperBld)
            disableCopperBld=true
            ;;
        -disableTest)
            disableTest=true
            ;;
        -disableUpdate)
            disableUpdate=true
            ;;
        *)
            nothing="true"
            ;;
    esac
    shift
done

if [ "$disableVenusBld" != true ]; then
    echo "Starting build"
fi
iman453
fuente
Gracias por las respuestas chicos, agradezco que se tomen un tiempo para ayudarme. Intenté un trozo de código, pero parece que no puedo entender qué está mal. ¿Algunas ideas? (He pegado el código en una edición de mi publicación original)
iman453
Hmm: funciona para mi. Agregué #! /bin/sh -a la parte superior de lo que has incluido allí, hice que el script fuera ejecutable, luego ./t.shimprime "Iniciando compilación", pero ./t.sh -disableVenusBldno imprime nada.
Norman Gray

Respuestas:

59

Parece que estás manejando opciones en un script de shell. Aquí está el modismo para eso:

#! /bin/sh -

# idiomatic parameter and option handling in sh
while test $# -gt 0
do
    case "$1" in
        --opt1) echo "option 1"
            ;;
        --opt2) echo "option 2"
            ;;
        --*) echo "bad option $1"
            ;;
        *) echo "argument $1"
            ;;
    esac
    shift
done

exit 0

(Hay un par de convenciones para sangrar el ;;, y algunos shells le permiten dar las opciones como (--opt1), para ayudar con la combinación de llaves, pero esta es la idea básica)

Gris normando
fuente
3
Una shiftdeclaración se usa cuando el número de argumentos de un comando no se conoce de antemano, por ejemplo, cuando los usuarios pueden dar tantos argumentos como quieran. En tales casos, los argumentos se procesan en un whilebucle con una condición de prueba de $#. Esta condición es verdadera siempre que el número de argumentos sea mayor que cero. La $1variable y la shiftdeclaración procesan cada argumento. El número de argumentos se reduce cada vez que shiftse ejecuta y finalmente se convierte en cero, sobre el cual whilesale el bucle. fuente
Serge Stroobandt
Aquí hay un ejemplo similar con echo $1 | sedprocesamiento de valor de argumento adicional .
Serge Stroobandt
26

Esto funcionó para mí. Hace exactamente lo que pidió y nada más (sin procesamiento de opciones). Si eso es bueno o malo es un ejercicio para el afiche :)

if [[ "$*" == *YOURSTRING* ]]
then
    echo "YES"
else
    echo "NO"
fi

Esto aprovecha el manejo especial de $* bash super-test [[... ]]brackets.

Rich Homolka
fuente
2
En mi humilde opinión, esta tenía que ser la respuesta más correcta, ya que la pregunta solo requiere verificar la presencia de un parámetro. Sin embargo, he editado, cambiando $*a $@, ya que la cadena a probar podría tener espacios y agregar un enlace a la documentación de bash al respecto.
h7r
99
¿Querías usar el operador = ~? De lo contrario, no veo por qué esto debería funcionar, y de hecho no funciona cuando intento el script exacto.
Seppo Enarvi
3
No funciona. bash -c 'echo args=$*; [[ "$@" == "bar" ]] && echo YES || echo NO' -- foo bar
Tobia
2
Esto compara toda la lista de argumentos con your string. Creo que debe hacer lo que sugiere esta respuesta . es decir: bash -c 'echo args=$*; for i in "$@" ; do [[ $i == "bar" ]] && echo "Is set!" && break ; done' -- bar foofuncionaría
Starfry
2
Esta respuesta ha sido incorrecta durante los últimos cuatro años porque la edición de h7r la rompió. La respuesta original (que ahora he restaurado) funciona, siempre que "su cadena" no contenga caracteres globales y con algunos falsos positivos. Por ejemplo, si el comando es create a new certificatey "su cadena" es cat, esto informará una coincidencia porque certificate contiene cat .
Scott
8

¿Qué tal buscar (con comodines) todo el espacio de parámetros:

if [[ $@ == *'-disableVenusBld'* ]]
then

Editar: Ok, ok, entonces esa no era una respuesta popular. ¿Qué tal este, es perfecto !:

if [[ "${@#-disableVenusBld}" = "$@" ]]
then
    echo "Did not find disableVenusBld"
else
    echo "Found disableVenusBld"
fi

Edit2: Ok, ok, tal vez esto no sea perfecto ... Creo que funciona solo si -param está al comienzo de la lista y también coincidirá con -paramXZY o -paramABC. Sigo pensando que el problema original se puede resolver muy bien con la manipulación de bash string, pero no lo he resuelto aquí ... ¿Puedes?

Rico
fuente
Su segunda sugerencia, comparar la sustitución de filtrado con la sustitución completa, funciona razonablemente bien y tiene la ventaja de no interrumpir la lista de argumentos.
Donal Fellows
¿Podría explicar qué hace la segunda sugerencia (especialmente ${@#)?
velop
1
@velop ¡Seguro! Entonces, ¿sabes que $@es una variable especial que contiene todos los argumentos de la línea de comandos? Bueno, acabo de utilizar la manipulación de cadenas Bash en esa variable para eliminar la subcadena "-disableVenusBld", y luego la comparo con la original $@. Entonces, si $@es igual, -foo -barentonces ${@#-disableVenusBld}todavía lo sería -foo -bar, por lo que puedo ver que la bandera que estoy buscando no está presente. Sin embargo, si $@es igual, -foo -disableVenusBld -barentonces ${@#-disableVenusBld}sería lo -foo -barque no es igual $@, ¡lo que me dice que la bandera que estoy buscando está presente! Genial eh!
Rico
@velop Obtenga más información sobre la manipulación de cadenas Bash aquí: tldp.org/LDP/abs/html/string-manipulation.html
Rico
@Rich bastante limpio ^^, gracias por la explicación.
velop
4
disCopperBld=
for x; do
  if [ "$x" = "-disCopperBld" ]; then disCopperBld=1; break; fi
done
if [ -n "$disCopperBld" ]; then
  ...
fi

Si necesita probar solo los parámetros a partir de $3, realice la búsqueda en una función:

## Usage: search_trailing_parameters NEEDLE NUM "$@"
## Search NEEDLE amongst the parameters, skipping $1 through ${$NUM}.
search_trailing_parameters () {
  needle=$1
  shift $(($2 + 2))
  for x; do
    if [ "$x" = "$needle" ]; then return 0; fi
  done
  return 1
}
if search_trailing_parameters -disCopperBld 2 "$@"; then
  ...
fi

Pero me pregunto por qué estás tratando de hacer esto en primer lugar, no es una necesidad común. Por lo general, procesaría las opciones en orden, como en la respuesta de Dennis a su pregunta anterior .

Gilles 'SO- deja de ser malvado'
fuente