IT

한 파일에서 다른 파일에있는 행 삭제

lottoking 2020. 7. 20. 07:17
반응형

한 파일에서 다른 파일에있는 행 삭제


파일이 있습니다 f1.

line1
line2
line3
line4
..
..

다른 파일에있는 모든 줄을 삭제하고 싶습니다 f2.

line2
line8
..
..

나는 cat및로 시도를 시도했는데 sed, 의도했던 것과 동일한 것입니다. 어떻게해야합니까?


grep -v -x -f f2 f1 트릭을해야합니다.

설명 :

  • -v 일치하지 않는 줄을 선택하려는 경우
  • -x 전체 줄에만 일치
  • -f f2 패턴을 소유 위해 f2

대신 패턴 대신 고정 문자열사용 grep -F하거나 fgrep일치 여부 시킬 수 있습니다 (줄 을 정규식 패턴으로 처리하지 않고 "있는 경우 표시되는 방식"으로 줄을 제거하려는 경우 ).f2f2


대신 통신을 시도하십시오 (f1과 f2가 "이미 정렬되어 가정")

comm -2 -3 f1 f2

너무 크지 않은 파일을 제외하고 AWK의 연관 배열을 사용할 수 있습니다.

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

"from-this.txt"파일과 순서로 출력됩니다. tolower()당신이 필요한 경우 기능, 그것은 대소 문자를 구분합니다.

알고리즘 복잡도는 아마도 O (n) (exclude-these.txt 크기) + O (n) (from-this.txt 크기)입니다.


Dennis Williamson의 답변과 유사합니다 (주로 구문 대신 파일 번호를 명시 적으로 설정하는 구문 변경 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

액세스 r[$0]하면 해당 행에 대한 항목이 작성 항목에 대한 항목이 없습니다.

awk가 설치와 (평균) 업데이트 시간을 가진 해시 테이블을 사용하는 가정하면, 이것의 시간 복잡도는 O (n + m)이며, 여기서 n과 m 은의 길이입니다. 필자의 경우 n은 ~ 2500 만 및 m ~ 14000이었습니다. awk 솔루션은 훨씬 더 빠르며 원래 순서를 유지하는 것이 좋습니다.


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

어느 것이 O (N ^ 2)를 사용하여 실행합니다. 성능에 관심이 있으시면 다른 버전이 있습니다.

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

해시를 사용하여 빼기에 영향을 미치기 때문에 O (n) (a의 크기) + O (n) (b의 크기)

여기에 사용자 576875의 호의가있는 위의 100K 라인이있는 작은 벤치 마크가 있습니다.

$ 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 생성 된 2 개의 파일간에 차이가 없음을 표시하는 데 사용됩니다.


다양한 다른 답변 사이의 타이밍 비교 :

$ 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 두 파일에 여러 번 줄을 제거하기 때문에 대칭적인 차이조차 없습니다.

comm은 stdin 및 여기 문자열과 함께 사용할 수도 있습니다.

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

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

당신은 시도해 봤어 나오지도 함께?

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

참고 URL : https://stackoverflow.com/questions/4780203/deleting-lines-from-one-file-which-are-in-another-file

반응형