web-dev-qa-db-ja.com

bash [[コマンドの=〜演算子を使用した正規表現一致の問題

OSXでは、日付形式を検証してからエポック時間に変換する関数を作成しています。エラーではない場合、関数は日付が次のいずれかの形式であることを検証する必要があります:01/01/1970 10:00PMまたは10:00PM%m/%d/%Y %I:%M%pまたは%I:%M%p

[〜#〜]関数[〜#〜]

checkTIME () {
    local CONVERT_CHK_TIME="$1"
    if [[ "$CONVERT_CHK_TIME" =~ ^(0[0-9]|1[0-2]):[0-9][0-9](AM|PM)$ ]]; then
        CONVERT_TIME="$(date -j -f "%I:%M%p" "$CONVERT_CHK_TIME" "+%s")"
    Elif [[ "$CONVERT_CHK_TIME" =~ (0[0-9]|1[0-2])\/([0-2][0-9]|3[0-1])\/\d{4}\s[0-9][0-9]:[0-9][0-9](AM|PM) ]]; then
        CONVERT_TIME="$(date -j -f "%m/%d/%Y %I:%M%p" "$CONVERT_CHK_TIME" "+%s")"
    else
        echo "ERROR!"
        exit 1
    fi
}

現在、10:00PMですが、試しても一致しません01/10/2017 10:00PM

私はそれを次のように呼んでいます:

./convert '01/10/2017 10:00PM'
...
...
+ [[ -n 01/10/2017 10:00PM ]]
+ checkTIME '01/10/2017 10:00PM'
+ local 'CONVERT_CHK_TIME=01/10/2017 10:00PM'
+ [[ 01/10/2017 10:00PM =~ ^(0[0-9]|1[0-2]):[0-9][0-9](AM|PM)$ ]]
+ [[ 01/10/2017 10:00PM =~ (0[0-9]|1[0-2])/([0-2][0-9]|3[0-1])/d{4}s[0-9][0-9]:[0-9][0-9](AM|PM) ]]
+ echo 'ERROR!'
ERROR!
+ exit 1

ありがとう!

次の正規表現も試しました:

(0[0-9]|1[0-2])\/([0-2][0-9]|3[0-1])\/\d{4}\ [0-9][0-9]:[0-9][0-9](AM|PM)
5
jesse_b

\dは、一部のバージョンの正規表現(Perl)の10進数と一致しますが、bash=~コマンドの[[演算子に使用される拡張正規表現には一致しません。

したがって、4つの10進数と一致するパターンの\d[0-9]に変更します。

\sも同様です。 1つのリテラルスペース文字に一致させるには、\sをエスケープされたスペース(\)に置き換えます。 1つ以上blanks(スペースまたはタブ)に一致させる場合は、\s[[:blank:]]+に置き換えます。

さらに重要なのは、これらの正規表現の取り違えを避けるためです。

man bashは、regex(3)で説明されているように、=~正規表現が拡張正規表現構文に従って一致することを示しています。
man 3 regex(POSIX正規表現関数)はSEE ALSO regex(7)と言います。
man 7 regexは、正規表現構文の説明を提供し、SEE ALSO POSIX.2, section 2.8 (Regular Expression Notation)と言います。

The Open Group'sPosix Regular Expressions documentation で説明されている完全なPOSIX拡張正規表現構文を見つけることができます。

7
RobertL

GNU dateへのアクセス権がある場合の1つのオプションは、ロバを機能させ、REの複雑さを完全に回避することです。

checkTIME () {
    convert_time=$(date --date "$1" +'%s' 2>/dev/null)
    if [[ -z "$convert_time" ]]
    then
        echo 'ERROR!'
        exit 1
    fi
}

GNU dateへのアクセス権がないことと、検証のために照合するREが必要であることを通知したので、このアプローチを使用できます。他にもいくつか提供されています。)

[[ " $1 " =~ ^' '*([01]?[0-9]/[0123]?[0-9]/2[0-9][0-9][0-9])?' '+([01]?[0-9]:[0-5][0-9][AP]M)?' '*$ ]]

入力パラメーター($1)の両側にスペースを追加して、datetime、または日時(2つのコンポーネント間に必須のスペースあり)。書かれているように、日付部分は2000年代の4桁の年を要求します。この要件を緩和してください。

スペースを指定するために' 'を使用しました。必要に応じて、[[:space:]]を使用して空白を表すことができます。

比較が完了したら、日付コンポーネントを${BASH_REMATCH[1]}として、時間コンポーネントを${BASH_REMATCH[2]}として選択できます。

8
roaima

\ dおよび\ sエスケープは、ご使用のバージョンのbashでは機能しないようです。代わりに[[:digit:]][[:space:]]を使用してみてください。

(0[0-9]|1[0-2])/([0-2][0-9]|3[0-1])/[[:digit:]]{4}[[:space:]](0[0-9]|1[0-2]):[0-9][0-9](AM|PM)

実行中:

bash-3.2$ [[ "01/10/2017 10:00PM" =~ (0[0-9]|1[0-2])/([0-2][0-9]|3[0-1])/[[:digit:]]{4}[[:space:]](0[0-9]|1[0-2]):[0-9][0-9](AM|PM) ]] && echo match
match
3
mmusante

ファイルs1のこのスニペット:

mydate='01/10/2017 10:00PM'

pl " Expected output:"
cat expected-output1

pl " Results:"
# Linux: dateutils.dconv -f "%s%n" -i "%m/%d/%Y %I:%M%p" "$mydate"
dateconv -f "%s%n" -i "%m/%d/%Y %I:%M%p" "$mydate"

生成する:

-----
 Expected output:
1484085600

-----
 Results:
1484085600

次のようなシステム:

OS, ker|rel, machine: Apple/BSD, Darwin 16.7.0, x86_64
Distribution        : macOS 10.12.6 (16G29), Sierra
bash GNU bash 3.2.57

Dateconv(別名dconv、dateutils.dconv)コードは、brewから入手できるdateutilsパッケージの一部です-dateconvの詳細の一部:

dateconv - Convert DATE/TIMEs between calendrical systems.
Home    : http://www.fresse.org/dateutils
Path    : /usr/local/bin/dateconv
Version : - ( local: /usr/local/bin/dateconv, 2017-10-15 )
Type    : Mach-O64-bitexecutablex86_64 ...)

最高の願い...乾杯、drl

2
drl