¿Cómo reemplazar las cadenas que contienen barras con sed?

147

Tengo un proyecto de Visual Studio, que se desarrolla localmente. Los archivos de código deben implementarse en un servidor remoto. El único problema es que contienen URL que están codificadas.

El proyecto contiene URLS como ? Page = one . Para que el enlace sea válido en el servidor, debe ser / page / one .

Decidí reemplazar todas las URLS en mis archivos de código con sed antes de la implementación, pero estoy atascado en barras.

Sé que esta no es una solución bonita, pero es simple, me ahorraría mucho tiempo. El número total de cadenas que tengo que reemplazar es menor que 10. El número total de archivos que deben verificarse es ~ 30.

El ejemplo que describe mi situación está abajo:

Comando que estoy usando:

sed -f replace.txt < a.txt > b.txt

replace.txt que contiene todas las cadenas:

s/?page=one&/pageone/g
s/?page=two&/pagetwo/g
s/?page=three&/pagethree/g

a.txt:

?page=one&
?page=two&
?page=three&

Contenido de b.txt después de ejecutar mi comando sed:

pageone
pagetwo
pagethree

Lo que quiero que b.txt contenga:

/page/one
/page/two
/page/three
afaf12
fuente
1
posible duplicado de búsqueda
Damien MATHIEU
3
posible duplicado de barras
tripleee

Respuestas:

274

La forma más fácil sería utilizar un delimitador diferente en sus líneas de búsqueda / reemplazo, por ejemplo:

s:?page=one&:pageone:g

Puede usar cualquier carácter como delimitador que no sea parte de ninguna cadena. O bien, podría escapar con una barra invertida:

s/\//foo/

Lo cual reemplazaría /con foo. Debería usar la barra invertida escapada en casos en los que no sabe qué caracteres pueden aparecer en las cadenas de reemplazo (si son variables de shell, por ejemplo).

mirón
fuente
1
> O podrías escapar con una barra invertida. Un ejemplo de eso sería más útil, ya que no siempre sabes qué caracteres hay en una cadena para poder elegir algo diferente. por ejemplo, esto: echo / | sed s / \ // a / g no funciona: sed: -e expresión # 1, char 5: opción desconocida para `s '
Max Waterman
1
¿Podría agregar uno entonces? Gracias :) Encontré que entre comillas dobles parece funcionar: echo / | sed "s / \ // a / g"
Max Waterman
@MaxWaterman es un procedimiento operativo estándar cuando se usa sedel comando regex entre comillas dobles. No los usé en mi respuesta porque no estaba mostrando la sedlínea de comando completa , sino solo la sedcadena de comando regex como lo había hecho el OP. Si lo coloca en un archivo, como lo hizo el OP, no necesita las comillas.
merodeador
Sí, bastante justo (aunque tal vez podría mencionarse). Ese ejemplo ayuda. He descubierto que necesito poner muchas barras invertidas a veces ... y se vuelve realmente confuso. por ejemplo, -e "s / '/ \\\\\\\\ & / g" Creo que el texto está equivocado, sin embargo: "¿Cuál reemplazaría \ por foo"? debería ser "Cuál reemplazaría / por foo", ¿no?
Max Waterman el
@MaxWaterman gracias por atrapar eso en \ vs./. Arreglado. Si tiene un sedcomando en un script de shell, es posible que se necesiten más barras inclinadas invertidas (cada barra invertida debe reducirse nuevamente).
merodeador
105

El scomando puede usar cualquier carácter como delimitador; cualquier personaje viene después de que sse usa. Fui educado para usar a #. Al igual que:

s#?page=one&#/page/one#g
Tom Anderson
fuente
55
La página del manual para el BSD sed en OS X dice del comando s : Sustituya la cadena de reemplazo por la primera instancia de la expresión regular en el espacio del patrón. Se puede usar cualquier carácter que no sea la barra diagonal inversa o la nueva línea en lugar de una barra diagonal para delimitar el RE y el reemplazo. Apostaría dinero a que la página de manual de GNU sed dice algo similar.
Tom Anderson el
La respuesta actual aceptada es básicamente la misma que esta, ¡y se publicó un minuto antes!
Tom Anderson
61

Un hecho muy útil pero menos conocido sobre sed es que el s/foo/bar/comando familiar puede usar cualquier puntuación, no solo barras. Una alternativa común es s@foo@bar@, a partir de la cual se hace evidente cómo resolver su problema.

John Zwinck
fuente
Un consejo genial cuando quieras sustituir las barras diagonales. ¡Gracias!
mbb
9

agregar \ antes de caracteres especiales:

s/\?page=one&/page\/one\//g

etc.

Ilja
fuente
44
Puede que me haya perdido algo, pero lo he intentado y parece que no funciona. Parecía lo más obvio intentarlo, pero suponiendo que estoy en lo cierto y realmente no funciona, ¿por qué publicarlo?
codenoob
44
@codenoob (y cualquier otra persona que llegue aquí): se requiere la 's' al principio. s/foo\/bar/foo_bar/funcionará, pero /foo\/bar/foo_bar/no lo hará.
MynockSpit
5

