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

1789

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

Una Naranja Mecánica
fuente

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
SiegeX
fuente
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
Kurumi
fuente
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.

slashdottir
fuente
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
Kevin Nguyen
fuente
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.

kenorb
fuente
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.

Aniket Sinha
fuente
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
Jadzia
fuente
¿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).

Bhuvanesh
fuente
¿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
Jahid
fuente
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).

Kjetil S.
fuente
2

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

Shizzmo
fuente
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
FatihSarigol
fuente
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
1
cat filename | grep -v "pattern" > filename.1
mv filename.1 filename
Andrey Izman
fuente
Está sobrescribiendo un archivo mientras todavía está en uso.
Davor Cubranic
@DavorCubranic arreglado
Andrey Izman
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.

nassim
fuente
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
Shawn
fuente