Bash 스크립트에서 문자열이 정규식과 일치하는지 확인하십시오.


204

내 스크립트가 수신하는 인수 중 하나는 다음 형식의 날짜입니다 yyyymmdd.

입력으로 유효한 날짜가 있는지 확인하고 싶습니다.

어떻게해야합니까? 정규식을 사용하려고합니다.[0-9]\{\8}


형식이 올바른지 확인하는 것이 쉽습니다. 그러나 나는 당신이 bash에서 (내장으로) 날짜가 유효한지 확인할 수 없다고 생각합니다.
RedX

답변:


317

[[ ]]정규 표현식 일치 연산자와 함께 테스트 구문을 사용할 수 있습니다 .=~ 문자열이 정규식 패턴과 일치하는지 확인할 수 있습니다.

구체적인 경우에는 다음과 같이 쓸 수 있습니다.

[[ $date =~ ^[0-9]{8}$ ]] && echo "yes"

또는 더 정확한 테스트 :

[[ $date =~ ^[0-9]{4}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])$ ]] && echo "yes"
#           |^^^^^^^^ ^^^^^^ ^^^^^^  ^^^^^^ ^^^^^^^^^^ ^^^^^^ |
#           |   |     ^^^^^^^^^^^^^  ^^^^^^^^^^^^^^^^^^^^^^^^ |
#           |   |          |                   |              |
#           |   |           \                  |              |
#           | --year--   --month--           --day--          |
#           |          either 01...09      either 01..09     end of line
# start of line            or 10,11,12         or 10..29
#                                              or 30, 31

즉, 원하는 형식과 일치하는 Bash 에서 정규식을 정의 할 수 있습니다 . 이 방법으로 할 수있는 일 :

[[ $date =~ ^regex$ ]] && echo "matched" || echo "did not match"

&&테스트가 성공하면 이후의 명령 이 실행되고 이후의 명령은|| 테스트가 실패하면 실행됩니다.

이것은 bash의 사용자 입력 날짜 형식 확인에서 Aleks-Daniel Jakimenko의 솔루션을 기반으로합니다 .


다른 쉘에서는 grep 을 사용할 수 있습니다 . 쉘이 POSIX 호환 인 경우

(echo "$date" | grep -Eq  ^regex$) && echo "matched" || echo "did not match"

POSIX 호환이 아닌 fish 에서는 할 수 있습니다

echo "$date" | grep -Eq "^regex\$"; and echo "matched"; or echo "did not match"

19
나는 그것을 알고 있지만, 누가 묻는 사람과 그들이 bash와 얼마나 멀리 있는지 고려하고 싶습니다. 우리가 매우 복잡한 조건을 제공한다면, 그들은 아무것도 배우지 않고 또 다른 의심이있을 때마다 돌아올 것입니다. 좀 더 이해하기 쉬운 대답을 선호합니다.
fedorqui 'SO 중지 피해'

7
허. 글을 배우는 유일한 방법은 좋은 코드를 많이 읽는 것입니다. 이해하기 쉽지만 사용을 권장하지 않는 잘못된 코드를 제공하는 경우 잘못된 방법입니다. 또한 방금 bash를 배우기 시작한 사람들 (아마도 다른 언어의 비트를 이미 알고 있음)은 플래그 가있는 일부 grep명령 보다 정규식에 대한 bash 구문을 더 쉽게 이해할 것 -E입니다.
Aleks-Daniel Jakimenko-A.

8
@ Aleks-DanielJakimenko 나는이 게시물을 다시 겪었으며 이제는 bash 정규식을 사용하는 것이 가장 좋습니다. 좋은 방향을 가리키고 업데이트 된 답변을 보내 주셔서 감사합니다.
fedorqui 'SO 중지 피해'

4
예를 들어 sh를 위해 OP 질문보다 조금 더 사용할 수있는 Upvote.
Dereckson

3
하기 Aleks-DanielJakimenko이 GREP을 사용하여 @ 당신이 사용하는 경우 최선의 선택이 될 것 같다 sh, fish또는 덜 장착 된 포탄입니다.
tomekwi

47

bash 버전 3에서는 '= ~'연산자를 사용할 수 있습니다.

if [[ "$date" =~ ^[0-9]{8}$ ]]; then
    echo "Valid date"
else
    echo "Invalid date"
fi

참조 : http://tldp.org/LDP/abs/html/bashver3.html#REGEXMATCHREF

참고 : Bash 버전 3.2부터는 이중 대괄호 [[]] 내에서 일치 연산자의 인용 부호가 더 이상 필요하지 않습니다.


20
정규 expresion에서 char "을 사용하면 안됩니다. expresion을 사용할 때 작동하지 않기 때문에
Dawid Drozd

또한, {와}의 백 슬래시 이스케이프 처리도 비슷합니다.
kbulgrien

32

문자열이 올바른 날짜인지 테스트하는 좋은 방법은 명령 날짜를 사용하는 것입니다.

if date -d "${DATE}" >/dev/null 2>&1
then
  # do what you need to do with your date
else
  echo "${DATE} incorrect date" >&2
  exit 1
fi

의견에서 : 서식을 사용할 수 있습니다

if [ "2017-01-14" == $(date -d "2017-01-14" '+%Y-%m-%d') ] 

9
날짜 함수가 오류가 발생하기 쉬운 정규식이 아닌 날짜를 처리 할 수 ​​있도록 답변을 높게 평가하십시오.
Ali

