bash는 문자열로 시작하는 줄을 찾습니다.

bash는 문자열로 시작하는 줄을 찾습니다.

여러 개의 파일이 있고 어떤 파일에 특정 문자열로 시작하는 연속 줄이 포함되어 있는지 찾고 싶습니다.

예를 들어 다음 파일의 경우:

Aaaaaaaaaaaa
Baaaaaaaaaaa
Cxxxxxxxxx
Cyyyyyyyyy
Czzzzzzzzz
Abbbbbbbbbbb
Bbbbbbbbbbbb
Caaaaaa
Accccccccccc
Bccccccccccc
Cdddddd
Ceeeeee

"C"로 시작하는 줄이 두 개 이상 있어서 명령을 통해 파일을 찾고 싶습니다.
예를 들어 다음 파일의 경우:

Aaaaaaaaaaaa
Baaaaaaaaaaa
Cxxxxxxxxx
Abbbbbbbbbbb
Bbbbbbbbbbbb
Caaaaaa
Accccccccccc
Bccccccccccc
Cdddddd

항상 "C"로 시작하는 줄이 있는데 이 파일은 필요하지 않습니다. a grep또는 a를 사용하려고 생각했지만 sed정확히 어떻게 해야 할지 모르겠습니다. 어쩌면 정규 표현식 ^C.*$^C이나 이와 유사한 것을 사용할 수도 있습니다. 어떤 아이디어가 있나요?

답변1

그리고 pcregrep:

pcregrep -rMl '^C.*\nC' .

POSIX적으로:

find . -type f -exec awk '
  FNR==1 {last=0; printed=0; next}
  printed {next}
  /^C/ {if (last) {print FILENAME; printed=1; nextfile} else last=1; next}
  {last=0}' {} +

awk(이는 지원되지 않는 구현을 사용하여 모든 파일을 완전히 읽는 것을 의미하지만 nextfile).


GNU 버전 grep최대 2.5.4:

grep -rlP '^C.*\nC' .

나타나다작동하지만 이는 실패작이며 작동이 보장되지 않습니다.

2.6에서 수정되기 전(이번에 제출하세요), GNU는 grep사용 중인 PCRE를 무시합니다. 검색 기능은 현재 처리 중인 전체 버퍼와 일치하므로 grep모든 종류의 놀라운 동작이 발생합니다. 예를 들어:

grep -P 'a\s*b'

다음을 포함하는 파일과 일치합니다.

bla
bla

이는 다음과 일치합니다.

printf '1\n2\n' | grep -P '1\n2'

하지만 이것은:

(printf '1\n'; sleep 1; printf '2\n') | grep -P '1\n2'

또는:

(yes | head -c 32766; printf '1\n2\n') > file; grep -P '1\n2' file

아니요( 1\n2\n에서 처리하는 두 개의 버퍼에 걸쳐 있기 때문입니다 grep).

그러나 이 동작은 결국 다음과 같이 문서화되었습니다.

15-행 전체를 일치시키는 방법은 무엇입니까?

표준 grep은 기본적으로 라인 기반이기 때문에 이를 수행할 수 없습니다. 따라서 '[:space:]' 문자 클래스를 사용하는 것만으로는 예상한 대로 개행 문자와 일치하지 않습니다. 그러나 Perl 모드가 활성화된 상태에서 grep이 컴파일된 경우 Perl 's' 수정자를 사용할 수 있습니다('.'가 개행과 일치하도록 함).

     printf 'foo\nbar\n' | grep -P '(?s)foo.*?bar'

2.6 수정 이후 문서가 수정되지 않았습니다.거기).

답변2

그리고 awk:

awk '{if (p ~ /^C/ && $1 ~ /^C/) print; p=$1}' afile.txt

로 시작하는 연속 줄이 있으면 파일 내용이 인쇄됩니다 C. 이 표현식은 (p ~ /^C/ && $1 ~ /^C/)파일의 연속된 줄을 살펴보고 두 줄의 첫 번째 문자가 일치하면 true로 평가됩니다 C. 이 경우 해당 행이 인쇄됩니다.

이 패턴을 가진 모든 파일을 찾으려면 find다음 명령을 통해 위의 awk를 실행할 수 있습니다.

find /your/path -type f -exec awk '{if (p ~ /^C/ && $1 ~ /^C/) {print FILENAME; exit;} p=$1}' {} \;

이 명령에서 +는 각 파일을 반복하고 각 파일에 대해 유사한 필터링을 수행하고 findawk 표현식이 true로 평가되면 해당 이름을 인쇄합니다. 여러 일치 항목이 있는 단일 파일을 여러 번 인쇄하는 것을 방지하려면 이 문을 사용합니다(@terdon에게 감사드립니다).execawkFILENAMEFILENAMEexit

답변3

GNU의 또 다른 옵션 sed:

단일 파일의 경우:

sed -n -- '/^C/{n;/^C/q 1}' "$file" || printf '%s\n' "$file"

(읽을 수 없는 파일도 보고하지만)

을 위한 find:

find . -type f ! -exec sed -n '/^C/{n;/^C/q 1}' {} \; -print

다음 코드를 작성하면 읽을 수 없는 파일을 인쇄하는 문제를 피할 수 있습니다.

find . -type f -size +2c -exec sed -n '$q1;/^C/{n;/^C/q}' {} \; -print

답변4

해결책:

( set -- *files ; for f ; do (
set -- $(printf %c\  `cat <$f`)
while [ $# -ge 1 ] ;do [ -z "${1#"$2"}" ] && {
    echo "$f"; break ; } || shift
done ) ; done )

데모:

먼저 테스트 기반을 만듭니다.

abc="a b c d e f g h i j k l m n o p q r s t u v w x y z" 
for l in $abc ; do { i=$((i+1)) h= c= ;
    [ $((i%3)) -eq 0 ] && c="$l" h="${abc%"$l"*}"
    line="$(printf '%s ' $h $c ${abc#"$h"})"
    printf "%s$(printf %s $line)\n" $line >|/tmp/file${i}
} ; done

위에서 26개의 파일이 생성되었습니다./tmp명명 된file1-26.각 파일에는 문자로 시작하는 27~28줄이 있습니다.a-z그런 다음 나머지 알파벳이 나옵니다. 각 세 번째 파일에는 첫 번째 문자가 반복되는 두 개의 연속 라인이 포함되어 있습니다.

견본:

cat /tmp/file12
...
aabcdefghijkllmnopqrstuvwxyz
babcdefghijkllmnopqrstuvwxyz
cabcdefghijkllmnopqrstuvwxyz
...
kabcdefghijkllmnopqrstuvwxyz
labcdefghijkllmnopqrstuvwxyz
labcdefghijkllmnopqrstuvwxyz
mabcdefghijkllmnopqrstuvwxyz
...

변경할 때:

set -- *files

도착하다:

set -- /tmp/file[0-9]*

알겠어요...

산출:

/tmp/file12
/tmp/file15
/tmp/file18
/tmp/file21
/tmp/file24
/tmp/file3
/tmp/file6
/tmp/file9

간단히 말해서 솔루션은 다음과 같이 작동합니다.

set에스모든 파일의 하위 쉘 위치 및 각 파일

set에스중첩된 하위 쉘은 각 파일의 각 줄의 첫 번째 문자로 반복됩니다.

[ tests ]만약에$1부정적인$2일치하는 경우 일치함을 나타냅니다.

echoes그러면 파일명이break에스현재 루프 반복

기타shift에스다음 단일 문자 위치로 이동하여 다시 시도하세요.

관련 정보