Quiero escribir una función que verifique si una variable dada, digamos, var
comienza con alguna de las palabras en una lista determinada de cadenas. Esta lista no cambiará.
Para crear una instancia, supongamos que quiero comprobar si var
comienza aa
con abc
o 3@3
.
Además, quiero comprobar si var
contiene el carácter >
.
Digamos que esta función se llama check_func
. Mi uso previsto se parece a
if check_func "$var"; then
do stuff
fi
Por ejemplo, debería "hacer cosas" para aardvark
, abcdef
y .[email protected]
12>5
He vistoesta pregunta SOdonde un usuario proporciona parte del trabajo:
beginswith() { case $2 in "$1"*) true;; *) false;; esac; }
Mi idea es iterar sobre la lista mencionada anteriormente y usar esta función. Mi dificultad radica en no entender exactamente cómo se debe salir (o lo que sea que reemplace el regreso) para que esto funcione.
Respuesta1
check_prefixes () {
value=$1
for prefix in aa abc 3@3; do
case $value in
"$prefix"*) return 0
esac
done
return 1
}
check_contains_gt () {
value=$1
case $value in
*">"*) return 0
esac
return 1
}
var='aa>'
if check_prefixes "$var" && check_contains_gt "$var"; then
printf '"%s" contains ">" and starts with one of the prefixes\n' "$var"
fi
Dividí las pruebas en dos funciones. Tanto el uso case ... esac
como la devolución son exitosos (cero) tan pronto como se pueda determinar. Si nada coincide, se devuelve el error (1).
Para hacer que la lista de prefijos sea más dinámica, posiblemente se podría escribir la primera función como
check_prefixes () {
value=$1
shift
for prefix do
case $value in
"$prefix"*) return 0
esac
done
return 1
}
(el valor a inspeccionar es el primer argumento, que guardamos dentro value
y luego shift
fuera de la lista de argumentos de la función; luego iteramos sobre los argumentos restantes) y luego lo llamamos como
check_prefixes "$var" aa abc 3@3
La segunda función podría cambiarse de manera similar, en
check_contains () {
value=$1
shift
case $value in
*"$1"*) return 0
esac
return 1
}
(para comprobar si hay alguna subcadena arbitraria), o
check_contains_oneof () {
value=$1
shift
for substring do
case $value in
*"$substring"*) return 0
esac
done
return 1
}
(para comprobar si hay alguna de varias subcadenas)
Respuesta2
Para fiesta:
Usando las propiedades de expresiones regulares puedes escribir start
con ^
y contain
sin nada.
La lista de expresiones regulares para verificar.comenzarcon aa
abc
o 3@3
ycontiene >
es:
^aa ^abc ^3@3 >
Haz de eso unadecuadamentelista citada y pedirle a bash que use expresiones regulares ( =~
):
check_func() {
matched=1
for test_regex in '^aa' '^abc' '^3@3' '>'; do
if [[ $var =~ $test_regex ]] ; then
matched=0
break
fi
done
return "$matched"
}
var='aaIsAMatch'
if check_func; then
echo "A match was found"
fi
La función ha codificado la lista de coincidencias y el nombre de la var.
Proporcionando la lista de expresiones regulares en una variable de matriz y el valor a probar en el primer argumento:
check_func() {
local matched; matched=1
for t in "${test_regex[@]}"; do
[[ $1 =~ $t ]] && { matched=0; break; }
done
return "$matched"
}
test_regex=('^aa' '^abc' '^3@3' '>')
if check_func 'aaIsAMatch'; then
echo "A match was found"
fi
La función podría mejorarse aún más para utilizar el nombre de una variable (en lugar de un valor) como primer argumento.
posix
Como no hay expresiones regulares en los shells posix y la única forma de realizar pruebas es una declaración de caso, debemos usar una declaración de caso. Lamentablemente, para shells más antiguos ([no hay globs extendidos disponibles][1]) debemos realizar un bucle para realizar todas las pruebas. Y los globos deben ser:
'aa*' 'abc*' '3@3*' '*>*'
Un ejemplo de script que prueba varias cadenas de entrada con varios globos:
check_func() { :
matched=1
value=$1; shift
for t in "$@"; do
case $value in $t) matched=0; #break;; esac
echo "matched $value with $t"
;;
esac
done
return "$matched"
}
for var in abdg wabcde aadef abcde 3@3hello hmm3@3hell 'we>we' 'a>dfff' 'dfd>' 'a> de' 'a*> fg'; do
if check_func "$var" 'aa*' 'abc*' '3@3*' '*>*'; then
echo "========A match was found for \"$var\""
fi
done
Una versión más simple de la función que se adapta exactamente a su solicitud:
check_func() { :
matched=1
value=$1; shift
for t in "$@"; do
case $value in $t) matched=0; break;; esac
done
return "$matched"
}
Respuesta3
Esto es lo que case
hace la declaración: llevar el segundo parámetro a la función ( $2
). Si coincide con el patrón "$1"*
, es decir, el primer argumento de la función seguido de cualquier cosa, ejecute true
y finalice la case
declaración. true
no hace nada y devuelve el estado 0. De lo contrario, si coincide *
, es decir, cualquier cosa, ejecuta false
y finaliza la case
declaración. false
no hace nada y devuelve el estado 1. Por lo tanto, la case
declaración tiene el estado 0 si el segundo parámetro comienza con el primer parámetro y 1 en caso contrario. Dado que esta es la última (y única) declaración de la función, la función devuelve 0 si el segundo parámetro comienza con el primer parámetro y 1 en caso contrario.
Las declaraciones condicionales, como las if
del shell, consideran que una declaración es verdadera si devuelve 0 y falsa en caso contrario. Por lo tanto, if beginswith "$var" "string"; then echo yes; else echo no; fi
se imprime yes
si el valor de var
comienza con string
y no
en caso contrario.
Hay varias formas alternativas de escribir esta función. Por ejemplo, el autor podría haber usado return 0
o return 1
en lugar de true
y false
, ya que son la última declaración de la función. La forma en que se escribió la función hace posible usar su cuerpo directamente sin envolverlo en una función, simplemente cambiando las referencias a los parámetros de la función ( $1
y $2
) a cualquier cadena con la que desee trabajar.
Para permitir múltiples prefijos, repita sobre ellos en un bucle. Tan pronto como haya encontrado un prefijo coincidente, regrese de la función con un estado verdadero (0). Si ninguno de los prefijos coincide, devuelve un estado falso (convencionalmente 1).
# begins_with STRING PREFIX1 PREFIX2...
# Test if STRING starts with any of PREFIX1, PREFIX2, ...
begins_with () {
string=$1
shift
for prefix in "$@"; do
case "$string" in
"$prefix"*) return 0;;
esac
done
return 1
}
if begins_with "$var" 'aa' 'abc' '3@3'; then
echo "The value starts with one of the permitted prefixes"
fi
Para probar un sufijo, use el patrón *"$suffix"
en lugar de "$prefix"*
. Para probar una subcadena, use *"$substring"*
. Tenga en cuenta que las comillas dobles son necesarias aquí; de lo contrario, la variable se interpretaría como un patrón. Por ejemplo:
suffix='?'
case "$var" in
*"$suffix") echo "The value of var ends with a question mark";;
esac
case "$var" in
*$suffix) echo "The value of var is not empty";;
esac
Respuesta4
Revisado en base a la aclaración de la pregunta: Esto es menos elegante (y mucho menos flexible), pero más compacto que las otras respuestas.
check_func() {
case "$1" in
( aa* | abc* | 3@3* | *">"*)
return 0
esac
return 1
}
Esto devuelve verdadero para aardvark
, abcdef
y . Y, por supuesto, también , y .[email protected]
12>5
aard>vark
abc<def>ghi
3@3>3