광범위한 날짜 옵션을 확인하는 데 유용하지만 특정 날짜 형식을 확인해야하는 경우 가능합니까? 예를 들어 내가 date -d 2017-11-14e2017 년 11 월 14 일 05:00:00 UTC를 반환하지만 스크립트가 손상됩니다.
요시야

1
다음과 같이 사용할 수 있습니다. if [ "2017-01-14"== $ (date -d "2017-01-14" '+ % Y- % m- % d')] 날짜가 올바른지 테스트합니다. 결과가 입력 한 데이터와 동일한 지 확인하십시오. 그건 그렇고, 현지화 된 날짜 형식 (예를 들어 월-일 대 월-년)에 매우주의하십시오.
Django Janny

1
지역에 따라 작동하지 않을 수 있습니다. MM-DD-YYYY를 사용한 미국 형식 날짜는 DD-MM-YYYY (유럽) 또는 YYYY-MM-DD (아시아 일부)를 사용하여 전 세계 어느 곳에서도 작동하지 않습니다.
Paul

@Paul, 어떻게 작동하지 않을 수 있습니까? 코멘트로 작성된 것처럼, 포맷 옵션을 사용할 수 있습니다 ...
Betlista

4

expr match대신에 사용 합니다 =~:

expr match "$date" "[0-9]\{8\}" >/dev/null && echo yes

이것은 빈 문자열과도 일치 =~하므로 =~IMHO는 사용하지 않아야 하기 때문에 현재 사용되는 대답보다 낫습니다 . badvar정의되지 않은 다음 [[ "1234" =~ "$badvar" ]]; echo $?(잘못된) 0expr match "1234" "$badvar" >/dev/null ; echo $?제공하지만 올바른 결과 를 제공 한다고 가정 하십시오 1.

우리는 사용할 필요가 >/dev/null숨기기로 expr match출력 값 일치하는 항목이없는 경우 문자의 수가 일치 또는 0,. 음표 출력값이 상이하다 그 종료 상태 . 일치하는 것이 있으면 종료 상태는 0이고 그렇지 않으면 1입니다.

일반적으로 구문 expr은 다음과 같습니다.

expr match "$string" "$lead"

또는:

expr "$string" : "$lead"

$lead정규식은 어디에 있습니까 ? 그것이 exit status사실이 될 것입니다 (0)의 경우 lead경기의 주요 슬라이스 string(이 이름이 있습니까?). 예를 들어 expr match "abcdefghi" "abc"종료 true하지만 expr match "abcdefghi" "bcd"종료 false합니다. (이 점을 지적한 @Carlo Wood에게 감사드립니다.


7
=~빈 문자열과 일치하지 않으면 예제에서 빈 패턴 과 문자열을 일치 시킵니다. 구문은 string =~ pattern이며 빈 패턴은 모든 것과 일치합니다.
bstpierre

2
이것은 하위 문자열과 일치하지 않으며, 일치하는 선행 문자 수를 리턴하고 (stdout으로) 최소 1 개의 문자가 일치하면 종료 상태가 true입니다. 빈 문자열 (0 문자와 일치)이 종료 상태가 false 인 이유입니다. 예를 들어 expr match "abcdefghi" "^" && echo Matched || echo No match-와 expr match "abcdefghi" "bcd" && echo Matched || echo No match–는 모두 반환 "0\nNo match"합니다. 일치하는 곳 "a.*f"이 반환 "6\nMatched"됩니다. 따라서 예제에서 '^'을 사용하는 것도 불필요하며 이미 암시되어 있습니다.
Carlo Wood

@ bstpierre : 여기서 요점은 =~빈 문자열 일치 동작을 합리화 할 수 있는지 여부가 아닙니다 . 이 동작은 예기치 않은 오류가 발생할 수 있습니다. 나는이 답변에 구체적으로 썼다.
Penghe Geng 2016 년

@PengheGeng 예기치 않은 동작? 패턴에 정의 나 제약이없는 경우 실제로 패턴과 일치합니다. 패턴이 없으면 모든 것이 일치합니다. 강력한 코드를 작성하는 것은 답이 아니며 잘못된 설명을 정당화하지는 않습니다.
앤서니 Rutledge

@AnthonyRutledge "견고한 코드"는 우발적 인 코딩 오류를 방지하기 위해 사용 가능한 도구를 최대한 사용해야합니다. 맞춤법 오류와 같은 방법으로 언제라도 빈 변수를 쉽고 실수로 도입 할 수있는 셸 코드에서는 빈 변수를 일치시키는 것이 강력한 기능이라고 생각하지 않습니다. 분명히 GNU의 저자는 expr저에게 동의합니다.
Penghe Geng

0

정규식을 사용하여 날짜의 문자 순서가 올바른지 확인하는 데 도움이 될 수 있으면 날짜가 유효한지 쉽게 확인할 수 없습니다. 다음 예제는 정규식을 전달하지만 모두 유효하지 않은 날짜입니다. 20180231, 20190229, 20190431

따라서 날짜 문자열 (이라고 부름 datestr)이 올바른 형식 인지 확인하려면 날짜 를 구문 분석 하고 문자열을 올바른 형식으로 변환 date하도록 요청 하는 것이 가장 좋습니다 date. 두 문자열이 모두 같으면 유효한 형식과 유효한 날짜입니다.

if [[ "$datestr" == $(date -d "$datestr" "+%Y%m%d" 2>/dev/null) ]]; then
     echo "Valid date"
else
     echo "Invalid date"
fi
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.