En un sistema que estoy desarrollando, la cadena que se reemplazará por sed es el texto de entrada de un usuario que se almacena en una variable y se pasa a sed.

Como se señaló anteriormente en esta publicación, si la cadena contenida dentro del bloque de comando sed contiene el delimitador real utilizado por sed, entonces sed termina en un error de sintaxis. Considere el siguiente ejemplo:

Esto funciona:

$ VALUE=12345
$ echo "MyVar=%DEF_VALUE%" | sed -e s/%DEF_VALUE%/${VALUE}/g
MyVar=12345

Esto se rompe:

$ VALUE=12345/6
$ echo "MyVar=%DEF_VALUE%" | sed -e s/%DEF_VALUE%/${VALUE}/g
sed: -e expression #1, char 21: unknown option to `s'

Reemplazar el delimitador predeterminado no es una solución sólida en mi caso, ya que no quería limitar al usuario la entrada de caracteres específicos utilizados por sed como delimitador (por ejemplo, "/").

Sin embargo, escapar de cualquier ocurrencia del delimitador en la cadena de entrada resolvería el problema. Considere la siguiente solución de escapar sistemáticamente del carácter delimitador en la cadena de entrada antes de analizarlo mediante sed. Tal escape se puede implementar como un reemplazo usando sed, este reemplazo es seguro incluso si la cadena de entrada contiene el delimitador, esto se debe a que la cadena de entrada no es parte del bloque de comando sed:

$ VALUE=$(echo ${VALUE} | sed -e "s#/#\\\/#g")
$ echo "MyVar=%DEF_VALUE%" | sed -e s/%DEF_VALUE%/${VALUE}/g
MyVar=12345/6

He convertido esto en una función para ser utilizada por varios scripts:

escapeForwardSlashes() {

     # Validate parameters
     if [ -z "$1" ]
     then
             echo -e "Error - no parameter specified!"
             return 1
     fi

     # Perform replacement
     echo ${1} | sed -e "s#/#\\\/#g"
     return 0
}
Yoav Drori
fuente
1
Lo que me quitó su respuesta fue que si el VALOR que está usando para reemplazar DEF_VALUE tiene barras diagonales, debe escapar de ellas con 3 barras diagonales inversas para que sed funcione, por ejemploVALUE="01\\\/01\\\/2018"
alexkb
3

esta línea debería funcionar para tus 3 ejemplos:

sed -r 's#\?(page)=([^&]*)&#/\1/\2#g' a.txt
  • Solía -rahorrar un poco de escape.
  • la línea debe ser genérica para su caso uno, dos tres. no tienes que hacer el sub 3 veces

prueba con tu ejemplo (a.txt):

kent$  echo "?page=one&
?page=two&
?page=three&"|sed -r 's#\?(page)=([^&]*)&#/\1/\2#g'
/page/one
/page/two
/page/three
Kent
fuente
1

replace.txt debiera ser

s/?page=/\/page\//g
s/&//g
Ion Cojocaru
fuente
1

Gran respuesta de Anónimo. \ resolvió mi problema cuando intenté escapar de las comillas en cadenas HTML.

Entonces, si usa sed para devolver algunas plantillas HTML (en un servidor), use una barra diagonal inversa doble en lugar de una sola:

var htmlTemplate = "<div style=\\"color:green;\\"></div>";
Sirar Salih
fuente
1

sedes el s TREAM ed itor , en el que se puede utilizar |(tubería) para enviar flujos estándares (entrada y salida estándar específicamente) a través sedy modificarlos mediante programación sobre la marcha, por lo que es una herramienta muy útil en la filosofía de la tradición Unix; pero también puede editar archivos directamente, utilizando el -iparámetro mencionado a continuación.
Considere lo siguiente :

sed -i -e 's/few/asd/g' hello.txt

s/se utiliza para s ubstitute la expresión que se encuentra fewcon asd:

Los pocos, los valientes.


El asd, el valiente.

/gsignifica "global", lo que significa hacer esto para toda la línea. Si deja el /g(con s/few/asd/, siempre debe haber tres barras sin importar qué) y fewaparece dos veces en la misma línea, solo el primero fewse cambia a asd:

Los pocos hombres, las pocas mujeres, los valientes.


Los hombres asd, las pocas mujeres, los valientes.

Esto es útil en algunas circunstancias, como alterar caracteres especiales al comienzo de las líneas (por ejemplo, reemplazar los símbolos mayores que algunas personas usan para citar material anterior en hilos de correo electrónico con una pestaña horizontal mientras deja una desigualdad algebraica citada más adelante en la línea intacto), pero en su ejemplo donde especifica que en cualquier few lugar se debe reemplazar, asegúrese de tenerlo /g.

Las siguientes dos opciones (banderas) se combinan en una sola -ie:

-iopción se utiliza para editar i n lugar en el archivo hello.txt.

-eopción indica el correo Xpression / comando a ejecutar, en este caso s/.

Nota: es importante que utilice -i -epara buscar / reemplazar. Si lo hace -ie, crea una copia de seguridad de cada archivo con la letra 'e' añadida.

Chaminda Bandara
fuente
0

Una alternativa más simple es usar AWK como en esta respuesta :

awk '$0="prefix"$0' file > new_file

marca
fuente