파일에서 문자열을 찾고 싶지만 후행 줄 바꿈으로 끝나지 않는 줄의 일치 항목을 무시합니다. 즉, 파일의 마지막 줄이 줄바꿈으로 끝나지 않으면 무시하고 싶습니다.
이를 수행하는 가장 좋은 방법은 무엇입니까?
subprocess
처리하기 전에 큰 텍스트 로그 파일을 필터링하기 위해 모듈을 통해 grep을 호출하는 Python 스크립트에서 이 문제가 발생했습니다 . 파일의 마지막 줄이 기록되는 중일 수 있으며, 이 경우 해당 줄을 처리하고 싶지 않습니다.
답변1
사용 gawk
(ERE와 같은 것을 사용 grep -E
):
gawk '/pattern/ && RT' file
RT
in에는 gawk
레코드 구분 기호와 일치하는 콘텐츠가 포함되어 있습니다. RS
기본값 RS
( \n
)을 사용하면 \n
구분되지 않은 마지막 레코드를 제외하고 레코드 RT
는 비어 있습니다 .
사용 perl
(사용 가능한 것과 유사한 Perl RE grep -P
):
perl -ne 'print if /pattern/ && /\n\z/'
gawk
grep
또는 와 달리 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/'
.