답변:
tac
첫 번째 일치 후 grep -m 1
(GNU 가정 grep
)를 사용 하여 grep
중지 한 경우에만 도움이됩니다 .
tac accounting.log | grep -m 1 foo
보낸 사람 man grep
:
-m NUM, --max-count=NUM
Stop reading a file after NUM matching lines.
귀하의 질문에, 모두의 예에서 tac
와 grep
사용하므로 전체 파일을 처리 할 필요 tac
종류 무의미하다.
따라서을 사용 grep -m
하지 않는 한 전혀 사용하지 말고 tac
출력을 구문 분석 grep
하여 마지막 일치 항목을 얻으십시오.
grep foo accounting.log | tail -n 1
또 다른 방법은 Perl 또는 다른 스크립트 언어를 사용하는 것입니다. 예를 들어 (where $pattern=foo
) :
perl -ne '$l=$_ if /foo/; END{print $l}' file
또는
awk '/foo/{k=$0}END{print k}' file
tac
. 제 요점은 -m
파일을 여전히 두 개의 프로그램으로 완전히 읽어야 하기 때문에 사용하지 않으면 도움이되지 않는다는 것 입니다. 그렇지 않으면, 당신은 모든 사건을 검색하고 내가 한 것처럼 마지막 사건 만 유지할 수 있습니다 tail -n 1
.
grep -m
매우 효율적이어야합니다.
grep -m
하면됩니다. OP는 사용하지 않았 -m
으므로 grep과 tac는 모든 것을 처리했습니다.
awk
선의 의미를 넓히 시겠습니까?
왜 그런지
tac file | grep foo | head -n 1
첫 번째 경기에서 멈추지 않는 것은 버퍼링 때문입니다.
일반적으로 head -n 1
줄을 읽은 후 종료합니다. 따라서 grep
SIGPIPE를 가져 와서 두 번째 줄을 쓰는 즉시 종료해야합니다.
그러나 결과는 출력이 터미널로 가지 않기 때문에 grep
버퍼링한다는 것입니다. 즉, 충분히 축적 될 때까지 작성하지 않습니다 (GNU grep을 사용한 테스트에서 4096 바이트).
즉 grep
, 8192 바이트의 데이터를 쓰기 전에는 종료되지 않으므로 아마도 몇 줄이 될 것입니다.
GNU grep
를 사용 --line-buffered
하면 터미널에 갔는지 여부에 관계없이 줄을 찾 자마자 작성하도록 지시하는을 사용하여 더 빨리 종료 할 수 있습니다 . 그래서 grep
다음 발견 한 두 번째 줄에 종료 것입니다.
그러나 grep
어쨌든 GNU 를 사용 -m 1
하면 @terdon이 보여준 것처럼 대신 사용할 수 있습니다 . 첫 번째 경기에서 나올 때 더 좋습니다.
your grep
가 GNU가 아닌 경우 또는 대신 grep
사용할 수 있습니다 . 그러나 는 GNU 명령되고, 난 당신이있는 시스템 찾을 수 있습니다 의심 곳 GNU되지 않습니다 .sed
awk
tac
tac
grep
grep
tac file | sed "/$pattern/!d;q" # BRE
tac file | P=$pattern awk '$0 ~ ENVIRON["P"] {print; exit}' # ERE
일부 시스템은 tail -r
GNU와 동일한 작업을 수행해야합니다 tac
.
일반 (찾을 수있는) 파일의 경우 파일을 뒤로 읽기 때문에 효율적 tac
이며 tail -r
파일을 뒤로 인쇄하기 전에 메모리에서 파일을 완전히 읽는 것이 아닙니다 ( @slm의 sed 방식 또는 tac
비정규 파일의 경우와 같이) .
사용 가능 하지 tac
않거나 tail -r
사용할 수 없는 시스템에서 유일한 옵션은 다음과 같은 프로그래밍 언어를 perl
사용 하여 수동으로 역독을 구현하는 것입니다.
grep -e "$pattern" file | tail -n1
또는:
sed "/$pattern/h;$!d;g" file
그러나 이는 모든 일치 항목을 찾고 마지막 일치 항목 만 인쇄하는 것을 의미합니다.
다음은 처음부터 패턴이 처음 발생한 위치를 찾는 가능한 솔루션입니다.
tac -s "$pattern" -r accounting.log | head -n 1
이것은 다음과 같은 스위치 -s
와 -r
스위치를 사용 tac
합니다.
-s, --separator=STRING
use STRING as the separator instead of newline
-r, --regex
interpret the separator as a regular expression
다음을 사용하여 @Terdon의 훌륭한 답변에 대한 대체 방법을 보여줍니다sed
.
$ sed '1!G;h;$!d' file | grep -m 1 $pattern
$ sed -n '1!G;h;$p' file | grep -m 1 $pattern
$ seq 10 > file
$ sed '1!G;h;$!d' file | grep -m 1 5
5
$ sed -n '1!G;h;$p' file | grep -m 1 5
5
보너스로 여기 Perl에서 조금 더 기억하기 쉬운 표기법이 있습니다 :
$ perl -e 'print reverse <>' file | grep -m 1 $pattern
$ perl -e 'print reverse <>' file | grep -m 1 5
5
sed
하나) grep 5 | tail -n1
또는 보다 몇 배나 느릴 것 sed '/5/h;$!d;g'
입니다. 또한 잠재적으로 많은 메모리를 사용합니다. 아직 GNU를 사용하고 있기 때문에 이식성이 떨어 grep -m
집니다.