역 참조를 사용하여 캡처 그룹이라는 Bash 정규식을 사용합니까?

역 참조를 사용하여 캡처 그룹이라는 Bash 정규식을 사용합니까?

나는 다음을 수행하고 싶습니다 -

bash-shell>echo (*).prop ; echo \1 

분명히 위의 방법은 작동하지 않습니다. 그러나 이것이 가능한지, 그에 상응하는 것이 무엇인지 궁금합니다.

*현재 디렉터리의 모든 파일과 일치하도록 쉘에 와일드카드를 사용 하고 싶습니다 . 물론, 위 검색을 .prop로 끝나는 파일로만 제한하세요. .prop 확장자가 없는 파일 이름을 캡처하고 역참조를 사용하여 인쇄합니다.\1

제가 추가한 예는 설명하기가 좀 간단합니다. 내 사용 사례는 더 복잡하지만 요구 사항을 충족하기 위한 역참조가 필요합니다.

답변1

ksh93은 AFAIK, ksh93 및 zsh 지원 캡처 그룹을 지원하는 역참조를 지원하는 유일한 셸입니다. 이는 여기서 찾고 있는 것과 비슷하지만 제안한 대로 사용할 수는 없습니다. (ksh93 \1) 또는 $match[1](zsh)에는 일치하는 각 파일에 대해 캡처된 내용에 대한 참조가 필요합니다.

ksh93에서는 다음을 수행할 수 있습니다.

files=( ~(N)*.prop )
(( ${#files[@]} == 0 )) || printf '%s\n' "${files[@]/@(*).prop/\1}"

zsh에서:

set -o extendedglob
files=( *.prop(N) )
print -rC1 -- ${files/(#b)(*).prop/$match[1]}

연산자의 일부로 캡처 그룹에 대한 참조가 일치하는 각 파일에 대해 수행됩니다 ${array/pattern/replacement}.

이는 zshval glob 한정자의 일부로 수행될 수도 있습니다 e.

set -o extendedglob
print -rC1 -- *.prop(Ne['REPLY=${REPLY/(#b)(*).prop/$match[1]}'])

:r확장을 제거하기 위한 전용 ootname 수정자가 있지만 :

print -rC1 -- *.prop(N:r)

Bash에서는 언제든지 다음을 수행할 수 있습니다.

shopt -s nullglob
files=( *.prop )
(( ${#files[@]} == 0 )) ||
  printf '%s\n' "${files[@]%.prop}"

역참조는 기본 정규식 및 기타 정규식 엔진의 기능입니다.

bash실제로 내장된 정규식 일치 연산자가 있지만 ERE(확장 정규식)를 사용한다는 점에 유의하세요. 표준 ERE는 역참조를 만들지 않지만 일부 구현에서는 이를 확장으로 지원합니다.

존재하다:

[[ aa =~ (.)\1 ]]

\1표준 ERE 연산자가 아니기 때문에 그다지 효율적이지는 않지만 bash는 이를 \1인용된 것으로 처리하여 1시스템의 정규식 엔진을 (.)1정규식으로 호출하기 때문입니다.

regexp='(.)\1'
[[ aa =~ $regex ]]

GNU 시스템과 같이 확장 정규식 엔진이 역참조를 지원하는 시스템에서 작동합니다.

여기에는 여러분이 원하는 것이 더 많이 포함되어 있으며, bash는 바로 그 일을 합니다.

성공 후

[[ $file =~ ^(.*)\.prop$ ]]

일치하는 콘텐츠는 (.*)(배열의 두 번째 요소, zsh에서 캡처된 내용이 배열에 들어감)에서 사용할 수 있으므로 다음을 수행할 수 있습니다.${BASH_REMATCH[1]}$BASH_REMATCH$match

shopt -s nullglob
for file in *.prop; do
  if [[ $file =~ ^(.*)\.prop$ ]]; then
    printf '%s\n' "${BASH_REMATCH[1]}"
  fi
done

( 예를 들어 파일 이름이 사용자의 로캘 문자 집합으로 인코딩되지 않은 경우 파일 실패가 *.prop발생할 수 있습니다.)[[ $file =~ ^(.*)\.prop$ ]]


어쨌든 POSIX 셸에서는 \1or와 동일합니다. 즉, 인용됩니다. 따라서 POSIX와 호환되도록 설계된 쉘은 POSIX가 이를 지정하지 않은 영역(예: ksh93에서 두 개의 동일한 문자로 시작하는 파일을 찾는 경우(따옴표가 없는 문자가 지정되지 않은 동작을 발생시키는 경우) 또는 이전에 언급한 경우에만 다른 의미를 부여할 수 있습니다. file은 POSIX 지정 연산자가 아닙니다.'1'"1"1print -r -- @(?)\1*()"${files[@]/@(*).prop/\1}"${array/pattern/replacement}

답변2

GNU 사용 basename(또는 FreeBSD 또는 여러 단일 인수를 처리하고 각 인수에서 접미사를 제거하는 basename비표준 -a및 옵션을 제공하는 기타 구현에서):-s

basename -a -s .prop -- *.prop

*.prop그러면 패턴과 일치 하지만 .prop파일 이름 접미사가 제거된 파일 이름이 제공됩니다 .

제안한 것과 비슷한 것을 사용하십시오.

names=( *.prop )
printf '%s\n' "${names[@]%.prop}"

그러면 일치하는 모든 이름을 포함하는 배열이 생성됩니다 names. 그런 다음 사용된 변수 대체는 각 이름을 출력하기 전에 printf파일 이름 접미사를 제거합니다 ..propprintf

배열에 로 끝나는 문자열만 포함되어 있다는 것을 알고 있으므로 .prop두 번째 줄은 다음과 같이 단축될 수 있습니다.

printf '%s\n' "${names[@]%.*}"

그러면 배열의 각 문자열에서 마지막 점(및 점) 뒤의 모든 항목이 제거됩니다 names.

쉘은 실제로 파일 이름을 일치시키기 위해 정규식을 사용하지 않습니다. 이는 파일 이름 글로빙 패턴을 통해 수행됩니다. 정규식은 파일의 텍스트를 일치시키는 데 더 일반적으로 사용됩니다.

관련 정보