¿Cómo eliminar de un archivo de texto todas las líneas que contienen una cadena específica?

¿Cómo usaría sed para eliminar todas las líneas en un archivo de texto que contiene una cadena específica?

preguntado el 23 de marzo de 11 a las 16:03

19 Respuestas

Para eliminar la línea e imprimir la salida en salida estándar:

sed '/pattern to match/d' ./infile

Para modificar directamente el archivo, no funciona con BSD sed:

sed -i '/pattern to match/d' ./infile

Lo mismo, pero para BSD sed (Mac OS X y FreeBSD) - no funciona con GNU sed:

sed -i '' '/pattern to match/d' ./infile

Para modificar directamente el archivo (y crear una copia de seguridad), funciona con BSD y GNU sed:

sed -i.bak '/pattern to match/d' ./infile

Respondido el 27 de junio de 19 a las 10:06

Gracias, pero no parece borrarlo del archivo, solo imprime el contenido del archivo de texto sin esa cadena. - Una Naranja Mecánica

@A Clockwork: sí, debe redirigir la salida a un nuevo archivo con algo como sed '/pattern to match/d' ./infile > ./newfile o si desea realizar una edición en el lugar, puede agregar la -i bandera a sed como en sed -i '/pattern to match/d' ./infile. Tenga en cuenta que el -i flag requiere GNU sed y no es portátil - asedioX

Para algunos sabores de sed; El indicador "-i" de sed requería que se proporcionara una extensión. (p.ej sed -i.backup '/pattern to match/d' ./infile) Eso me ayudó con las ediciones in situ. - Avelis

@SiegeX Mejor aún, no aplique comandos como sed a cualquier archivo que no esté controlado por versión. - matrizrana

Una nota más para los usuarios de Mac OS X: por alguna razón, la bandera -i requiere que se pase un argumento, incluso si es solo una cadena vacía, como sed -i '' '/pattern/d' ./infile. - geerlingguy

Hay muchas otras formas de eliminar líneas con una cadena específica además sed:

AWK

awk '!/pattern/' file > temp && mv temp file

Rubí (1.9+)

ruby -i.bak -ne 'print if not /test/' file

Perl

perl -ni.bak -e "print unless /pattern/" file

Shell (bash 3.2 y posterior)

while read -r line
do
  [[ ! $line =~ pattern ]] && echo "$line"
done <file > o
mv o file

GNU grep

grep -v "pattern" file > temp && mv temp file

Y por supuesto sed (imprimir el inverso es más rápido que la eliminación real):

sed -n '/pattern/!p' file

Respondido el 15 de Septiembre de 18 a las 23:09

¿Cómo eliminar una línea en particular con un patrón y también la línea inmediatamente superior? Tengo una multa con miles de líneas de este tipo entre diferentes datos. - oortcloud_domicilio

En OS / X, la variación de shell no conserva los espacios iniciales, pero la variación grep -v funcionó bien para mí. - Pablo Beusterien

el sed ejemplo tiene un comportamiento diferente, ¡solo greps! debería ser algo como sed -n -i '/pattern/!p' file. - cesarsol

La versión grep no funciona cuando todas las líneas coinciden con el patrón. Mejor hazlo: grep -v "pattern" file > temp; mv temp file Esto podría aplicarse a algunos de los otros ejemplos según el valor de retorno. - chris maes

"imprimir lo inverso es más rápido que eliminarlo": no en mi máquina (2012 MacBook Air, OS X 10.13.2). Crea un archivo: seq -f %f 10000000 >foo.txt. sed d: time sed -i '' '/6543210/d' foo.txt real 0m9.294s. sed! p: time sed -i '' -n '/6543210/!p' foo.txt real 0m13.671s. (Para archivos más pequeños, la diferencia es mayor). jcsahnwaldt Reincorporar a Monica

Puede usar sed para reemplazar líneas en su lugar en un archivo. Sin embargo, parece ser mucho más lento que usar grep para el inverso en un segundo archivo y luego mover el segundo archivo sobre el original.

p.ej

sed -i '/pattern/d' filename      

or

grep -v "pattern" filename > filename2; mv filename2 filename

El primer comando tarda 3 veces más en mi máquina de todos modos.

Respondido 19 ago 15, 16:08

Votando tu respuesta también, ¡solo porque probaste una comparación de rendimiento! - anuragw

+1 para ofrecer la opción de sobrescribir el archivo actual con la línea grep. - Rhyuk

La segunda solución 'grep' también es mejor para archivos grandes: simoes

Tengo curiosidad por saber cuál sería la diferencia de rendimiento si fuera sed '/pattern/d' filename > filename2; mv filename2 filename - Pete

