grep이 줄 바꿈 없이 줄을 무시하도록 만드는 방법

grep이 줄 바꿈 없이 줄을 무시하도록 만드는 방법

파일에서 문자열을 찾고 싶지만 후행 줄 바꿈으로 끝나지 않는 줄의 일치 항목을 무시합니다. 즉, 파일의 마지막 줄이 줄바꿈으로 끝나지 않으면 무시하고 싶습니다.

이를 수행하는 가장 좋은 방법은 무엇입니까?

subprocess처리하기 전에 큰 텍스트 로그 파일을 필터링하기 위해 모듈을 통해 grep을 호출하는 Python 스크립트에서 이 문제가 발생했습니다 . 파일의 마지막 줄이 기록되는 중일 수 있으며, 이 경우 해당 줄을 처리하고 싶지 않습니다.

답변1

사용 gawk(ERE와 같은 것을 사용 grep -E):

gawk '/pattern/ && RT' file

RTin에는 gawk레코드 구분 기호와 일치하는 콘텐츠가 포함되어 있습니다. RS기본값 RS( \n)을 사용하면 \n구분되지 않은 마지막 레코드를 제외하고 레코드 RT는 비어 있습니다 .

사용 perl(사용 가능한 것과 유사한 Perl RE grep -P):

perl -ne 'print if /pattern/ && /\n\z/'

gawkgrep또는 와 달리 perl기본값은 문자가 아닌 바이트에 적용됩니다. 예를 들어 .정규식 연산자는 UTF-8로 인코딩된 2바이트 각각과 일치합니다 £. 로케일의 문자 정의(예: awk/ ) 에 따라 문자를 처리하려면 다음을 grep사용할 수 있습니다.

perl -Mopen=locale -ne 'print if /pattern/ && /\n\z/'

답변2

grep분명히한정된개행 문자는 무시되므로 실제로 사용할 수 없습니다. sed현재 줄(조각)이 줄 바꿈으로 끝나는지 여부를 내부적으로 알고 있지만 해당 정보를 공개하도록 강제하는 방법은 알 수 없습니다. awk개행 문자( RS)로 레코드를 구분하지만 개행 문자가 있는지 여부는 실제로 상관하지 않습니다. 기본 동작은 모든 경우 끝에 개행 문자( )를 인쇄하는 것입니다 print.ORS

따라서 일반적인 도구는 여기서는 큰 도움이 되지 않는 것 같습니다.

그러나 sed마지막 줄에서 작업하는 시기를 알고 있으므로 마지막 줄의 일부를 보지 않고 마지막 전체 줄을 잃어도 괜찮다면 sed마지막 줄이라고 생각되는 것을 삭제할 수 있습니다. 예를 들어

sed -n -e '$d' -e '/pattern/p'  < somefile                   # or
< somefile sed '$d' | grep ...

그것이 선택 사항이 아니라면 항상 Perl이 있습니다. 이렇게 하면 /pattern/끝에 개행 문자가 포함된 일치하는 행만 인쇄됩니다 .

perl -ne 'print if /pattern/ && /\n$/'

답변3

다음과 같은 작업이 수행됩니다.

#!/usr/bin/env sh

if [ "$(tail -c 1 FILE)" = "" ]
then
    printf "Trailing newline found\n"
    # grep whole file
    # grep ....
else
    printf "No trailing newline found\n"
    # ignore last line
    # head -n -1 FILE | grep ...
fi

우리는 아래에 설명된 명령 대체 기능을 사용합니다 man bash.

Bash는 명령을 실행하고 명령 대체를 명령의 표준 출력으로 대체하여 확장을 수행합니다.무엇이든 후행 줄 바꿈을 제거하십시오.

답변4

속도가 필요한 경우 C에서 PCRE(또는 다른 더 빠른 정규식 라이브러리)를 사용하면 정규식을 사용하고 줄 바꿈을 확인할 수 있습니다. 단점: 새로운 코드를 유지 관리하고 디버깅해야 하며, 부분을 다시 구현하는 데 걸리는 시간은 표현식의 복잡성이나 이와 같은 기능의 사용 여부에 따라 달라질 grep수 있습니다 .perl--only-matching

#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <pcre.h>
#define MAX_OFFSET 3

int main(int argc, char *argv[])
{
    // getline
    char *line = NULL;
    size_t linebuflen = 0;
    ssize_t numchars;
    // PCRE
    const char *error;
    int erroffset, rc;
    int offsets[MAX_OFFSET];
    pcre *re;

    if (argc < 2) errx(1, "need regex");
    argv++;
    if ((re = pcre_compile(*argv, 0, &error, &erroffset, NULL)) == NULL)
        err(1, "pcre_compile failed at offset %d: %s", erroffset, error);

    while ((numchars = getline(&line, &linebuflen, stdin)) > 0) {
        if (line[numchars-1] != '\n') break;
        rc = pcre_exec(re, NULL, line, numchars, 0, 0, offsets, MAX_OFFSET);
        if (rc > 0) fwrite(line, numchars, 1, stdout);
    }
    exit(EXIT_SUCCESS);
}

이것은 perl -ne 'print if /.../ && /\n\z/'.

관련 정보