Reemplace la línea completa que contiene una cadena usando Sed

319

Tengo un archivo de texto que tiene una línea particular algo así como

sometext sometext sometext TEXT_TO_BE_REPLACED sometext sometext sometext

Necesito reemplazar toda la línea de arriba con

This line is removed by the admin.

La palabra clave de búsqueda es TEXT_TO_BE_REPLACED

Necesito escribir un script de shell para esto. ¿Cómo puedo lograr esto usando sed?

Rahul
fuente
@Scharron Intenté sed -rne 's / (TEXT_TO_BE_REPLACED) \ s + \ w + / \ 1 aaa / xxx' Pero eso simplemente reemplazaría aaa con xxx en la cadena si hay aaa presente. En mi caso, el texto no es fijo ... todo lo que tengo es TEXT_TO_BE_REPLACED.
Rahul
esa no es una expresión sed válida. ¿Seguro que lo quieres con sed? Cualquier lenguaje de programación con buenas expresiones regulares puede reemplazarlo (busque una subfunción). Eso sería más fácil que comprenderlo solo
Scharron
@Scharron Bueno, se debe hacer con shell script, así que supongo que sed es mi mejor opción.
Rahul

Respuestas:

483

Puede usar el comando de cambio para reemplazar toda la línea y la -ibandera para realizar los cambios en el lugar. Por ejemplo, usando GNU sed:

sed -i '/TEXT_TO_BE_REPLACED/c\This line is removed by the admin.' /tmp/foo
Todd A. Jacobs
fuente
44
Tenga en cuenta que necesita un espacio antes de c \. Acabo de editar para agregar esto.
Marcus Downing
27
@MarcusDowning GNU sed no requiere espacio; funciona bien como se publicó originalmente. Si su sed en particular requiere el espacio, entonces tenga en cuenta qué sed es incompatible y agregue la invocación necesaria como comentario. Sin embargo, no cambie el código de trabajo en una respuesta aceptada.
Todd A. Jacobs
77
¿Cómo puedo usar una variable en lugar del texto "Esto ..."? Si lo reemplazo por $ variable, no imprime su contenido sino el nombre de la variable.
Steven
18
Hay un problema con c\ cuando se sigue directamente una variable: …c\$VAR…la barra invertida escapará al dólar. En este caso, tuve que escribir (bash / sed en Ubuntu 15.10)…c\\$VAR…
enero
66
en un uso mac: sed -i '' '/TEXT_TO_BE_REPLACED/c\This line is removed by the admin.' /tmp/foo; (cuando el primer parámetro está en blanco se edita en el archivo, de lo contrario crea una copia de seguridad)
AndreDurao
152

Debe usar wildards ( .*) antes y después para reemplazar toda la línea:

sed 's/.*TEXT_TO_BE_REPLACED.*/This line is removed by the admin./'
Thor
fuente
Gracias, tengo el mío funcionando: sed 's /.* <expresión>. * / <Expresión> SE_LABEL = ABC <expresión> / g' MYR2.xml> test.txt
Nasri Najib
99
Esto está funcionando en Mac OS X Yosemite con la excepción de que estoy usando los indicadores -i y -e de la siguiente manera:sed -i -e "s/.*search_string.*/Replacement_line/' file_being_searched.txt
Kent Bull
1
@KentJohnson Creo que tiene comillas no coincidentes en su comando.
HashHazard
@MBarnett tienes razón, debería tener dos comillas dobles allí.
Kent Bull
2
Solo por la información completa. Para hacerlo in situ, se puede agregar una -iopción
Temak,
20

La respuesta aceptada no me funcionó por varias razones:

  • mi versión de sed no me gusta -icon una extensión de longitud cero
  • la sintaxis del c\comando es extraña y no pude hacerlo funcionar
  • No me di cuenta de que algunos de mis problemas provienen de cortes sin escape

Así que aquí está la solución que se me ocurrió y creo que debería funcionar para la mayoría de los casos:

function escape_slashes {
    sed 's/\//\\\//g' 
}

function change_line {
    local OLD_LINE_PATTERN=$1; shift
    local NEW_LINE=$1; shift
    local FILE=$1

    local NEW=$(echo "${NEW_LINE}" | escape_slashes)
    sed -i .bak '/'"${OLD_LINE_PATTERN}"'/s/.*/'"${NEW}"'/' "${FILE}"
    mv "${FILE}.bak" /tmp/
}

Entonces, el uso de muestra para solucionar el problema planteado:

change_line "TEXT_TO_BE_REPLACED" "This line is removed by the admin." yourFile
skensell
fuente
18

La respuesta anterior:

sed -i '/TEXT_TO_BE_REPLACED/c\This line is removed by the admin.' /tmp/foo

Funciona bien si la cadena / línea de reemplazo no es una variable.

El problema es que en Redhat 5 \después de la cfuga $. Un doble \\tampoco funcionó (al menos en Redhat 5).

A través de hit y trial, descubrí que el \after ces redundante si su cadena / línea de reemplazo es solo una línea. Entonces no lo usé \después c, usé una variable como una sola línea de reemplazo y fue una alegría.

El código se vería así:

sed -i "/TEXT_TO_BE_REPLACED/c $REPLACEMENT_TEXT_STRING" /tmp/foo

Tenga en cuenta el uso de comillas dobles en lugar de comillas simples.

usuario4256255
fuente
todavía puede usar comillas simples como esta: sed -i '/ TEXT_TO_BE_REPLACED / c' "$ VARIABLE" '' / tmp / foo
Alistair McIntyre
4

