여러 개의 파일이 있고 어떤 파일에 특정 문자열로 시작하는 연속 줄이 포함되어 있는지 찾고 싶습니다.
예를 들어 다음 파일의 경우:
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}' {} \;
이 명령에서 +는 각 파일을 반복하고 각 파일에 대해 유사한 필터링을 수행하고 find
awk 표현식이 true로 평가되면 해당 이름을 인쇄합니다. 여러 일치 항목이 있는 단일 파일을 여러 번 인쇄하는 것을 방지하려면 이 문을 사용합니다(@terdon에게 감사드립니다).exec
awk
FILENAME
FILENAME
exit
답변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
에스다음 단일 문자 위치로 이동하여 다시 시도하세요.