파일에서 6 자 미만의 모든 줄을 어떻게 제거합니까?


17

약 1000 만 줄의 파일이 있습니다.

파일에서 6 자 미만의 모든 줄을 제거하고 싶습니다.

어떻게해야합니까?


이 질문이 Stackoverflow에 더 적합하지 않습니까?
user1073075

2
@ user1073075는 여기에 완벽하게 주제입니다.
세스

답변:


30

이를 수행하는 방법에는 여러 가지가 있습니다.

사용 grep:

grep -E '^.{6,}$' file.txt >out.txt

이제 out.txt6 자 이상의 문자가있는 줄이 포함됩니다.

반대 방향 :

grep -vE '^.{,5}$' file.txt >out.txt

를 사용하여 sed길이가 5 이하인 줄을 제거합니다.

sed -r '/^.{,5}$/d' file.txt

길이가 6 이상인 라인 인쇄 :

sed -nr '/^.{6,}$/p' file.txt 

>연산자와 같은 연산자를 사용하여 출력을 다른 파일로 저장 grep하거나 다음 -i옵션을 사용하여 파일을 제자리에서 편집 할 수 있습니다 sed.

sed -ri.bak '/^.{6,}$/' file.txt 

원본 파일은 그대로 백업되고 file.txt.bak수정 된 파일은입니다 file.txt.

백업을 유지하지 않으려면 다음을 수행하십시오.

sed -ri '/^.{6,}$/' file.txt

shell, Slower, Do not do을 사용하면 다른 방법을 보여주기위한 것입니다.

while IFS= read -r line; do [ "${#line}" -ge 6 ] && echo "$line"; done <file.txt

사용 python, 심지어 느린보다 grep, sed:

#!/usr/bin/env python2
with open('file.txt') as f:
    for line in f:
        if len(line.rstrip('\n')) >= 6:
            print line.rstrip('\n')

파이썬을 더 잘 사용하기 위해 목록 이해력을 향상시키는 것이 좋습니다.

#!/usr/bin/env python2
with open('file.txt') as f:
     strip = str.rstrip
     print '\n'.join([line for line in f if len(strip(line, '\n')) >= 6]).rstrip('\n')

예이! 나는 파이썬 답변을 기대하고 있었다 =)
TellMeWhy

@DevRobot 내가 본 .. 그런 다음 내가 추가 한 목록 이해, 더 파이썬적인 것 ..
heemayl

1
또한 @DevRobot은 첫 번째 옵션을 사용할 때 큰 파일에서 파이썬이 느리다는 것을 확신하지 못합니다. 실제로 파이썬은 줄 당 읽기 때문에 수백만 줄에서 더 빠릅니다.
Jacob Vlijm

1
두 번째 파이썬 예제는 결합을 수행하기 전에 전체 파일을 메모리로 읽습니다. 이 경우 첫 번째 파이썬 예제가 더 좋다고 생각합니다.
Holloway

파일이 그런 식으로 구성되어 있지 않기 때문에 줄 단위로 읽는 속도가 느려집니다. 어쨌든 블록을 미리 읽고 병렬화 가능성이 줄어든 줄 바꿈을 찾은 다음 부분 문자열 만 반환해야합니다. 순환 버퍼가 필요합니다. 줄 길이를 모르는 경우 메모리를 동적으로 할당해야합니다.
Vee

19

매우 간단합니다.

grep ...... inputfile > resultfile   #There are 6 dots

이 같은 매우 효율적이다 grep가 필요한 것보다 더 많은 구문 분석하려고하지 않으며, 어떠한 방법으로 문자를 해석 : 그것은 단순히 표준 출력 (전체) 선 (쉘이 다음 resultfile로 리디렉션하는) 보내 빨리으로 이 6 보았다 해당 줄의 문자 ( .regexp 컨텍스트에서 1 문자와 일치).

따라서 grep은 6 개 이상의 문자가있는 행만 출력하고 다른 문자는 grep에 의해 출력되지 않으므로 결과 파일로 만들지 않습니다.


14

해결 방법 # 1 : C 사용

가장 빠른 방법 :이 C 프로그램을 컴파일하고 실행하십시오.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_BUFFER_SIZE 1000000

int main(int argc, char *argv[]) {
    int length;

    if(argc == 3)
        length = atoi(argv[2]);
    else
        return 1;

    FILE *file = fopen(argv[1], "r");

    if(file != NULL) {
        char line[MAX_BUFFER_SIZE];

        while(fgets(line, sizeof line, file) != NULL) {
            char *pos;

            if((pos = strchr(line, '\n')) != NULL)
                *pos = '\0';
            if(strlen(line) >= length)
                printf("%s\n", line);
        }

        fclose(file);
    }
    else {
        perror(argv[1]);
        return 1;
    }

    return 0;
}

