여러 파일에서 마지막으로 나타나는 문자열 찾기


9

문자열의 마지막 항목을 찾으려면 여러 로그 파일 (지난 24 시간 동안 생성 된 모든 파일을 모두 동일한 디렉토리에 유지)을 검색해야합니다. 이것은 내가 쓴 명령입니다.

find . -mtime 1 | grep fileprefix | xargs grep 'search string' | tail -1

그러나 이것은 하나의 파일에 대한 마지막 줄만 반환합니다. 모든 라인을 얻기 위해 이것을 조정하는 방법에 대한 제안?


꼬리와 마지막 grep을 뒤집으려고 했습니까? 찾기 . mtime 1 | grep 파일 접두사 | xargs tail -1 | grep '검색 문자열'
Mathieu

답변:


4

GNU 기능을 가정 :

find . -mtime -1 -exec bash -c \
'for f; do tac "$f" | grep -m1 fileprefix; done' _ {} +

이미 bash 쉘을 사용하고 있으므로 'bash -c \'의 목적을 정교하게 설명해 주시겠습니까? 또한 마지막에 '_ {} +'의 목적.
Lokesh

@Lokesh,을 find사용하여 파일에서 명령을 실행할 수 있습니다 -exec. 와 bash -c, 우리가 산란하고 bash파일을 통해 루프에 의해 발견 쉘을 find실행한다 tac .. | grep -m1 fileprefix
iruvar

cut 명령을 포함하여 for 루프에서 문자열 필터링을 확장하려고했습니다. 전술 "$ f"| grep -m1 파일 접두사 | cut -d ''-f4,7-8 그러나 순간 cut 명령을 넣으면 예기치 않은 파일 끝 오류가 발생합니다. 내가 뭘 잘못하고 있는지 제안 해 주시겠습니까?
Lokesh

@lokesh, -d" "cut과 함께 사용하십시오 . 작은 따옴표 대신 큰 따옴표
iruvar

1
find명령은 파일 접두사를 필터링 할 수 있습니다. 은 grep그 필요하지 않아야합니다. 검색 문자열이이 답변에 표시되지 않는다는 것도 놀라운 일입니다.
Jonathan Leffler

8

모든 것이 단일 디렉토리에있는 경우 다음을 수행 할 수 있습니다.

for file in *fileprefix*; do
    grep 'search string' "$file" | tail -1
done

이러한 파일이 큰 파일 인 경우 tac파일을 역순으로 인쇄하고 (마지막 마지막 줄) grep -m1첫 번째 항목과 일치 시켜서 속도를 높이는 것이 좋습니다. 그렇게하면 전체 파일을 읽을 필요가 없습니다.

for file in *fileprefix*; do
    tac file | grep -m1 'search string'
done

둘 다 일치하는 디렉토리가 없다고 가정 fileprefix합니다. 있는 경우 무시할 수있는 오류가 발생합니다. 문제가있는 경우 파일 만 확인하십시오.

 for file in *fileprefix*; do
    [ -f "$file" ] && tac file | grep -m1 'search string'
 done

파일 이름도 인쇄해야 할 경우 -Hgrep호출에 추가하십시오 . 또는 grep지원하지 않는 경우을 통해 검색하도록 지시하십시오 /dev/null. 출력은 변경되지 않지만 grep여러 파일이 제공되므로 각 적중마다 항상 파일 이름을 인쇄합니다.

for file in *fileprefix*; do
    grep 'search string' "$file" /dev/null | tail -1
done

“그러면 전체 파일을 읽을 필요가 없습니다”— 어? 아니요, grep에서 전체 파일을 읽는 것을 피하지만 대신 전체 파일을 tac을 통해 넣습니다. 일치하는 것이 파일의 시작 또는 끝 부분에 있는지 여부에 따라 다르지만 더 빠를 것이라는 것은 분명하지 않습니다.
Gilles 'SO- 악의를 멈춰라'

@Gilles 아니오, 전체 파일을 넣지 않습니다 tac. 첫 번째 경기가 발견되는 즉시 종료됩니다. 방금 832M 텍스트 파일과 마지막 줄에서 찾은 패턴으로 테스트했습니다. grep -m 1 pattern file도구 ~ 7 초 tac file | grep -m1 pattern소요 0.009.
terdon

4
find . ! -name . -prune -mtime 1 -name 'fileprefix*' \
     -exec sed -se'/searchstring/h;$!d;x' {} +

... eparate files 옵션과 POSIX sed를 지원하는 GNU 가 있는 경우 작동합니다 .-sfind

디렉토리를 읽으려고 시도해도 유용하지 않으므로 일반 파일로 범위를 좁 히면 파이프 또는 직렬 장치 파일에서 읽기가 중단되는 것을 피할 수 있기 때문에 ! -type d또는 -type f한정자를 추가해야 합니다.

논리는 매우 간단 sed합니다. h이전 공간을 일치하는 입력 행의 복사본으로 덮어 쓴 searchstring다음 d모든 입력 행의 출력에서 ​​각 입력 파일의 마지막 행 을 생략합니다. 마지막 행에 도달하면 x보류 및 패턴 공간이 변경되므로 searchstring파일을 읽는 동안 발견 된 경우 마지막으로 발생한 항목이 출력되도록 자동 인쇄되고, 그렇지 않으면 빈 행을 씁니다. ( 원치 않는 경우 스크립트 /./!d의 꼬리 부분에 추가하십시오 sed) .

이것은 sed약 65k 입력 파일마다 또는 ARG_MAX한도에 관계없이 단일 호출 을 수행합니다 . 이것은 매우 성능이 뛰어난 솔루션이어야하며 매우 간단하게 구현됩니다.

최신 GNU가 주어지면 파일 이름을 원한다면 명령을 사용하여 파일 sed을 별도의 줄에 작성 F하거나 find배치 -print후 별도의 목록으로 인쇄 할 수 있습니다 +.


1

어때요 :

find . -mtime -1 -name "fileprefix*" -exec sh -c \
'echo "$(grep 'search string' $1 | tail -n 1),$1"' _ {} \;

위의 내용은 각 파일에서 마지막으로 나타나는 검색 문자열과 쉼표 뒤에 각각의 파일 이름이 나오는 멋진 결과를 제공합니다 (에코 아래에서 ", $ 1"부분을 수정하여 포맷을 변경하거나 필요없는 경우 제거). 접두사가 "file"인 파일에서 '10'검색 문자열을 검색하는 샘플 출력은 다음과 같습니다.

[dmitry@localhost sourceDir]$ find . -mtime -1 -name "file*" -exec  sh -c 'echo "$(grep '10' $1 | tail -n 1),$1"' _ {} \;
Another data 02 10,./file02.log
Some data 01 10,./file01.log
Yet another data 03 10,./file03.log 

1
find . -mtime 1 -name 'fileprefix*' -exec grep -Hn 'search string' {} + |
    sort -t: -k1,2 -n | 
    awk -F: '{key=$1 ; $1="" ; $2="" ; gsub(/^  /,"",$0); a[key]=$0} 
             END {for (key in a) { print key ":" a[key] }}'

이것은 GNU 사용 grep-H-n항상 파일 이름과 모든 일치의 LINENUMBER 모두를 인쇄하려면 옵션을, 다음은 파일 이름과 LINENUMBER하고, AWK에 파이프를에 의해 정렬하는 저장 배열에있는 각 파일 이름의 마지막 경기, 결국 인쇄 그것.

상당히 무차별 한 방법이지만 작동합니다.

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