Búsqueda que no distingue entre mayúsculas y minúsculas y reemplazar con sed

81

Estoy tratando de usar SED para extraer texto de un archivo de registro. Puedo buscar y reemplazar sin demasiados problemas:

sed 's/foo/bar/' mylog.txt

Sin embargo, quiero que la búsqueda no distinga entre mayúsculas y minúsculas. Por lo que busqué en Google, parece que agregar ial final del comando debería funcionar:

sed 's/foo/bar/i' mylog.txt

Sin embargo, esto me da un mensaje de error:

sed: 1: "s/foo/bar/i": bad flag in substitute command: 'i'

¿Qué va mal aquí y cómo lo soluciono?

Craig Walker
fuente
2
¿Puedes intentar actualizar tu copia de sed? Ies una extensión GNU que puede no estar disponible con su copia de sed.
Lazer
4
EDITAR : taché la calificación de OS X, ya que el OP aceptó una respuesta que no funciona en OS X. (Como se indicó en otra respuesta, sed en OS X no admite la coincidencia sin distinción de mayúsculas y minúsculas, al contrario de la documentación de Apple)
danorton
1
@danorton: Gracias por eso; en caso de que haya deducido la sensación de que la documentación de Apple promete algo que la implementación no ofrece a partir de mi respuesta a continuación: man sedES coherente con la implementación: no se menciona (y no se admite en la práctica) la coincidencia que no distingue entre mayúsculas y minúsculas; Si encuentra algún documento que indique lo contrario, háganoslo saber.
mklement0
1
@ mklement0, sí, lo siento, estoy corregido. La documentación de Apple no hace ningún reclamo de coincidencia entre mayúsculas y minúsculas para sed.
danorton
1
FWIW, las versiones GNU de las herramientas cuya versión BSD viene con OS X están disponibles en varios administradores de paquetes. Tengo el conjunto completo de utilidades de texto instaladas a través de Homebrew con un gprefijo, por lo que puedo usar gsedo gdatecuando necesito una función que no se encuentra en la versión estándar.
Mark Reed

Respuestas:

72

Para ser claros: en macOS , a partir de Mojave (10.14), sedque es la implementación de BSD , NO admite la coincidencia que no distingue entre mayúsculas y minúsculas , es difícil de creer, pero es cierto. La respuesta aceptada anteriormente , que en sí misma muestra un comando GNU sed , ganó ese estado debido a la perlsolución basada en la mencionada en los comentarios.

Para que la solución Perl también funcione con caracteres extranjeros , a través de UTF-8, use algo como:

perl -C -Mutf8 -pe 's/öœ/oo/i' <<< "FÖŒ" # -> "Foo"
  • -C activa la compatibilidad con UTF-8 para transmisiones y archivos, asumiendo que la configuración regional actual está basada en UTF-8.
  • -Mutf8le dice a Perl que interprete el código fuente como UTF-8 (en este caso, la cadena pasada a -pe) - este es el equivalente más corto del más detallado -e 'use utf8;'.Gracias, Mark Reed

(Tenga en cuenta que el uso awktampoco es una opción , ya que awken macOS (es decir, BWK awk , también conocido como BSD awk ) parece desconocer por completo las configuraciones regionales: sus funciones tolower()y toupper()ignoran los caracteres extranjeros (y sub()/ gsub()no tienen indicadores que no distingan entre mayúsculas y minúsculas para empezar con).)

mklement0
fuente
Para corregir la configuración regional: blogs.agilefaqs.com/2014/01/12/…
Eduardo Cuomo
69

Nota del editor : esta solución no funciona en macOS (lista para usar), porque solo se aplica a GNU sed , mientras que macOS viene con BSD sed .

Escriba con mayúscula la "I".

sed 's/foo/bar/I' file
Wesley Rice
fuente
2
También vi esto y lo intenté ... pero sigo recibiendo el mismo mensaje de error.
Craig Walker
15
BSD sed tiene muchas limitaciones, al parecer. Haría esto en PERL (es decir, perl -pe 's / foo / bar / i'), si ese es el caso.
Wesley Rice
3
La instalación predeterminada de OS X Lion da el error: sed: 1: "s / foo / bar / I": bandera incorrecta en el comando sustituto: 'I'
Ben Clayton
13
El Isufijo no es un uso portátil de sed. POSIX sedusa solo Expresiones regulares básicas (BRE), que son sorprendentemente limitadas. Ni siquiera admiten +(tienes que usar \{1,\}en su lugar), y mucho menos la coincidencia que no distingue entre mayúsculas y minúsculas. La única forma portátil de hacerlo con sed es buscar algo como /[hH][eE][lL][lL][oO]/, que a menudo no será práctico.
Edam
5
De lo /gIcontrario, solo funcionará en el primer partido.
Faheem Mitha
25

