D를 제외한 모든 줄 삭제

D를 제외한 모든 줄 삭제

다음과 같은 세부 정보가 포함된 세 개의 큰 파일이 있는 장면이 있습니다 Test.txt.Test1.txtTest2.txt

H|||||||||||||||||||||||
D||||||||||||||||||||||||
D|||||||||||||||||||||||
H|||||||||||||||||||||
D||||||||||||||||||||||||
D||||||||||||||||||||||||
T||||||||||||||||||||||||

D라인을 제외한 모든 항목을 삭제해야 합니다. 내 파일 세 개 모두에서 다음과 같이 보일 것입니다. (10GB 이상)

D||||||||||||||||||||||||
D|||||||||||||||||||||||
D||||||||||||||||||||||||
D||||||||||||||||||||||||

Test.txt따라서 , Test2.txt, 및 에서 D 줄만 유지한 후 Test3.txt새 파일로 병합해야 합니다.

나는 sed를 사용하여 위의 작업을 수행했습니다.

sed '/^\('D'\)|/!d' $Filename.txt >>  $NewFilename.txt

하지만 파일이 크기 때문에 시간이 오래 걸립니다.

이를 효율적으로 수행하기 위해 사용할 수 있는 다른 명령이 있습니까?

답변1

cat Test.txt Test2.txt Test3.txt | LC_ALL=C grep '^D' > newfile.txt

또는:

for file in Test.txt Test2.txt Test3.txt; do
  LC_ALL=C grep '^D' < "$file"
done > newfile.txt

또는 grep선호하는 GNU가 grep해당 -h옵션을 지원하는 경우(파일 이름 인쇄를 피하기 위해):

LC_ALL=C grep -h '^D' Test.txt Test2.txt Test3.txt > newfile.txt

이를 사용하면 UTF-8 데이터 구문 분석을 피할 LC_ALL=C수 있습니다 . grep를 사용하면 ^Dgrep줄의 첫 번째 문자만 표시됩니다. grep, 특히 grepGNU는 일반적으로 sed.

답변2

이는 CPU 바인딩이 아닌 I/O 바인딩 작업일 가능성이 높으므로 다음과 같은 정규식 엔진을 사용하지 않더라도 다음과 같습니다.

grep -F 'D|' Test.txt Test2.txt Test3.txt

파일을 선으로 표시한 후 패턴을 검색해야 하기 때문에 시간이 오래 걸립니다.

이것이 일회성이고 인코딩에 신경 쓰지 않는다면 mmap(3)전체 파일을 메모리에 넣고 다음을 사용할 수 있습니다 memmem(3).

char *p;
if ((p = memmem(file, size, "\nD|", 3)) != NULL) {
        /* massage the line, i.e. find the next '\n'
         * and print the region between p+1 and the
         * next '\n' */
}

어디에 file매핑된 버퍼에 대한 포인터이고 size파일 크기입니다. (도움이 된다면 자세히 설명해 드리겠습니다.)

이 접근 방식은 여전히 ​​시간이 좀 걸리지만(문제가 I/O 바인딩되어 있기 때문에) 최소한 파일을 행으로 표시하는 시간을 절약할 수 있습니다.

관련 정보