![grep의 그룹 일치에 추가 문자가 포함되어 있습니다.](https://linux55.com/image/46666/grep%EC%9D%98%20%EA%B7%B8%EB%A3%B9%20%EC%9D%BC%EC%B9%98%EC%97%90%20%EC%B6%94%EA%B0%80%20%EB%AC%B8%EC%9E%90%EA%B0%80%20%ED%8F%AC%ED%95%A8%EB%90%98%EC%96%B4%20%EC%9E%88%EC%8A%B5%EB%8B%88%EB%8B%A4..png)
Bash에서 정규식을 사용하여 일부 텍스트를 추출하고 싶었기 때문에 다음과 같은 간단한 예제를 시도해 보기로 결정했습니다.
echo "abc def ghi" | grep -Po " \K(.*?) "
나는 을 얻을 것으로 예상했지만 "def"
놀랍게도 "def "
(끝에 추가 공간이 있음)을 얻었습니다.
grep
끝에 여분의 공간이 포함된 이유와 이를 제거하는 방법에 관심이 있습니다 . 다른 줄을 사용하여 결과를 사후 처리할 수 있다는 것을 알고 있지만 이 문제를 해결하는 데 관심이 있습니다.
답변1
간단히 말해서:
\K
grep이 모든 것을 유지하게 만듭니다.이전에\K로 변환하고 일치 항목에 포함하지 않습니다. 이것은 다음에 일어날 일에 영향을 미치지 않습니다뒤쪽에이것 \K()
.
이것으로 충분할 수 있습니다:
" \K(.+)(?= )"
(?= )
비캡처 그룹은 어디에 있나요?
아니면 더 좋을 수도 있습니다:
" \K([^ ]+)(?= )"
" \K(\w+)(?= )"
또는 유사합니다.
답변2
수행하려는 작업을 수행하는 BRE는 sed
다음과 같습니다.
sed 's/ *\(\([^ ]*\) *\)\{[num]\}.*/\2/'
sed
...또는 GNU 및 BSD 버전과 같이 이를 지원하는 ERE로 :
sed -E 's/ *(([^ ]*) *){[num]}.*/\2/p'
[num]
...어느 표현식이든 그룹의 첫 번째 문자부터 시작하여 일치합니다.(여기서 [num]
양의 정수는 무엇입니까?)패턴 공간의 공백이 아닌 문자를 검색 [^ ]*
하고 줄 끝까지 일치를 계속합니다.
그러나 중요한 것은 일부 일치 항목을 그룹화한다는 것입니다.
(([^ ]*) *){[num]}
- 이 그룹은 공백이 아닌 그룹 및 다음 공백 문자의 일부/모두만큼 많이 발생하며[num]
역참조로 사용할 수 있습니다\1
.{[num]}
- 패턴이\{[num]\}
여러 번 일치하는 경우 해당 패턴에 대한 유일한 참조는 마지막 패턴입니다. 따라서 그룹이 지정된 패턴과 여러 번 일치하는 경우에도 반환되는 유일한 참조는 마지막 패턴입니다.
([^ ]*)
- 그러나 위 그룹의 하위 그룹은 에서 일치하는 공백이 아닌 문자의 하위 집합에만 일치합니다\1
. 이 하위 그룹은 에서 참조될 수 있습니다\2
.*
And.*
- 이는 패턴 공간으로 이어지는 모든 공백 문자와 하위 표현식에서 일치하는 항목 다음에 나오는 모든 문자와 일치합니다./\2/
- 위의 모든 항목이 에서 참조된 그룹으로 대체됩니다\2
.
[^ ]*
and는 부울 보수 *
이고 [^ ]*
U를 *
함께 사용하면 가능한 모든 문자열을 설명할 수 있으므로 위의 정규식은 보편적입니다.
귀하의 예를 들어:
for n in 1 2 3 4
do echo "abc def ghi" |
sed -E "s/ *(([^ ]*) *){$n}.*/\2/"
done | sed -n l
...인쇄...
abc$
def$
ghi$
$
있는 그대로는 위에서 요청한 특정 이벤트에 대해 항상 빈 줄을 인쇄하지만, 원하지 않는 경우 다음과 같이 줄을 출력에서 완전히 제거할 수 있습니다.
sed -En 's/ *(([^ ]*) *){[num]}.*/\2/;/./p'
한 단계 더 나아가서 대체를 전역적으로 적용하여 모든 발생 항목만 얻을 수 있습니다 [num]
. 매우 제한적 이므로 대신 *
이것을 사용하겠습니다 . [[:space:]]*
어떤 <space><tab><newline><vertical tab><return>
.
s=
{ printf "${s:=$(printf '\r\v\t%10s')}"
seq -s"$s" 100
} | sed -En "s/[${s:=[:space:]}]*(([^$s]*)[$s]*){21}/\2\\
/g; /[^$s]/s/\n*$//p"
sed
위의 비트는 적용되기 전에 printf ...; seq ...
한 줄을 인쇄합니다 . 예를 들면 다음과 같습니다.
\r\v\t 1\r\v\t 2\r\v\t 3\r\v\t...
... 등. 그러나 위의 결과를 적용하면 sed
다음과 같습니다.
21
42
63
84
...뒤에 공백 없이 숫자를 인쇄합니다.