Otra solución alternativa para sedMac OS X es instalar gseddesde MacPorts o HomeBrew y luego crear el alias sed='gsed'.

Casimir Crystal
fuente
gsed "s / a / b / Ig" funciona, gracias! ¿Por qué una buena respuesta de trabajo debería tener un voto negativo?
Matthias M
3
esta respuesta es genial. usado brew install gnu-sedluego fue a mi ~ / .bash_profile y agregué el alias. Gracias @davmat
ThinkBonobo
8
Es mejor hacerlo brew install gnu-sed --with-default-names: esto anulará el valor predeterminado sed.
Mar0ux
4

Las preguntas frecuentes de sed abordan la búsqueda que no distingue entre mayúsculas y minúsculas . Señala que a) muchas versiones de sed admiten una bandera para él yb) es incómodo hacerlo en sed, debería usar awk o Perl.

Pero para hacerlo en POSIX sed, sugieren tres opciones (adaptadas para sustitución aquí):

  1. Convierta a mayúsculas y almacene la línea original en el espacio de espera; Sin embargo, esto no funcionará para sustituciones, ya que el contenido original se restaurará antes de imprimir, por lo que solo es bueno para insertar o agregar líneas basadas en una coincidencia que no distinga entre mayúsculas y minúsculas.

  2. Tal vez las posibilidades se limitan a FOO, Fooe foo. Estos pueden ser cubiertos por

    s/FOO/bar/;s/[Ff]oo/bar/
    
  3. Para buscar todas las coincidencias posibles, se pueden usar expresiones entre corchetes para cada carácter:

    s/[Ff][Oo][Oo]/bar/
    
Benjamin W.
fuente
1

La versión para Mac sedparece un poco limitada. Una forma de evitar esto es usar un contenedor de Linux (a través de Docker) que tiene una versión utilizable de sed:

cat your_file.txt | docker run -i busybox /bin/sed -r 's/[0-9]{4}/****/Ig'
usuario1307434
fuente
15
esto es algo particularmente atroz. Si alguien está considerando esto seriamente, simplemente instale un sed de GNU localmente.
ocodo
¡Enfoque general excesivo pero útil para saber!
YvesgereY
1

Si primero está haciendo una coincidencia de patrones, por ejemplo,

/pattern/s/xx/yy/g

entonces quieres poner el Idespués del patrón:

/pattern/Is/xx/yy/g

Ejemplo:

echo Fred | sed '/fred/Is//willma/g'

devoluciones willma; sin el I, devuelve la cadena sin tocar ( Fred).

CBB
fuente
2
En MacOs obtengo:sed: 1: "/fred/Is//willma/g": invalid command code I
Chris F Carroll
Buen consejo. Así es como yo lo uso en una búsqueda compleja: sed -r '/'"$PATTERN"'/I,${s//'$YELLOW'&'$NO_COLOR'/g;b};$q3'. Imprime el texto y, si se encuentra un patrón (que no distingue entre mayúsculas y minúsculas), resalta el texto en amarillo (color ansi). Si no se encuentra, devuelve el código de salida 3.
Noam Manos
0

Tenía una necesidad similar y se me ocurrió esto:

este comando para simplemente encontrar todos los archivos:

grep -i -l -r foo ./* 

este para excluir this_shell.sh (en caso de que pones el comando en un script llamado this_shell.sh ), envía la salida a la consola para ver qué sucedió, y luego usa sed en cada nombre de archivo encontrado para reemplazar el texto foo con bar :

grep -i -l -r --exclude "this_shell.sh" foo ./* | tee  /dev/fd/2 | while read -r x; do sed -b -i 's/foo/bar/gi' "$x"; done 

Elegí este método, ya que no me gustó que se cambiaran todas las marcas de tiempo de los archivos no modificados. alimentar el resultado de grep permite ver solo los archivos con el texto de destino (por lo tanto, es probable que también mejore el rendimiento / velocidad)

asegúrese de hacer una copia de seguridad de sus archivos y probarlos antes de usarlos. Es posible que no funcione en algunos entornos para archivos con espacios incrustados. (?)

gojimmypi
fuente
0

Utilice lo siguiente para reemplazar todas las apariciones: sed 's / foo / bar / gI' mylog.txt

yogendrar54
fuente
Consulte stackoverflow.com/a/4412964/4294399 , que cubre la capital I. Tampoco creo que esto realmente responda a la pregunta, ya que no se refiere al reemplazo global.
Calculuswhiz