Si desea reemplazar una palabra clave con una cadena usando sed, sed se esfuerza por interpretar su cadena de reemplazo. Si la cadena de reemplazo tiene caracteres que sed considera especiales, como un carácter '/', fallará, a menos que, por supuesto, haya querido decir que su cadena de reemplazo tiene caracteres que le dicen a sed cómo actuar.
Ex:
VAR="hi/"
sed "s/KEYWORD/$VAR/g" somefile
¿Hay alguna forma de decirle a sed que no intente interpretar la cadena de reemplazo para caracteres especiales? Todo lo que quiero es poder reemplazar una palabra clave en un archivo con el contenido de una variable, sin importar cuál sea ese contenido.
bash
shell-script
sed
Tal
fuente
fuente
sed
y hacer que no sean especiales, simplemente barra diagonal inversa escapar de ellos.VAR='hi\/'
No da tal problema.sed(1)
solo interpreta lo que se pone. En su caso, lo obtiene a través de una interpolación de shell. Creo que no puede hacer lo que quiere, pero consulte el manual. Sé que en Perl (que hace unsed
reemplazo pasable , con expresiones regulares mucho más ricas) puede especificar que una cadena se tome literalmente, nuevamente, consulte el manual.Respuestas:
Sólo hay 4 caracteres especiales en la pieza de repuesto: \, &, nueva línea y el delimitador ( ref )
fuente
s///
es una expresión regular, en realidad es solo una cadena (a excepción de las barras invertidas y los escapes ). Si la cadena de reemplazo es tan larga, un revestimiento de concha no es su solución.&
Puede usar Perl en lugar de sed con
-p
(asumir el bucle sobre la entrada) y-e
(dar el programa en la línea de comandos). Con Perl puede acceder a las variables de entorno sin interpolarlas en el shell. Tenga en cuenta que la variable debe exportarse :Si no desea exportar la variable a todas partes, solo debe proporcionarla para ese proceso únicamente:
Tenga en cuenta que la sintaxis de expresión regular de Perl es, por defecto, ligeramente diferente de la de sed.
fuente
PATTERN
variable de entorno , no en argumentos. En cualquier caso, este error seríaE2BIG
, que igualmente obtendría si lo usarased
.La solución más simple que aún manejaría correctamente la gran mayoría de los valores de las variables sería utilizar un carácter que no se imprima como delimitador del
sed
comando sustituto.En
vi
puede escapar de cualquier carácter de control escribiendo Ctrl-V (más comúnmente escrito como^V
). Entonces, si usa algún carácter de control (a menudo lo uso^A
como delimitador en estos casos), sused
comando solo se romperá si ese carácter no imprimible está presente en la variable que está colocando.Entonces escribiría
"s^V^AKEYWORD^V^A$VAR^V^Ag"
y lo que obtendría (envi
) se vería así:Esto funcionará siempre
$VAR
que no contenga el carácter que no se imprime, lo^A
cual es extremadamente improbable.Por supuesto, si pasa la entrada del usuario al valor de
$VAR
, entonces todas las apuestas están desactivadas y será mejor que desinfecte su entrada a fondo en lugar de confiar en que los caracteres de control son difíciles de escribir para el usuario promedio.Sin embargo, en realidad hay más de qué tener cuidado que la cadena delimitador. Por ejemplo,
&
cuando está presente en una cadena de reemplazo, significa "todo el texto que coincidió". Por ejemplo,s/stu../my&/
reemplazaría "cosas" con "mystuff", "picado" con "mystung", etc. Entonces, si tiene algún carácter en la variable que está colocando como una cadena de reemplazo, pero desea usar el literal solo el valor de la variable, entonces tiene que desinfectar algunos datos antes de poder usar la variable como una cadena de reemplazosed
. (Sinsed
embargo, la desinfección de datos también se puede hacer ).fuente
sed
eli
comando nsert. Perosed
no es una buena herramienta para procesar grandes cantidades de texto de formas complejas. Publicaré otra respuesta que muestre cómo hacer estoawk
.En su lugar, puede usar a
,
o a|
y lo tomará como un separador y técnicamente podría usar cualquier cosadesde la página del manual
Como puede ver, debe comenzar con un \ antes de su separador al principio, luego puede usarlo como separador.
de la documentación http://www.gnu.org/software/sed/manual/sed.html#The-_0022s_0022-Command :
Ejemplo:
sed -e 'somevar|s|foo|bar|'
echo "Hello all" | sed "s_all_user_"
echo "Hello all" | sed "s,all,user,"
echo "Hello/ World" | sed "s,Hello/,Neo,"
fuente
/
e ignorará/
felizmente como acabo de señalar ... de hecho, incluso puedes buscarlo y reemplazarlo en una cadena >>> he editado con un ejemplo >>> estos las cosas no son tan seguras y siempre encontrarás un tipo más inteligentesed
en primer lugar, ¿cuál es su proyecto?bash
es para manipulación de cadenas. En absoluto, en absoluto, en absoluto. Es para la manipulación de archivos y la coordinación de comandos . Resulta que tiene algunas funciones prácticas incorporadas para cadenas, pero realmente limitadas y no muy rápidas si eso es lo principal que está haciendo. Consulte "¿Por qué usar un bucle de shell para procesar texto se considera una mala práctica?" Algunas herramientas que están diseñadas para el procesamiento de texto son, en orden de la más básica a la más poderosa , y Perl.sed
awk
Si se basa en una línea y solo se debe reemplazar una línea, recomiendo anteponer el archivo con la línea de reemplazo usando
printf
, almacenar esa primera línea ensed
el espacio de espera y soltarla según sea necesario. De esta manera, no tiene que preocuparse por caracteres especiales en absoluto. (La única suposición aquí es que$VAR
contiene una sola línea de texto sin líneas nuevas, que es lo que ya dijo en los comentarios). Además de las líneas nuevas, VAR podría contener cualquier cosa y esto funcionaría independientemente.printf '%s\n'
imprimirá el contenido de$VAR
como una cadena literal, independientemente de su contenido, seguido de una nueva línea. (echo
en algunos casos, hará otras cosas, por ejemplo, si el contenido de$VAR
comienza con un guión, se interpretará como un indicador de opción al que se pasaecho
).Las llaves se usan para anteponer la salida de
printf
los contenidos de asomefile
medida que se pasansed
. El espacio en blanco que separa las llaves por sí mismos es importante aquí, al igual que el punto y coma antes de la llave de cierre.1{h;d;};
comosed
comando almacenará la primera línea de texto ensed
el espacio de espera y luegod
elegirá la línea (en lugar de imprimirla)./KEYWORD/
aplica las siguientes acciones a todas las líneas que contienenKEYWORD
. La acción esg
et, que obtiene el contenido del espacio de espera y lo coloca en lugar del espacio del patrón; en otras palabras, la línea actual completa. (Esto no es para reemplazar solo una parte de una línea.) El espacio de espera no se vacía, por cierto, solo se copia en el espacio del patrón, reemplazando lo que esté allí.Si desea anclar su expresión regular para que no coincida con una línea que simplemente contiene KEYWORD, sino solo una línea donde no hay nada más en la línea que KEYWORD, agregue un ancla de inicio de línea (
^
) y un ancla de final de línea ($
) a tu expresión regular:fuente
Puede hacer una barra diagonal inversa para escapar de las barras diagonales en su cadena de reemplazo, utilizando la expansión del parámetro de sustitución de patrones de Bash. Es un poco desordenado porque las barras diagonales también deben escaparse para Bash.
salida
Usted podría poner la expansión de parámetros directamente en su comando sed:
pero creo que la primera forma es un poco más legible. Y, por supuesto, si va a reutilizar el mismo patrón de reemplazo en múltiples comandos sed, tiene sentido hacer la conversión una vez.
Otra opción sería usar un script escrito en awk, perl o Python, o un programa en C, para hacer sus sustituciones en lugar de usar sed.
Aquí hay un ejemplo simple en Python que funciona si la palabra clave que se va a reemplazar es una línea completa en el archivo de entrada (sin contar la nueva línea). Como puede ver, es esencialmente el mismo algoritmo que su ejemplo de Bash, pero lee el archivo de entrada de manera más eficiente.
fuente
\x
secuencias de escape de estilo. O para usar un programa que pueda manejar entradas arbitrarias, como mencioné en mi último párrafo.Así es como fui:
esto funciona muy bien en mi caso porque mi palabra clave está en una línea por sí sola. Si la palabra clave estuviera en una línea con otro texto, esto no funcionaría.
Todavía me gustaría saber si hay una manera fácil de hacer esto que no implique codificar mi propia solución.
fuente
echo
en absoluto. Usar en suprintf
lugar. Y hacer procesamiento de texto en un bucle de shell es una mala idea.read
es bastante lento. Está destinado a procesar la entrada interactiva del usuario, no al procesamiento de archivos de texto. Es lento porque lee stdin char por char, haciendo una llamada al sistema para cada char.printf "hi\n"
hará que printf imprima una nueva línea mientras laecho "hi\n"
imprime tal como está.printf
significa "formato": el primer argumentoprintf
es un especificador de formato . Si ese especificador es%s\n
, que significa "cadena seguida de nueva línea", nada en el siguiente argumento será interpretado o traducidoprintf
en absoluto . (El shell todavía puede interpretarlo, por supuesto; es mejor pegarlo todo entre comillas simples si es una cadena literal, o comillas dobles si desea una expansión variable). Vea mi respuesta usandoprintf
para obtener más detalles.