Búsqueda de subcadenas sin distinción entre mayúsculas y minúsculas en un script de shell [cerrado]

22

¿Cómo puedo escribir un script de shell que haga una coincidencia de subcadena sin distinción entre mayúsculas y minúsculas de la salida del comando?

Miguel Roque
fuente
grep -i¿tal vez?
Ramesh
¿Cómo voy a poner eso dentro de mi script? Lo siento si esta es una pregunta novata. Estoy empezando a estudiar Linux porque lo necesito para mi pasantía. ¡Gracias!
Miguel Roque
1
Lo que está preguntando es sobre los scripts de shell : "linux" no es un lenguaje de programación, es un núcleo del sistema operativo. El shell más comúnmente utilizado con Linux es bash, que es un superconjunto del estándar Unixsh . Puede comenzar mirando uno de estos: | 1 | | 2 | - solo para comprender cuál es el contexto real.
Ricitos
1
Esta pregunta ahora parece bastante clara y coincide con las pautas del centro de ayuda. ¿Puede abrirse en beneficio de otros?
BobDoolittle
2
No veo la confusión por qué esta pregunta no está clara. ¿Qué debo agregar para que quede claro?
Miguel Roque

Respuestas:

11

Primero, aquí hay un script de ejemplo simple que no ignora el caso:

#!/bin/bash
if [ $(echo hello) == hello ]; then
    echo it works
fi

Intente cambiar la cadena hola a la derecha, y ya no debería hacer eco it works. Intente reemplazar echo hellocon un comando de su elección. Si desea ignorar mayúsculas y minúsculas, y ninguna cadena contiene un salto de línea, puede usar grep:

#!/bin/bash
if echo Hello | grep -iqF hello; then
    echo it works
fi

La clave aquí es que está canalizando una salida de comando a grep. La ifdeclaración prueba el estado de salida del comando más a la derecha en una tubería, en este caso grep. Grep sale con éxito si y solo si encuentra una coincidencia.

La -iopción de grep dice que ignore el caso.
La -qopción dice no emitir salida y salir después del primer partido.
La -Fopción dice tratar el argumento como una cadena en lugar de una expresión regular.

Tenga en cuenta que el primer ejemplo utiliza lo que permite comparaciones directas y varios operadores útiles. La segunda forma solo ejecuta comandos y prueba su estado de salida.[ expression ]

BobDoolittle
fuente
No entiendo por qué Gilles sintió que era necesario cambiar el código que contribuí. No rompió nada, pero funcionó bien. No necesita las comillas dobles en este ejemplo; sin embargo, son importantes si la salida contiene espacios. Y == funciona igual de bien que = porque sh es realmente bash en Linux. El Bourne Shell original ya no existe en este momento. No creo que incluso Solaris lo envíe más. Si bien es innecesario en este ejemplo, estoy de acuerdo en que las comillas dobles son probablemente una mejor práctica, pero también lo es '==' en mi opinión, para mantener la asignación y la comparación claramente separadas.
BobDoolittle
Espera, ¿puedes editar una publicación? No sabía eso.
Miguel Roque
Con suficiente reputación, sí. Sin embargo, espero que alguien con alta reputación lo piense dos veces antes de hacer ediciones innecesarias, particularmente para codificar en este foro. unix.stackexchange.com/help/privileges
BobDoolittle
@BobDoolittle Puede ser que en ciertos casos marque la diferencia, pero no con su configuración, es bueno saberlo.
2
Tenga en cuenta que, en la práctica, no se trata solo del shell Bourne. ==No es POSIX. shno está bashen todos los sistemas basados ​​en Linux. ==no está respaldado por ash(en el que shse basan al menos muchos BSD y derivados de Debian), o posh, y las necesidades citadas en zsh. No tiene sentido duplicar el =. [es un comando para probar. No hay necesidad de desambiguar entre asignación y comparación aquí. Eso es diferente en (( a == b ))contra (( a = b)). Usar ==un script que comienza con #! /bin/shestá mal. Si asume ksho bashsintaxis, actualice el #!correspondiente.
Stéphane Chazelas
49

Puede hacer una coincidencia de subcadenas sin distinción entre mayúsculas y minúsculas al bashusar el operador regex =~si configura la nocasematchopción de shell. Por ejemplo

s1="hElLo WoRlD"
s2="LO"

shopt -s nocasematch

[[ $s1 =~ $s2 ]] && echo "match" || echo "no match"
match

s1="gOoDbYe WoRlD"
[[ $s1 =~ $s2 ]] && echo "match" || echo "no match"
no match
conductor de acero
fuente
66
jajaja puntos para conocimiento oscuro de la cáscara.
BobDoolittle
2
Esta opción también afecta al operador de coincidencia simple. [[ XYZ == xyz ]] && echo "match"=>match
itsadok
7

Para una búsqueda de cadenas entre mayúsculas y minúsculas del valor de la variable needleen el valor de la variable haystack:

case "$haystack" in
  *"$needle"*) echo "present";
  *) echo "absent";
esac

Para una búsqueda de cadenas que no distingue entre mayúsculas y minúsculas, convierta ambas al mismo caso.

uc_needle=$(printf %s "$needle" | tr '[:lower:]' '[:upper:]' ; echo .); uc_needle=${uc_needle%.}
uc_haystack=$(printf %s "$haystack" | tr '[:lower:]' '[:upper:]' ; echo .); uc_haystack=${uc_haystack%.}
case "$uc_haystack" in
  *"$uc_needle"*) echo "present";;
  *) echo "absent";;
esac

Tenga tren cuenta que en GNU coreutils no admite configuraciones regionales multibyte (por ejemplo, UTF-8). Para hacer el trabajo con configuraciones regionales multibyte, use awk en su lugar. Si va a usar awk, puede hacer que haga la comparación de cadenas y no solo la conversión.

if awk 'BEGIN {exit !index(toupper(ARGV[2]), toupper(ARGV[1]))}' "$needle" "$haystack"; then
  echo "present"
else
  echo "absent"
fi

El trde BusyBox no admite la sintaxis; puedes usar en su lugar. BusyBox no admite configuraciones regionales que no sean ASCII.[:CLASS:]tr a-z A-Z

En bash (pero no sh), versión 4.0+, hay una sintaxis incorporada para la conversión de mayúsculas y una sintaxis más simple para la coincidencia de cadenas.

if [[ "${haystack^^}" = *"${needle^^}"* ]]; then
  echo "present"
else
  echo "absent"
esac
Gilles 'SO- deja de ser malvado'
fuente
Me doy cuenta de que esto tiene un par de años, pero todo eso printf | trhace que mi cabeza gire. Siempre que sea posible, mantenga su invocación de comandos al mínimo ... dada una variable v, puede lograr lo mismo usando v=$(tr '[:lower:]' '[:upper:]' <<<$v). Para aquellos que nunca lo han visto antes, <<<es esencialmente una "variable aquí" como el uso de <<EOFes para un documento aquí. No printfo echomenos que sea absolutamente necesario hacerlo.
Will
@ Will Eso solo funciona en shells que tienen el <<<operador: ksh, bash, zsh, pero no sh simple. Y es bastante cerca de las tuberías de printfen términos de cómo funciona: no hay el mismo número de llamadas a forky execve(suponiendo que printfestá incorporado, que es el caso en la mayoría de los depósitos comunes); La diferencia es que <<<crea un archivo temporal en lugar de utilizar una tubería. <<<Es conveniente escribir pero no una mejora del rendimiento.
Gilles 'SO- deja de ser malvado'