vacias una ultimas reemplazar quitar que por lineas linea empiezan eliminar con caracter borrar archivo bash scripting sh

bash - una - Eliminar líneas de un archivo que están en otro archivo



sed linux (8)

Tengo un archivo f1 :

line1 line2 line3 line4 .. ..

Quiero eliminar todas las líneas que están en otro archivo f2 :

line2 line8 .. ..

Intenté algo con cat y sed , que ni siquiera estaba cerca de lo que pretendía. ¿Cómo puedo hacer esto?


¿Has probado esto con sed?

sed ''s#^#sed -i ''"''"''s%#g'' f2 > f2.sh sed -i ''s#$#%%g''"''"'' f1#g'' f2.sh sed -i ''1i#!/bin/bash'' f2.sh sh f2.sh


Algunas comparaciones de tiempo entre varias otras respuestas:

$ for n in {1..10000}; do echo $RANDOM; done > f1 $ for n in {1..10000}; do echo $RANDOM; done > f2 $ time comm -23 <(sort f1) <(sort f2) > /dev/null real 0m0.019s user 0m0.023s sys 0m0.012s $ time ruby -e ''puts File.readlines("f1") - File.readlines("f2")'' > /dev/null real 0m0.026s user 0m0.018s sys 0m0.007s $ time grep -xvf f2 f1 > /dev/null real 0m43.197s user 0m43.155s sys 0m0.040s

sort f1 f2 | uniq -u sort f1 f2 | uniq -u ni siquiera es una diferencia simétrica, ya que elimina las líneas que aparecen varias veces en cualquier archivo.

comm también se puede usar con stdin y aquí strings:

echo $''a/nb'' | comm -23 <(sort) <(sort <<< $''c/nb'') # a


Para excluir archivos que no son demasiado grandes, puede usar las matrices asociativas de AWK.

awk ''NR == FNR { list[tolower($0)]=1; next } { if (! list[tolower($0)]) print }'' exclude-these.txt from-this.txt

La salida estará en el mismo orden que el archivo "from-this.txt". La tolower() hace insensible a las mayúsculas y minúsculas, si lo necesita.

La complejidad algorítmica probablemente será O (n) (exclude-these.txt size) + O (n) (from-this.txt size)


Parece ser un trabajo adecuado para el shell SQLite:

create table file1(line text); create index if1 on file1(line ASC); create table file2(line text); create index if2 on file2(line ASC); -- comment: if you have | in your files then specify “ .separator ××any_improbable_string×× ” .import ''file1.txt'' file1 .import ''file2.txt'' file2 .output result.txt select * from file2 where line not in (select line from file1); .q


Pruebe con Comm en su lugar (suponiendo que f1 y f2 están "ya ordenados")

comm -2 -3 f1 f2


Similar a la respuesta de Dennis Williamson (principalmente cambios sintácticos, por ejemplo, estableciendo el número de archivo explícitamente en lugar del truco NR == FNR ):

awk ''{if (f==1) { r[$0] } else if (! ($0 in r)) { print $0 } } '' f=1 exclude-these.txt f=2 from-this.txt

Al acceder r[$0] crea la entrada para esa línea, no es necesario establecer un valor.

Suponiendo que awk usa una tabla hash con búsqueda constante y (en promedio) tiempo de actualización constante, la complejidad temporal de esto será O (n + m), donde n y m son las longitudes de los archivos. En mi caso, n fue ~ 25 millones y m ~ 14000. La solución awk fue mucho más rápida que la ordenada, y también preferí mantener el orden original.


si tienes Ruby (1.9+)

#!/usr/bin/env ruby b=File.read("file2").split open("file1").each do |x| x.chomp! puts x if !b.include?(x) end

Que tiene una complejidad O (N ^ 2). Si quieres preocuparte por el rendimiento, aquí hay otra versión

b=File.read("file2").split a=File.read("file1").split (a-b).each {|x| puts x}

que usa un hash para efectuar la resta, también lo es la complejidad O (n) (tamaño de a) + O (n) (tamaño de b)

Aquí hay un pequeño punto de referencia, cortesía de user576875, pero con 100K líneas, de lo anterior:

$ for i in $(seq 1 100000); do echo "$i"; done|sort --random-sort > file1 $ for i in $(seq 1 2 100000); do echo "$i"; done|sort --random-sort > file2 $ time ruby test.rb > ruby.test real 0m0.639s user 0m0.554s sys 0m0.021s $time sort file1 file2|uniq -u > sort.test real 0m2.311s user 0m1.959s sys 0m0.040s $ diff <(sort -n ruby.test) <(sort -n sort.test) $

diff se usó para mostrar que no hay diferencias entre los 2 archivos generados.


grep -v -x -f f2 f1 debería hacer el truco.

Explicación:

  • -v para seleccionar líneas que no coinciden
  • -x para -x solo líneas enteras
  • -f f2 para obtener patrones de f2

En su lugar, puede usar -F f2 para -F f2 cadenas fijas de f2 lugar de patrones (en caso de que desee eliminar las líneas de una manera "lo que ve si obtiene lo que obtiene" en lugar de tratar las líneas en f2 como patrones de expresiones regulares).