Pregunta En bash, ¿cómo puedo verificar si una cadena comienza con algún valor?


Me gustaría comprobar si una cadena comienza con "nodo", p. "node001". Algo como

if [ $HOST == user* ]  
  then  
  echo yes  
fi

¿Cómo puedo hacerlo correctamente?


Además, necesito combinar expresiones para verificar si HOST es "usuario1" o comienza con "nodo"

if [ [[ $HOST == user1 ]] -o [[ $HOST == node* ]] ];  
then  
echo yes 
fi

> > > -bash: [: too many arguments

¿Cómo hacerlo correctamente?


515
2018-01-31 16:12


origen


Respuestas:


Este fragmento en el Guía avanzada de scripts de Bash dice:

# The == comparison operator behaves differently within a double-brackets
# test than within single brackets.

[[ $a == z* ]]   # True if $a starts with a "z" (wildcard matching).
[[ $a == "z*" ]] # True if $a is equal to z* (literal matching).

Entonces tu lo tuviste casi correcto; tu necesitas doble corchetes, no corchetes individuales.


Con respecto a su segunda pregunta, puede escribirla de esta manera:

HOST=user1
if  [[ $HOST == user1 ]] || [[ $HOST == node* ]] ;
then
    echo yes1
fi

HOST=node001
if [[ $HOST == user1 ]] || [[ $HOST == node* ]] ;
then
    echo yes2
fi

Que hará eco

yes1
yes2

Bash's if es difícil acostumbrarse a la sintaxis (IMO).


711
2018-01-31 16:16



Si está utilizando un bash reciente (v3 +), sugiera el operador de comparación de expresiones regulares de bash =~, es decir

if [[ "$HOST" =~ ^user.* ]]; then
    echo "yes"
fi

Para unir this or that en un uso de expresiones regulares |, es decir

if [[ "$HOST" =~ ^user.*|^host1 ]]; then
    echo "yes"
fi

Nota: esta es la sintaxis de expresión regular "propia".

  • user* medio use y cero o más apariciones de r, asi que use y userrrr coincidirá.
  • user.* medio user y cero o más ocurrencias de cualquier carácter, por lo user1, userX coincidirá.
  • ^user.* significa que coincide con el patrón user.* al comienzo de $ HOST.

Si no está familiarizado con la sintaxis de expresión regular, intente consultar este recurso.

Nota: es mejor si hace cada nueva pregunta como una nueva pregunta, hace que stackoverflow sea más ordenado y más útil. Siempre puede incluir un enlace a una pregunta anterior para referencia.


139
2018-01-31 16:15



Siempre trato de seguir con POSIX sh en lugar de utilizar extensiones bash, ya que uno de los puntos principales de scripting es la portabilidad. (Además conectando programas, no reemplazándolos)

En sh, hay una manera fácil de verificar si hay una condición de "is-prefix".

case $HOST in node*)
    your code here
esac

Dado lo viejo, arcano y difícil que es (y bash no es la cura: es más complicado, menos consistente y menos portátil), me gustaría señalar un aspecto funcional muy agradable: mientras que algunos elementos de sintaxis como case están incorporados, las construcciones resultantes no son diferentes a cualquier otro trabajo. Se pueden componer de la misma manera:

if case $HOST in node*) true;; *) false;; esac; then
    your code here
fi

O incluso más corto

if case $HOST in node*) ;; *) false;; esac; then
    your code here
fi

O incluso más corto (solo para presentar ! como un elemento de lenguaje, pero ahora es un mal estilo)

if ! case $HOST in node*) false;; esac; then
    your code here
fi

Si te gusta ser explícito, crea tu propio elemento de idioma:

beginswith() { case $2 in "$1"*) true;; *) false;; esac; }

¿No es esto realmente bastante agradable?

if beginswith node "$HOST"; then
    your code here
fi

Y dado que sh es básicamente solo trabajos y listas de cadenas (y procesos internos, de los cuales están compuestos los trabajos), ahora podemos incluso hacer alguna programación funcional liviana:

beginswith() { case $2 in "$1"*) true;; *) false;; esac; }
checkresult() { if [ $? = 0 ]; then echo TRUE; else echo FALSE; fi; }

all() {
    test=$1; shift
    for i in "$@"; do
        $test "$i" || return
    done
}

