¿Cómo encontrar y reemplazar cadenas sin usar el comando Sed?

16

Como todos sabemos, sedes en gran medida eficiente para buscar y reemplazar la cadena, por ejemplo hallazgo 'a' y reemplazarlo con 'b': sed 's/a/b/g'.

¿Es posible hacer esto con otro comando o script de shell en lugar de sed?

Esto es para un sistema Linux recortado para TV que no tiene el sedcomando. Entonces tengo que usar otros comandos o scripts en lugar desed 's/a/b/g'. –

binghenzq
fuente
En realidad, eso es solo una sustitución basada en expresiones regulares. Cualquier herramienta o lenguaje capaz de manejar tal cosa será capaz de hacer lo mismo, pero con diferentes sintaxis: $var=~s/a/b/g, gsub(/a/,"b",var), var.gsub(/a/,'b'), var.replace(/a/g,'b'), preg_replace("/a/","b",$var), regsub -all a b $var. Además de eso, muchas herramientas e idiomas también pueden reemplazar cadenas de texto sin formato. Entonces su pregunta es de alguna manera amplia.
manatwork
1
¿Por qué? ¿Que problema estas tratando de resolver?
Gilles 'SO- deja de ser malvado'
Los sistemas linux recortados para TV no han recibido el comando. Entonces tengo que usar otro comando o script para en lugar de sed 's / a / b / g'.
binghenzq

Respuestas:

12

Sí, hay una variedad de formas de hacer esto. Puede usar awk, perlo bashpara hacer estas actividades también. Sin embargo, en general sedes probablemente la herramienta más adecuada para realizar este tipo de tareas.

Ejemplos

Digamos que tengo estos datos de muestra, en un archivo data.txt:

foo bar 12,300.50
foo bar 2,300.50
abc xyz 1,22,300.50

awk

$ awk '{gsub("foo", "foofoofoo", $0); print}' data.txt 
foofoofoo bar 12,300.50
foofoofoo bar 2,300.50
abc xyz 1,22,300.50

Perl

$ perl -pe "s/foo/foofoofoo/g" data.txt 
foofoofoo bar 12,300.50
foofoofoo bar 2,300.50
abc xyz 1,22,300.50

Edición en línea

Los ejemplos anteriores también pueden modificar directamente los archivos. El ejemplo de Perl es trivial. Simplemente agregue el -iinterruptor.

$ perl -pie "s/foo/foofoofoo/g" data.txt 

Porque awkes un poco menos directo pero igual de efectivo:

$ { rm data.txt && awk '{gsub("foo", "foofoofoo", $0); print}' > data.txt; } < data.txt

Este método crea un sub-shell con las llaves '{...}' donde el archivo se redirige a él a través de esto:

$ { ... } < data.txt

Una vez que el archivo ha sido redirigido al subconjunto, se elimina y luego awkse ejecuta contra el contenido del archivo que se leyó en los subconjuntos STDIN. Este contenido se procesa awky se vuelve a escribir en el mismo nombre de archivo que acabamos de eliminar, reemplazándolo efectivamente.

slm
fuente
Gracias por su respuesta y lo intentaré el próximo día laborable. Pero no estoy seguro de si funciona porque algún comando tal vez no exista en un sistema de TV recortado de Linux, como 'sed'. Así que todavía quiero usar el comando 'encontrar' , 'grep' y así sucesivamente para resolverlo.
binghenzq
@binghenzq: agregué ejemplos que editan el archivo en línea.
slm
-1 Raramente rechazo, pero en este caso el punto de la pregunta parecía ser un método más simple en lugar de otro más / igualmente complejo y probablemente también dependiente. Si la pregunta fuera solo sobre alternativas para una instalación completa de la máquina * nix, entonces probablemente haría +1 en esta buena respuesta.
Michael Durrant
@MichaelDurrant: acabo de agregar esas ediciones en línea elaboradas porque el OP las solicitó. Además, el OP estableció el requisito de NO usar sedno I. Sed es la herramienta adecuada para realizar sustituciones como esta, y obviamente está pidiendo comprender mejor los roles de estas herramientas, por lo que mostrarle a alguien estas cosas aunque sea malo, es extremadamente educativo para mostrar ellos por qué. Demasiadas veces la gente en el saber simplemente dice "no lo hagas" sin explicar por qué, así que lo estoy. Pero gracias por al menos dejar un comentario de por qué DV.
slm
Claro, pensé que era una gran respuesta en todos los demás aspectos. Sí, odio -1 sin explicación.
Michael Durrant
13

La alternativa clásica para las sustituciones de una sola letra es el trcomando que debería estar disponible en casi cualquier sistema:

$ echo "foobar" | tr a b   
foobbr

tres mejor que sedpara esta realidad ya que el uso sed(y mucho menos perlo awk) para las sustituciones de una sola letra es como usar un martillo para matar una mosca.

grep no está diseñado para esto, no modifica su entrada, solo busca a través de ella.

Alternativamente, puede usar las capacidades de sustitución de algunos shells. Aquí usando ksh, zsho bashsintaxis:

$ foo="foobar"
$ echo "${foo//a/b}"
foobbr

Podríamos darle respuestas más específicas si explica exactamente qué problema está tratando de resolver.

terdon
fuente
¿Hay una opción para ignorar el caso ${foo//a/b}?
AlikElzin-kilaka
@ AlikElzin-kilaka me temo que no. Vas a tener que usar algo más sofisticado, como, por ejemplo: echo "$foo" | sed 's/a/b/io dar una clase de caracteres: echo ${foo//[aA]/b}.
terdon
4

Puede usar Vim en modo Ex:

ex -s -c '%s/a/b/g|x' file
  1. % seleccione todas las líneas

  2. s sustituir

  3. g reemplazo global

  4. x guardar y cerrar

Steven Penny
fuente
muchas gracias. solo para agregar, el indicador -c es ejecutar el comando cuando comienza la edición (ya que ex es un editor) y el indicador -s es el modo de script que desactiva la retroalimentación o, como a algunos les gusta decir, modo slient. ref para más información: ex-vi.sourceforge.net/ex.html
Jimmy MG Lim
3

Si está trabajando con un archivo en lugar de una secuencia, puede usar el editor de texto estándar ed:

printf '%s\n' ',s/a/b/g' w q | ed file.txt

Esto debería estar disponible en cualquier * nix. La coma en ',s/a/b/g'le dice edque trabaje en cada línea (también puede usar %, lo que le resultará más familiar si está acostumbrado a vim), y el resto es una búsqueda y reemplazo estándar. wle dice que escriba (guarde) el archivo, qle dice que salga.

Tenga en cuenta que, a diferencia de la -iopción de sed (y opciones similares en otras herramientas), esto realmente edita el archivo en el lugar en lugar de hacer trampa con archivos temporales.

No creo que sea posible hacer que esto funcione con transmisiones, pero en realidad no sé mucho edy no me sorprendería si realmente tiene esa capacidad (la filosofía de Unix es lo que es).

maldad
fuente
2

Usando el comando ancestor (en el que -ssignifica quiet (silent) y la coma antes de los comandos significa ejecutar en todas las líneas):

Solo imprimiendo en STDOUT :

ed -s file <<!
,s/a/b/g
,p
q
!

reemplazo en el lugar:

ed -s file <<!
,s/a/b/g
w
q
!
Gilles Quenot
fuente