쉼표로 구분된 숫자와 일치하는 전역 패턴을 작성하고 싶습니다. 패턴은 어떤 모습일까요?
여기 몇 가지 예가 있어요
5
5,8,13
다음으로 시작했지만 일치하는 항목을 얻지 못하여 몇 가지 문제가 있습니다.
var="8,13,21"
echo "var: $var"
if [[ "$var" == ^*([[:digit:]])+(,+[[:digit:]])$ ]]; then
echo "match"
fi
답변1
bash 매뉴얼은 [[ expression ]]
구문을 설명합니다.
==
AND 연산자를 사용하는 경우!=
연산자 오른쪽의 문자열은 패턴으로 처리되며 마치extglob
셸 옵션이 활성화된 것처럼 패턴 일치에 설명된 규칙에 따라 일치됩니다.
여기서 쉘 옵션은 extglob
ksh 스타일 확장 글로브를 나타냅니다.
?(pattern-list)
Matches zero or one occurrence of the given patterns
*(pattern-list)
Matches zero or more occurrences of the given patterns
+(pattern-list)
Matches one or more occurrences of the given patterns
@(pattern-list)
Matches one of the given patterns
!(pattern-list)
Matches anything except one of the given patterns
내가 의심하는 것은 +[[:digit:]]
1개 이상의 숫자를 일치시키려는 것입니다 +([[:digit:]])
. 따라서 쉼표 뒤에 1개 이상의 숫자가 오고, 모두 0회 이상이어야 *(,+([[:digit:]])
합니다 .
+([[:digit:]])*(,+([[:digit:]]))
쉼표로 구분된 목록을 형성하기 위해 1개 이상의 숫자와 0개 이상의 쉼표로 구분된 숫자가 뒤따르는 일치 항목을 찾습니다.
^
glob 표현식은 앵커 를 사용하지 않는다는 점에 유의하십시오 $
. 이는 항상 전체 행입니다. 부분 일치를 원할 경우 *
표현식을 와일드카드로 묶어야 합니다.
1 이것은 bash 4.1부터 새로운 기능입니다. 이전 버전에서는 shopt -s extglob
이러한 확장된 전역 연산자를 내부 및 외부에서 명시적으로 사용할 수 있도록 해야 했습니다 [[...]]
.
답변2
사용하는 구문은 와일드카드와 정규식 구문이 혼합된 것처럼 보입니다.
Bash의 RegEx 일치를 사용하려는 경우(위에서 언급한 대로)댓글에서), 비교 연산자를 사용해야 합니다 =~
. 이 경우 테스트 구성의 올바른 구문은 다음과 같습니다.
if [[ "$var" =~ ^([[:digit:]])+(,[[:digit:]]+)*$ ]]; then
...
이는 여러 측면에서 시연한 시도와 다릅니다.
- 현재 시도에서는
,+[[:digit:]]
"하나 이상의 쉼표와 숫자"가 일치합니다. - 처음에 RegEx가
*
길을 잃은 것 같습니다. 리터럴과 일치하지 않는 한*
잘못되었거나(*
RegEx에서는 "가능한 문자 조합"이 아니라 "0개 이상의 선행 문자"를 의미함) 중복됩니다. ( 일치시키려면$.*
앵커를 제거하고 간단히 선언할 수도 있습니다([[:digit:]])+(,+[[:digit:]])$
).
반면에 실제로 "확장된 와일드카드" 구문( 연산자 의 구성 [[ ... ]]
에서 기본적으로 허용되는 ==
) 을 사용하려는 경우
^
앵커( 및 ) 사용이$
잘못되었습니다. 앵커는 정규식에만 유효하며 확장된 형식에서도 글로빙 구문의 일부가 아닙니다. 또한 전역 패턴은 기본적으로 전체 문자열에 적용되므로 필요하지 않습니다.- 또한,모든"반복 지정자"(예:
*
또는+
)가 앞에 오는 항목은 괄호 안에 배치해야 하므로 명령문에 괄호 세트가 누락됩니다+[[:digit:]]
.
따라서 이 경우 일치하는 글로브는 다음과 같아야 합니다.
if [[ "$var" == +([[:digit:]])*(,+([[:digit:]])) ]]; then echo "match"; fi
답변3
sh
완벽을 기하기 위해 명령문에서 표준 와일드카드 case
( kshism)를 사용하여 이 작업을 수행 하려면 [[...]]
그 반대를 수행해야 합니다.
case $var in
('' | *[!,0123456789]* | *, | ,* | *,,* ) echo WRONG;;
(*) echo RIGHT;;
esac
+
표준 glob 모드 ( ##
zsh 또는 ksh와 동일) 에는 ERE와 동등한 기능이 없습니다 .+(...)
그러나 다음 명령을 사용하여 정규식 일치를 수행할 수 있습니다 awk
¶
rematch() { awk -- 'BEGIN{exit(ARGV[1] !~ ARGV[2])}' "$@"; }
if rematch ",$var" '^(,[0123456789]+)+$'; then
echo RIGHT
else
echo WRONG
fi
1 ANSI C 이스케이프 시퀀스(예: , , (펄 스타일 단어 경계가 아닌 백스페이스의 경우)) awk
도 이해하는(또는 이해하기 위한 것이지만 모두가 이 방식으로 사용하는 것은 아님) 표준 확장 정규식의 변형을 얻습니다 . .\n
\t
\b