all "beginswith x" x xy xyz ; checkresult  # prints TRUE
all "beginswith x" x xy abc ; checkresult  # prints FALSE

Esto es elegante No es que defienda usar sh para nada serio: se rompe demasiado rápido en los requisitos del mundo real (sin lambdas, por lo que debe usar strings. Pero las llamadas a funciones de anidamiento con strings no son posibles, los pipes no son posibles ...)


73
2017-09-01 13:26



Puede seleccionar solo la parte de la cadena que desea verificar:

if [ ${HOST:0:4} = user ]

Para su pregunta de seguimiento, podría usar un O:

if [[ $HOST == user1 || $HOST == node* ]]

55
2018-01-31 16:15



Prefiero los otros métodos ya publicados, pero a algunas personas les gusta usar:

case "$HOST" in 
    user1|node*) 
            echo "yes";;
        *)
            echo "no";;
esac

Editar:

He agregado sus alternativas a la declaración del caso anterior

En su versión editada tiene demasiados corchetes. Debe tener un aspecto como este:

if [[ $HOST == user1 || $HOST == node* ]];

53
2018-01-31 16:29



ya que # tiene un significado en bash, llegué a la siguiente solución.
Además, me gusta más empacar cadenas con "" para superar espacios, etc.

A="#sdfs"
if [[ "$A" == "#"* ]];then
    echo "skip comment line"
fi

26
2017-11-01 09:11



Si bien la mayoría de las respuestas aquí son correctas, muchas contienen bashismos innecesarios. Expansión del parámetro POSIX te da todo lo que necesitas:

[ "${host#user}" != "${host}" ]

y

[ "${host#node}" != "${host}" ]

${var#expr} elimina el prefijo más pequeño que coincida expr de ${var} y devuelve eso. Por lo tanto si ${host} hace no Empezar con user (node), ${host#user} (${host#node}) es lo mismo que ${host}.

expr permite fnmatch() comodines, por lo tanto ${host#node??} y amigos también trabajan.


21
2018-05-06 13:02



@OP, para ambas preguntas puede usar case / esac

string="node001"
case "$string" in
  node*) echo "found";;
  * ) echo "no node";;
esac

segunda pregunta

case "$HOST" in
 node*) echo "ok";;
 user) echo "ok";;
esac

case "$HOST" in
 node*|user) echo "ok";;
esac

O Bash 4.0

case "$HOST" in
 user) ;& 
 node*) echo "ok";; 
esac

8
2018-01-31 23:54



if [ [[ $HOST == user1 ]] -o [[ $HOST == node* ]] ];  
then  
echo yes 
fi

no funciona, porque todos [, [[ y prueba reconocer la misma gramática no recursiva. mira la sección EXPRESIONES CONDICIONALES en tu página bash man.

Como un lado, el SUSv3 dice

El comando condicional derivado de KornShell (doble corchete [[]]) se eliminó de la descripción del lenguaje de comandos de shell en una propuesta temprana. Se plantearon objeciones a que el verdadero problema es el uso indebido de la prueba comando ([), y ponerlo en el caparazón es la forma incorrecta de solucionar el problema. En cambio, la documentación adecuada y una nueva palabra reservada shell (!) Son suficientes.

Pruebas que requieren múltiples prueba las operaciones se pueden hacer a nivel de shell utilizando invocaciones individuales de la prueba comando y shell lógicos, en lugar de utilizar el propenso a errores -o Bandera de prueba.

necesitarías escribirlo de esta manera, pero prueba no lo admite:

if [ $HOST == user1 -o $HOST == node* ];  
then  
echo yes 
fi

prueba usos = para igualdad de cadenas, más importante aún no es compatible con la coincidencia de patrones.

case / esac tiene un buen soporte para la coincidencia de patrones:

case $HOST in
user1|node*) echo yes ;;
esac

tiene el beneficio adicional de que no depende de bash, la sintaxis es portátil. de la especificación Single Unix, el lenguaje de comandos de Shell:

case word in
    [(]pattern1) compound-list;;
    [[(]pattern[ | pattern] ... ) compound-list;;] ...
    [[(]pattern[ | pattern] ... ) compound-list]
esac

6
2018-01-31 17:44



Otra cosa que puedes hacer es cat a cabo lo que está haciendo eco y pipa con inline cut -c 1-1


-4
2018-05-27 23:44