Problemas com correspondência de expressão regular usando o operador = ~ do comando bash [[

5

No OSX, estou criando uma função para validar formatos de data e, em seguida, convertê-los em tempos de época. A função deve validar se a data está em um dos seguintes formatos, se não houver erro: 01/01/1970 10:00PM ou 10:00PM ( %m/%d/%Y %I:%M%p ou %I:%M%p )

FUNÇÃO

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
}

Atualmente, ele funciona bem para 10:00PM , mas não está correspondendo quando tento 01/10/2017 10:00PM

Eu estou chamando da seguinte forma:

./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

Obrigado!

Eu também tentei o seguinte regex:

(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)
    
por Jesse_b 14.10.2017 / 21:43

4 respostas

7

\d corresponde a um dígito decimal em algumas versões de regex (perl), mas não nas Expressões regulares estendidas usadas para o operador =~ do comando [[ em bash .

Portanto, altere o \d para [0-9] para um padrão que corresponderá a 4 dígitos decimais.

Similarmente para \s . Para corresponder a um caractere de espaço literal, substitua o \s por um espaço de escape ( \ ). Se você quiser combinar 1 ou mais espaços em branco (espaços ou tabulações), substitua o \s por [[:blank:]]+ .

Mais importante, para evitar essas misturas de regex:

man bash diz que =~ expressões regulares correspondem de acordo com a sintaxe expressão regular estendida , conforme documentado em regex(3) .
man 3 regex (funções regex POSIX) diz SEE ALSO regex(7) .
man 7 regex fornece uma descrição da sintaxe da expressão regular e diz SEE ALSO POSIX.2, section 2.8 (Regular Expression Notation) .

Você pode encontrar a sintaxe completa das Expressões Regulares Extensivas POSIX, descrita em O Grupo Aberto Documentação de expressões regulares de Posix .

    
por 14.10.2017 / 23:34
8

Uma opção se você tiver acesso ao GNU date é fazer com que o burro funcione para você e evitar completamente a complexidade do RE:

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

Como você avisou que não tem acesso ao GNU date e precisa que o RE corresponda para validação, você pode usar essa abordagem. (Eu sei que você tem vários outros que foram oferecidos.)

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

Eu adicionei um espaço extra em cada lado do parâmetro de entrada ( $1 ) para que possamos corresponder a qualquer data , tempo ou data time (com espaço obrigatório entre os dois componentes). Conforme escrito, a parte da data exige um ano de quatro dígitos nos anos 2000; fique à vontade para relaxar esta exigência.

Eu usei ' ' para especificar um espaço. Você poderia usar [[:space:]] para representar qualquer espaço em branco se preferir.

Após a comparação ter sido feita, você pode escolher o componente de data como ${BASH_REMATCH[1]} e o componente de tempo como ${BASH_REMATCH[2]} .

    
por 14.10.2017 / 23:27
3

Parece que as fugas \ da \ e \ s não funcionam na sua versão do bash. Tente usar [[:digit:]] e [[: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)

Em ação:

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
    
por 14.10.2017 / 23:39
2

Este trecho no arquivo 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"

produz:

-----
 Expected output:
1484085600

-----
 Results:
1484085600

Em um sistema como:

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

O código dateconv (aka dconv, dateutils.dconv) faz parte do pacote dateutils disponível via brew - alguns detalhes para 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 ...)

Felicidades ... felicidades, drl

    
por 17.10.2017 / 19:17