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


Respuestas:


2760

Para eliminar la línea e imprimir la salida al 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

13
Gracias, pero no parece borrarlo del archivo, solo imprime el contenido del archivo de texto sin esa cadena.
Una naranja mecánica

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

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

99
@SiegeX Mejor aún, no aplique comandos como seda ningún archivo que no esté controlado por la versión.
MatrixFrog

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

631

Hay muchas otras formas de eliminar líneas con una cadena específica además de 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

44
¿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 tales líneas entre diferentes datos.
oortcloud_domicile

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

13
el sedejemplo tiene un comportamiento diferente, solo greps! Debería ser algo así sed -n -i '/pattern/!p' file.
caesarsol

8
La versión grep no funciona cuando cada línea coincide con el patrón. Mejor hacerlo: grep -v "pattern" file > temp; mv temp fileesto podría aplicarse a algunos de los otros ejemplos dependiendo del valor de retorno.
Chris Maes

1
"imprimir el inverso es más rápido que la eliminación real" - No en mi máquina (2012 MacBook Air, OS X 10.13.2). Crear el archivo: seq -f %f 10000000 >foo.txt. sed d: time sed -i '' '/6543210/d' foo.txtreal 0m9.294s. sed! p: time sed -i '' -n '/6543210/!p' foo.txtreal 0m13.671s. (Para archivos más pequeños, la diferencia es mayor.)
jcsahnwaldt dice GoFundMonica el

252

Puede usar sed para reemplazar las 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      

o

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

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


19
¡Vota tu respuesta también, solo porque intentaste una comparación de rendimiento!
anuragw

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

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

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

99
(usando ubuntu / usr / share / dict / words) grep y mv: 0.010s | sed en su lugar: 0.197s | sed y mv: 0.031s
ReactiveRaven

77

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

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

56
Un consejo útil para otras personas que tropiezan con este hilo de preguntas y respuestas y son nuevos en el script de shell: las opciones cortas están bien para usos únicos en la línea de comando, pero las opciones largas deberían preferirse en los scripts ya que son más legibles.
Dennis

3
+1 para la bandera - en el lugar. Necesito probar eso en archivos protegidos con permisos. (tener que hacer algún lavado de usuario.)
Bee Kay

8
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 la -ropció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 fue cuestionado?
ferreirabraga

38

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

ex +g/match/d -cwq file

dónde:

  • +se ejecuta dado el comando Ex ( man ex), igual que el -cque se ejecuta wq(escribir y salir)
  • g/match/d- Ex comando para eliminar líneas con dado match, ver: Poder de g

El ejemplo anterior es un método compatible con POSIX para editar in situ un archivo según esta publicación en las especificaciones exUnix.SE y POSIX para .


La diferencia con sedes que:

sedes un S TREAM ED itor, no un editor de archivos. BashFAQ

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


55
eso es genial ... cuando lo hago man exme da el hombre para vim, al parecer exes parte de vim ... si he entendido bien que mediante la sintaxis de patrón para matches vimregex.com que es similar pero diferente a los sabores POSIX y PCRE?
Anentropic

1
:g es un comando compatible con POSIX con algunas pequeñas diferencias . Supongo que PCRE se basó en ello.
kenorb

16

Estaba luchando con esto en Mac. Además, necesitaba hacerlo usando un reemplazo variable.

Entonces usé:

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

donde $filees el archivo donde se necesita la eliminación y $patternes el patrón que debe coincidir para la eliminación.

Elegí el ''de este comentario .

Lo que hay que tener en cuenta es el uso de comillas dobles en "/$pattern/d". La variable no funcionará cuando usemos comillas simples.


3
Mac sedrequiere 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 de conchas sed -i "/$pattern/d" $file. Gracias por su respuesta.
ashwaqar

14

Hice un pequeño punto de referencia con un archivo que contiene aproximadamente 345 000 líneas. El camino con grepparece ser alrededor de 15 veces más rápido que el sedmétodo en este caso.

He intentado con y sin la configuración LC_ALL = C, no parece cambiar los tiempos significativamente. 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

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

La plataforma que uso 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

14

También puedes usar esto:

 grep -v 'pattern' filename

Aquí -vse imprimirá solo que no sea su patrón (eso significa invertir coincidencia).


¿Cómo puedo eliminar líneas en un directorio que contiene una cadena específica
Namannimmo

13

Para obtener un resultado similar con grepusted, puede hacer esto:

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

44
Esto solo es bueno para el bashshell o similar (no tcsh).
esmit


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

El primer comando edita los archivos in situ (-i).

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


2

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


2

En caso de que alguien quiera hacerlo para coincidencias exactas de cadenas, puede usar la -wbandera en grep - w para todo. Es decir, por ejemplo, si desea eliminar las líneas que tienen el número 11, pero mantener 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 la -fbandera 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 del "archivo":

grep -w -v -f blacklist file

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


0

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, elimine más líneas de lo que se ha eliminado

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

el | moremostrará texto en fragmentos de una página a la vez.


0

Puede usar good old edpara editar un archivo de manera similar a la respuesta que usa ex. La gran diferencia en este caso es que edtoma sus comandos a través de una entrada estándar, no como argumentos de línea de comandos como expuede. Cuando se usa en un script, la forma habitual de acomodar esto es usar printfcomandos de canalización:

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

o con un heredoc:

ed -s filename <<EOF
g/pattern/d
w
EOF
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.