(usando ubuntu's / usr / share / dict / words) grep y mv: 0.010s | sed en su lugar: 0.197s | sed y mv: 0.031s - Reactivo Cuervo

La forma más fácil de hacerlo, con GNU sed:

sed --in-place '/some string here/d' yourfile

Respondido el 11 de diciembre de 17 a las 23:12

Un consejo útil para otros que se tropiecen con este hilo de preguntas y respuestas y son nuevos en la creación de scripts de shell: las opciones cortas están bien para usos únicos en la línea de comandos, pero las opciones largas deben preferirse en los scripts, ya que son más legibles. - Dennis

+1 para la bandera --in-place. Necesito probar eso en archivos protegidos con permisos. (tengo que hacer un barrido de usuario). Abeja kay

Tenga en cuenta que la opción larga solo está disponible en GNU sed. Los usuarios de Mac y BSD necesitarán instalar gsed para hacerlo de esta manera. - Matt

Otro consejo: si su expresión regular no parece coincidir, pruebe el -r opción (o -E, dependiendo de su versión). Esto permite el uso de metacaracteres de expresiones regulares +, ?, {...} y (...). - rjh

Esta es la respuesta correcta cuando su disco no tiene más espacio y no puede copiar el texto a otro archivo. ¿Este comando hace lo que se cuestionó? - ferreirabraga

Puede considerar usar ex (que es un editor estándar basado en comandos de Unix):

ex +g/match/d -cwq file

dónde:

  • + ejecuta un comando Ex dado (man ex), igual que -c que ejecuta wq (escribe y sal)
  • g/match/d - Ex comando para eliminar líneas con dado match, Consulte: Poder de g

El ejemplo anterior es un método compatible con POSIX para la edición in situ de un archivo según este publicar en Unix.SE y Especificaciones POSIX para ex.


La diferencia con sed es eso:

sed es un Stren EDitor, no un editor de archivos.Preguntas frecuentes sobre Bash

A menos que disfrute del código no portátil, la sobrecarga de E / S y algunos otros efectos secundarios negativos. Básicamente, algunos parámetros (como en el lugar /-i) son extensiones de FreeBSD no estándar y pueden no estar disponibles en otros sistemas operativos.

Respondido el 15 de Septiembre de 18 a las 23:09

eso es genial ... cuando lo hago man ex me da el hombre para vim, Parece ex es parte de vim ... si entendí bien, eso significa que la sintaxis del patrón para match is vimregex.com que es similar pero diferente a los sabores POSIX y PCRE? - Anentrópico

:g is Compatible con POSIX comando con algunos Ligeras diferencias. Supongo que PCRE se basó en eso. - Kenorb

Estaba luchando con esto en Mac. Además, necesitaba hacerlo mediante el reemplazo de variables.

Entonces usé:

sed -i '' "/$pattern/d" $file

sin que importe $file es el archivo donde se necesita la eliminación y $pattern es el patrón que debe coincidir para la eliminación.

Elegí el '' de esto comentario.

Lo que hay que tener en cuenta aquí es el uso de doble comillas in "/$pattern/d". La variable no funcionará cuando usamos comillas simples.

Respondido el 15 de Septiembre de 18 a las 23:09

Mac sed requiere un parámetro después -i, por lo que si no desea una copia de seguridad, aún debe agregar una cadena vacía: -i '' - Wisbucky

Para uso en concha sed -i "/$pattern/d" $file . Gracias por su respuesta. - Ashwaq

También puedes usar esto:

 grep -v 'pattern' filename

Aquí -v imprimirá solo otro que no sea su patrón (eso significa coincidencia invertida).

Respondido el 15 de Septiembre de 18 a las 23:09

Hice una pequeña referencia con un archivo que contiene aproximadamente 345 000 líneas. El camino con grep parece ser unas 15 veces más rápido que el sed método en este caso.

He intentado con y sin la configuración LC_ALL = C, no parece cambiar los tiempos de manera significativa. La cadena de búsqueda (CDGA_00004.pdbqt.gz.tar) está en algún lugar en el medio del archivo.

Aquí están los comandos y los tiempos:

time sed -i "/CDGA_00004.pdbqt.gz.tar/d" /tmp/input.txt

real    0m0.711s
user    0m0.179s
sys     0m0.530s

time perl -ni -e 'print unless /CDGA_00004.pdbqt.gz.tar/' /tmp/input.txt

real    0m0.105s
user    0m0.088s
sys     0m0.016s

time (grep -v CDGA_00004.pdbqt.gz.tar /tmp/input.txt > /tmp/input.tmp; mv /tmp/input.tmp /tmp/input.txt )

real    0m0.046s
user    0m0.014s
sys     0m0.019s

respondido 19 mar '17, 12:03

¿En que plataforma Estas tu? ¿Qué versiones de sed / perl / grep usas? - hagello

La plataforma que utilizo es Linux (Gentoo). La versión sed es GNU sed v 4.2.2, la versión perl perl 5 (no puedo decir qué revisión usé en el momento de la prueba) y grep (GNU) es la versión 3.0. - Jadzia

Para obtener un resultado similar al in situ con grep Puedes hacerlo:

echo "$(grep -v "pattern" filename)" >filename

Respondido el 13 de junio de 15 a las 20:06

Esto solo es bueno para el bash concha o similar (no tcsh). - emisión

Respondido el 20 de Septiembre de 16 a las 14:09

perl -i    -nle'/regexp/||print' file1 file2 file3
perl -i.bk -nle'/regexp/||print' file1 file2 file3

El primer comando edita los archivos en su lugar (-i).

El segundo comando hace lo mismo pero mantiene una copia o copia de seguridad de los archivos originales agregando .bk a los nombres de los archivos (.bk se puede cambiar a cualquier cosa).

Respondido el 08 de enero de 18 a las 12:01

echo -e "/thing_to_delete\ndd\033:x\n" | vim file_to_edit.txt

Respondido el 17 de Septiembre de 16 a las 00:09

cat filename | grep -v "pattern" > filename.1
mv filename.1 filename

Respondido el 29 de junio de 18 a las 17:06

Está sobrescribiendo un archivo mientras aún está en uso. - Davor Cubránico

@DavorCubranic fijo - Andrei Izman

En caso de que alguien quiera hacerlo para coincidencias exactas de cadenas, puede usar el -w bandera en grep - w para todo. Es decir, por ejemplo si quieres borrar las líneas que tienen el número 11, pero mantén las líneas con el número 111:

-bash-4.1$ head file
1
11
111

-bash-4.1$ grep -v "11" file
1

-bash-4.1$ grep -w -v "11" file
1
111

También funciona con -f marque si desea excluir varios patrones exactos a la vez. Si "lista negra" es un archivo con varios patrones en cada línea que desea eliminar de "archivo":

grep -w -v -f blacklist file

Respondido el 15 de Septiembre de 18 a las 23:09

Un poco engañoso. -w, --word-regexp Select only those lines containing matches that form whole words. vs -x, --line-regexp Select only those matches that exactly match the whole line. For a regular expression pattern, this is like parenthesizing the pattern and then surrounding it with ^ and $. - Sai

También puede eliminar un rango de líneas en un archivo. Por ejemplo, para eliminar procedimientos almacenados en un archivo SQL.

sed '/CREATE PROCEDURE.*/,/END ;/d' sqllines.sql

Esto eliminará todas las líneas entre CREAR PROCEDIMIENTO y FIN;.

He limpiado muchos archivos sql con este comando sed.

Respondido el 02 de Septiembre de 20 a las 02:09

para mostrar el texto tratado en la consola

cat filename | sed '/text to remove/d' 

para guardar el texto tratado en un archivo

cat filename | sed '/text to remove/d' > newfile

para agregar información de texto tratado a un archivo existente

cat filename | sed '/text to remove/d' >> newfile

para tratar el texto ya tratado, en este caso eliminar más líneas de lo que se ha eliminado

cat filename | sed '/text to remove/d' | sed '/remove this too/d' | more

el | more mostrará el texto en trozos de una página a la vez.

Respondido 27 Feb 20, 20:02

Puedes usar el buen viejo ed para editar un archivo de forma similar a la respuesta que los usos ex. La gran diferencia en este caso es que ed toma sus comandos a través de la entrada estándar, no como argumentos de línea de comando como ex lata. Cuando se usa en un script, la forma habitual de adaptarse a esto es usar printf para canalizar comandos a él:

printf "%s\n" "g/pattern/d" w | ed -s filename

o con un heredoc:

ed -s filename <<EOF
g/pattern/d
w
EOF

respondido 19 mar '20, 14:03

Curiosamente, la respuesta aceptada no responde a la pregunta directamente. La pregunta se refiere al uso de sed para reemplazar un cadena, pero la respuesta parece presuponer el conocimiento de cómo convertir una cadena arbitraria en una expresiones regulares.

Muchas bibliotecas de lenguajes de programación tienen una función para realizar dicha transformación, p. Ej.

python: re.escape(STRING)
ruby: Regexp.escape(STRING)
java:  Pattern.quote(STRING)

Pero, ¿cómo hacerlo en la línea de comandos?

Dado que esta es una pregunta orientada a sed, un enfoque sería usar sed en sí:

sed 's/\([\[/({.*+^$?]\)/\\\1/g'

Entonces, dada una cadena arbitraria $ STRING, podríamos escribir algo como:

re=$(sed 's/\([\[({.*+^$?]\)/\\\1/g' <<< "$STRING")
sed "/$re/d" FILE

o como una sola línea:

 sed "/$(sed 's/\([\[/({.*+^$?]\)/\\\1/g' <<< "$STRING")/d" 

con variaciones como se describe en otra parte de esta página.

Respondido 23 Oct 20, 02:10

Eliminar líneas de todos los archivos que coincidan

grep -rl 'text_to_search' . | xargs sed -i '/text_to_search/d'

Respondido 26 Feb 21, 16:02

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.