파이프를 사용하지 않고 파일에서 문자열을 찾는 Grep

파이프를 사용하지 않고 파일에서 문자열을 찾는 Grep

파이프를 사용하지 않고 파일의 마지막 n 줄에서 단어를 찾기 위해 grep을 사용하고 싶습니다.

grep <string> filename

파일 이름에서 문자열을 검색할 수 있습니다. 그러나 파일의 마지막 N 줄에서 문자열을 검색하고 싶습니다. 파이프를 사용하지 않고 검색하는 명령이 있습니까?

답변1

쉘이 이를 지원하는 경우( zsh, , , bash의 일부 구현 ksh) 다음을 사용할 수 있습니다.프로세스 교체

grep <pattern> <(tail -n5 yourfile.txt)

여기서 -n5는 마지막 5개 라인을 가져오는 것을 의미합니다.

비슷하게,

grep <pattern> <(head -n5 yourfile.txt)

yourfile.txt의 처음 5줄이 검색됩니다.

설명하다

간단히 말해서, 대체된 프로세스는 grep이 기대하는 파일로 가장합니다. 프로세스 대체의 장점 중 하나는 diff이 예에 표시된 것처럼 여러 명령의 출력을 다른 명령에 대한 입력으로 사용할 수 있다는 것입니다.

diff -y <(brew leaves) <(brew list)

이렇게 하면 파이프( |) 문자가 제거되지만 각 대체 문자는 실제로파이프라인 생성1 .


1 적어도 ksh93Linux에서는|아니요파이프를 사용하지만 소켓 쌍을 사용하십시오.프로세스 교체open파이프를 사용하십시오(소켓은 불가능하므로).

$ ksh93 -c '읽기링크 <(:)'
파이프: [620224]
$ ksh93 -c ': 읽기 링크 /proc/self/fd/0'
소켓: [621301]

답변2

n=$some_num
{   head -n"$(($(wc -l <in)-n))" >/dev/null
    grep 'match your string'
}   <in

불행하게도 줄 수를 얻으려면 파일을 완전히 읽어야 합니다. wc그렇지 않으면 파일에 몇 줄이 있는지, 얼마나 큰지 명확하지 않기 때문입니다 $n. 그 외에 이것은 매우 성능이 좋은 솔루션이어야 합니다 <in.lseek()유능한문서.

먼저 행 수를 구하고 $n그 수를 뺍니다. headstdin에서 해당 행을 읽고 결과를 작성합니다 /dev/null. 그 후에 남은 것은 $nstdin의 입력 행 수와 사용자 grep의 패턴뿐입니다.

기술적으로 이것은 속임수입니다.명령의 파이프는 으로 대체됩니다 wc. 이를 무시해도 됩니다.

그런데 또 다른 접근 방식은 다음과 같습니다.

{   grep "-m$n" 'some pattern near yours' >/dev/null
    grep 'your pattern'
}   <in

...GNU와 함께 grep. 목표 패턴 근처 어딘가에 나타나는 다른 패턴을 가질 수 있다면 grep $n실제로 파이프 없이도 그렇게 할 수 있습니다.

나는 w/ 를 고수하려고 노력하고 있지만 grep어쨌든 sed여기에 해결책이 있습니다. 아래 파이프라인은 입력 전용입니다. grep줄 번호 앞에 추가하는 것 외에는 전혀 관련되지 않으므로 어떤 번호인지 확인할 수 있습니다. 이 모든 것은 예시 사례에만 적용됩니다. sed모든 종류의 명명된 파일이나 표준 입력에 스크립트만 사용할 수 있으며 $pat적절한 $n설정을 사용하면 작동합니다.

사실 저는 경기를 고정시킬 수 없는 게 싫어서 이것을 다시 썼습니다. 이것은조금느림 - 눈에 띄지는 않지만 여전히 매우 빠르지만 버퍼링된 모든 후행 라인에 대해 후행 패턴 공간을 모두 잘라내고 버퍼의 첫 번째 라인을 격리합니다. 이렇게 하면 모든 일반 앵커 표현식이 예상대로 작동합니다.

pat=man n=40
man man   |
grep -n ''|
sed -e:B -e'${/^\n/D'  \
    -eh  -e's/\n.*//'  \
         -e"/$pat/p;x" \
    -e\} -e'$D;N;$bB'  \
         -e"$n,$ D;bB"

648:       /etc/man_db.conf
649:              man-db configuration file.
651:       /usr/share/man
652:              A global manual page hierarchy.
654:       /usr/share/man/index.(bt|db|dir|pag)
657:       /var/cache/man/index.(bt|db|dir|pag)
661:       apropos(1), groff(1), less(1), manpath(1),  nroff(1),  troff(1),  whatis(1),
662:       zsoelim(1),  setlocale(3),  manpath(5),  ascii(7),  latin1(7),  man(7), cat-
663:       man(8), mandb(8), the man-db package manual, FSSTND
680:       developing and maintaining man-db.

다음은 파일에 대한 또 다른 예입니다.

pat=. n=15
seq 100 >nums
sed -e:B -e'${/^\n/D'  \
    -eh  -e's/\n.*//'  \
         -e"/$pat/p;x" \
    -e\} -e'$D;N;$bB'  \
<nums    -e"$n,$ D;bB"

86
87
88
89
90
91
92
93
94
95
96
97
98
99
100

답변3

왜 파이프를 피해야 합니까?

실제로 파이프 사용을 피하려면 다음 두 가지 명령을 실행해야 합니다.

tail -N filename > filename.tmp
grep "string" filename.tmp

(when N is the last number of lines)

답변4

awk약간의 도움을 받으면 이 작업을 수행 할 수 있습니다 .

$ N=8
$ awk -v start_line="$(( $(wc -l < alphabet) - N + 1 ))" 'NR>=start_line  &&  /e/' alphabet
sierra
whiskey
yankee
$

e마지막 8줄에 포함된 모든 줄 찾기병음 알파벳. 이것의 단점은 전체 입력 파일을 두 번 읽는다는 것입니다.

관련 정보