Todas las respuestas proporcionadas hasta ahora suponen que usted sabe algo sobre el texto que se va a reemplazar, lo que tiene sentido, ya que eso es lo que le preguntó el OP. Le proporciono una respuesta que asume que no sabe nada sobre el texto que se va a reemplazar y que puede haber una línea separada en el archivo con el mismo contenido o contenido similar que no desea reemplazar. Además, supongo que conoce el número de línea de la línea que se va a reemplazar.

Los siguientes ejemplos demuestran la eliminación o el cambio de texto por números de línea específicos:

# replace line 17 with some replacement text and make changes in file (-i switch)
# the "-i" switch indicates that we want to change the file. Leave it out if you'd
#   just like to see the potential changes output to the terminal window.
# "17s" indicates that we're searching line 17
# ".*" indicates that we want to change the text of the entire line
# "REPLACEMENT-TEXT" is the new text to put on that line
# "PATH-TO-FILE" tells us what file to operate on
sed -i '17s/.*/REPLACEMENT-TEXT/' PATH-TO-FILE

# replace specific text on line 3
sed -i '3s/TEXT-TO-REPLACE/REPLACEMENT-TEXT/'
b_laoshi
fuente
3

para la manipulación de archivos de configuración

se me ocurrió esta solución inspirada en la respuesta de skensell

configLine [searchPattern] [replaceLine] [filePath]

va a:

  • crea el archivo si no existe
  • reemplace toda la línea (todas las líneas) donde searchPattern coincidió
  • agregue replaceLine al final del archivo si no se encontró el patrón

Función:

function configLine {
  local OLD_LINE_PATTERN=$1; shift
  local NEW_LINE=$1; shift
  local FILE=$1
  local NEW=$(echo "${NEW_LINE}" | sed 's/\//\\\//g')
  touch "${FILE}"
  sed -i '/'"${OLD_LINE_PATTERN}"'/{s/.*/'"${NEW}"'/;h};${x;/./{x;q100};x}' "${FILE}"
  if [[ $? -ne 100 ]] && [[ ${NEW_LINE} != '' ]]
  then
    echo "${NEW_LINE}" >> "${FILE}"
  fi
}

la magia del estado de salida loca viene de https://stackoverflow.com/a/12145797/1262663

Grano
fuente
2
bash-4.1$ new_db_host="DB_HOSTNAME=good replaced with 122.334.567.90"
bash-4.1$ 
bash-4.1$ sed -i "/DB_HOST/c $new_db_host" test4sed
vim test4sed
'
'
'
DB_HOSTNAME=good replaced with 122.334.567.90
'

funciona bien

nkl
fuente
1

En mi archivo MAKE uso esto:

@sed -i '/.*Revision:.*/c\'"`svn info -R main.cpp | awk '/^Rev/'`"'' README.md

PD: NO olvide que -i cambia realmente el texto en el archivo ... así que si cambia el patrón que definió como "Revisión", también cambiará el patrón para reemplazarlo.

Salida de ejemplo:

Proyecto Abc escrito por John Doe

Revisión: 1190

Entonces, si configura el patrón "Revisión: 1190" obviamente no es lo mismo que los definió como "Revisión:" solamente ...

Martin Pfeffer
fuente
1
cat find_replace | while read pattern replacement ; do
sed -i "/${pattern}/c ${replacement}" file    
done 

El archivo find_replace contiene 2 columnas, c1 con patrón para que coincida, c2 con reemplazo, el bucle sed reemplaza cada línea que contiene uno del patrón de la variable 1

sjordi
fuente
No, esto está mal en varios aspectos. Ejecute seduna vez con un archivo de secuencia de comandos que contiene todos los reemplazos que desea realizar. Ejecutar sed -ien el mismo archivo repetidamente es un antipatrón horrible.
tripleee
0

Es tan similar al anterior.

sed 's/[A-Za-z0-9]*TEXT_TO_BE_REPLACED.[A-Za-z0-9]*/This line is removed by the admin./'
Annapureddy Hari
fuente
3
Que cambia FOO=TEXT_TO_BE_REPLACEDa FOO=This line ...no cumple con la especificación.
Jens
Sí. Nuestro requisito es reemplazar toda la línea con 'Esta línea es eliminada por el administrador'. si encontramos la clave pattren 'TEXT_TO_BE_REPLACED'. El comando anterior es satisfactorio. Corrígeme si mi comprensión es incorrecta .. @Jens
Annapureddy Hari
@AnnapureddyHari esta respuesta no funciona si el texto anterior o posterior a la cadena de búsqueda contiene algo además de A-Za-z0-9. Falla si hay un signo igual, como señaló Jens. La porción "FOO =" permanecerá; No ha reemplazado toda la línea. Este código es miope sobre lo que podría estar en el archivo. Si te refieres a comodín, deberías poner comodín, como lo muestra la respuesta de Thor.
msouth
0

El siguiente comando funciona para mí. Que está trabajando con variables

sed -i "/\<$E\>/c $D" "$B"
Ritesh Borkar
fuente
Pero mi nuevo requisito es SALTAR la línea comentada (comienza con #) mientras se reemplaza. Como estamos reemplazando la línea completa, esto también reemplazará las líneas comentadas y terminará con propiedades duplicadas. Si alguien tiene una solución para esto, hágamelo saber.
Ritesh Borkar
-1

Muy a menudo uso expresiones regulares para extraer datos de archivos, solo lo usé para reemplazar la cita literal \"con //nada :-)

cat file.csv | egrep '^\"([0-9]{1,3}\.[0-9]{1,3}\.)' | sed  s/\"//g  | cut -d, -f1 > list.txt
staM
fuente