로 컴파일하고 gcc program.c -o program실행하십시오 ./program file line_length(여기서 file= 파일 경로 및 line_length= 최소 줄 길이 6; 최대 줄 길이는 1000000줄 당 문자 로 제한됩니다 MAX_BUFFER_SIZE. 값을 변경하여이를 변경할 수 있습니다 ).

(대신에 속임수 \n\0발견 여기에 .)

쉘 솔루션을 제외하고이 질문에 제안 된 다른 모든 솔루션과 비교 (테스트는 평균 길이가 8자인 10M 줄의 ~ 91MB 파일에서 실행) :

time ./foo file 6

real    0m1.592s
user    0m0.712s
sys 0m0.160s

time grep ...... file

real    0m1.945s
user    0m0.912s
sys 0m0.176s

time grep -E '^.{6,}$'

real    0m2.178s
user    0m1.124s
sys 0m0.152s

time awk 'length>=6' file

real    0m2.261s
user    0m1.228s
sys 0m0.160s

time perl -lne 'length>=6&&print' file

real    0m4.252s
user    0m3.220s
sys 0m0.164s

sed -r '/^.{,5}$/d' file >out

real    0m7.947s
user    0m7.064s
sys 0m0.120s

./script.py >out
real    0m8.154s
user    0m7.184s
sys 0m0.164s

해결 방법 # 2 : AWK 사용 :

awk 'length>=6' file
  • length>=6: length>=6TRUE를 반환하면 현재 레코드를 인쇄합니다.

솔루션 # 3 : Perl 사용 :

perl -lne 'length>=6&&print' file
  • 경우 lenght>=6반환 TRUE, 현재 레코드를 인쇄합니다.

% cat file
a
bb
ccc
dddd
eeeee
ffffff
ggggggg
% ./foo file 6
ffffff
ggggggg
% awk 'length>=6' file   
ffffff
ggggggg
% perl -lne 'length>=6&&print' file
ffffff
ggggggg

1
awk
나를

2
@heemayl 그리고 나는 즉시 질문을 보지 못했기 때문에 온라인 상태가되면 더 빠를 것임을 알았습니다 . 내 sed솔루션 을 삭제 해야했습니다 (알고 있습니다). XD
kos

pos변수 의 요점은 무엇입니까 ? line줄 바꿈 문자로 문자에 대한 포인터를 반환 하지만 결코 사용하지 않는 것 같습니다. 그리고 그것을 찾지 못하면 그냥 동일하게 설정하십시오 \0.
user1717828

@ user1717828 나는 경우 찾을 그것은 내가로 교체 \0( strchr()리턴 문자가있는 경우 NULL 포인터 되지 있음). 요점은 각 줄의 끝에서 각 줄 바꿈을 바꾸어 \0줄 바꿈이 계산되지 strlen()않도록하는 것입니다. 이는 마지막 줄에서 줄 바꿈 가능성에 관계없이 길이를 항상 6과 비교할 수 있도록하는 것입니다. 마지막 줄만 다르게 처리하는 것이 훨씬 효율적일 것입니다. 아마 이것을 나중에 업데이트 할 것입니다.
kos

1
@tripleee 아이디어는 일회성 작업 이상의 파일이나 더 큰 파일에 유용한 솔루션을 추가하는 것이 었지만grep 동일한 파일 에서 솔루션을 테스트했으며 실제로 더 빠릅니다 (아마도 strlen()최고의 아이디어가 아니기 때문에 ) . getchar()대신 첫 번째 N 문자 만 확인하기 위해 루프 를 사용하려고합니다 . 눈에 띄게 개선해야한다고 생각합니다. 그리고 그렇습니다. 버퍼 길이의 모든 선은 단순히 버퍼 길이로 잘립니다.
kos

2

Ex 모드에서 Vim을 사용할 수 있습니다 :

ex -sc 'v/\v.{6}/d' -cx file
  1. \v 마술을 켜다

  2. .{6} 6 자 이상의 줄을 찾으십시오

  3. v 반전 선택

  4. d 지우다

  5. x 저장하고 닫습니다


1

루비 솔루션 :

$ cat input.txt                                                                                                          
abcdef
abc
abcdefghijk

$ ruby -ne 'puts $_ if $_.chomp.length() >= 6 ' < input.txt                                                              
abcdef
abcdefghijk

간단한 아이디어 : 루비의 stdin으로 파일을 리디렉션하고 길이가 6 이상인 경우에만 stdin에서 줄을 인쇄하십시오.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.