2010-11-09 20 views
24

Para grep hay una opción de cadena fija, -F (fgrep) para desactivar la interpretación de expresiones regulares de la cadena de búsqueda. ¿Existe una instalación similar para sed? No pude encontrar nada en el hombre. Una recomendación de otra herramienta gnu/linux también estaría bien.sed o similar: no interpretar como expresiones regulares, interpretar como cadena fija/literal

estoy usando sed para la funcionalidad de búsqueda y reemplazo: sed -i "s/abc/def/g"

+0

posible duplicado de [Escape una cadena de patrón de búsqueda SED] (http://stackoverflow.com/questions/407523/escape-a-string-for-sed-search-pattern) –

Respuesta

5

Debería utilizar replace en lugar de sed.

Desde la página del manual:

The replace utility program changes strings in place in files or on the 
    standard input. 

    Invoke replace in one of the following ways: 

     shell> replace from to [from to] ... -- file_name [file_name] ... 
     shell> replace from to [from to] ... < file_name 

    from represents a string to look for and to represents its replacement. 
    There can be one or more pairs of strings. 
+5

hmmm, no tiene instalado 'replace' - parece ser una herramienta relacionada con MySQL? Tengo MySql instalado; ¿hay una instalación separada para reemplazar? – EoghanM

+0

No viene en un paquete separado, lo siento. Podrías tratar de encontrarlo en el árbol fuente mysql y compilarlo tú mismo, pero eso es una gran molestia. Entonces tienes mysql, pero no '/ usr/bin/replace'? Podría intentar reinstalar el paquete mysql ('mysql-server'). –

+0

no en/usr/bin y no se puede reinstalar! Aceptaré tu respuesta suponiendo que funciona :) – EoghanM

4

Opción 1) Escapar caracteres de expresiones regulares. P.ej. sed 's/\$0\.0/0/g' reemplazará todas las ocurrencias de $ 0.0 con 0.

Opción 2) Use perl -p -e junto con quotemeta. P.ej. perl -p -e 's/\\./,/gi' reemplazará todas las ocurrencias de . con ,.

Puede utilizar la opción 2 en secuencias de comandos de esta manera:

SEARCH="C++" 
REPLACE="C#" 
cat $FILELIST | perl -p -e "s/\\Q$SEARCH\\E/$REPLACE/g" > $NEWLIST 
+0

Ha Perl consiguió una equivalente de sed's -i? Estoy usando sed de la siguiente manera: find -name "* myfiles *" | xargs sed -i "s/abc/def/g" – EoghanM

+0

¡Veo que tu ejemplo de Perl se interpreta como una expresión regular! – EoghanM

+0

$ echo "a.b.c" | perl -p -e 's /./,/ g' me da ",,,,," y no "a, b, c" – EoghanM

6

No hay que usar sed? Si estás escribiendo un script bash, puede hacerlo

#!/bin/bash 
pattern='abc' 
replace='def' 
file=/path/to/file 
tmpfile="${TMPDIR:-/tmp}/$(basename "$file").$$" 
while read -r line 
do 
    echo ${line/$pattern/$replace} 
done < "$file" > "$tmpfile" && mv "$tmpfile" "$file" 

Con una cáscara de Bourne mayores (como ksh88 o SH POSIX), puede que no tenga que ${var/pattern/replace} estructura fresco, pero usted tiene ${var#pattern} y ${var%pattern}, que se puede usar para dividir la cuerda y luego volver a montarla. Si necesita hacer eso, tendrá mucho más código, pero en realidad no es tan malo.

Si no estás en un script de shell ya, muy fácilmente podría hacer que el patrón, reemplazar, y los parámetros de nombre de archivo y simplemente llamar a esto. :)

PS: la estructura $ {TMPDIR: -/tmp} usa $ TMPDIR si eso está establecido en su entorno, o usa/tmp si la variable no está configurada. Me gusta pegar el pid del proceso actual al final del nombre de archivo con la esperanza de que será un poco más único. Probablemente deberías usar mktemp o similar en el "mundo real", pero esto está bien para un ejemplo rápido, y el binario mktemp no siempre está disponible.

+0

Esta es una solución lenta. Se requiere echo para cada línea del archivo que podría mover miles de procesos de eco si está utilizando un archivo grande o múltiples. – John

+2

echo normalmente se implementa como un shell incorporado, que debe bifurcar 0 procesos en un shell moderno como bash. – dannysauer

+0

Puede ver los builtins en el trabajo utilizando "strace -e trace = process ./shellscript". Escriba la secuencia de comandos anterior y vea cuántas llamadas de fork hay. Usando un Bash actual en un Ubuntu actual, hay 2 llamadas fork (en realidad clone(), que es más rápido que fork()). Uno para el subshell donde se ejecuta basename, y otro para el mv. Si reescribió esto usando "/ bin/echo", por otro lado, en realidad hay una nueva horquilla para cada línea. Y podría ver que tarda mucho * más tiempo en ejecutarse. :) – dannysauer

3

Si usted no está opone a Ruby o líneas largas, se puede usar esto:

alias replace='ruby -e "File.write(ARGV[0], File.read(ARGV[0]).gsub(ARGV[1], ARGV[2]))"' 

replace test3.txt abc def 

Esto carga el archivo completo en la memoria, realiza la reemplazos y lo guarda de nuevo en el disco. Probablemente no debería usarse para archivos masivos.

1

si no quieren escapar de la cadena,
se puede llegar a su objetivo en 2 pasos:

fgrep la línea (conseguir el LineNumber) que desea reemplazar,
y después utilizar sed para reemplazar esta línea.

p. Ej.

#/bin/sh 
PATTERN='foo*[)*abc' # we need it literal 
LINENUMBER="$(fgrep -n "$PATTERN" "$FILE" | cut -d':' -f1)" 

NEWSTRING='my new string' 
sed -i "${LINENUMBER}s/.*/$NEWSTRING/" "$FILE" 
Cuestiones relacionadas