
Estou tentando obter o mês de 2 dígitos e o ano de 2 dígitos em que um arquivo foi modificado, mas não está funcionando.
modified=$(stat -c %y "$line");
# modified="2018-08-22 14:39:36.400469308 -0400"
if [[ $modified =~ ".{2}(\d{2})-(\d{2})" ]]; then
echo ${BASH_REMATCH[0]}
echo ${BASH_REMATCH[1]
fi
- Demonstração do Bash:http://rextester.com/DJSPH52792
- Demonstração RegEx:https://regex101.com/r/UEOlMO/1
O que estou fazendo de errado?
Responder1
Primeiro, as aspas suprimem o significado dos caracteres especiais na regex (manual on-line):
Um operador binário adicional,
=~
, está disponível, ... Qualquer parte do padrão pode ser citada para forçar a correspondência da parte citada como uma string. ... Se você deseja corresponder um caractere especial à gramática da expressão regular, ele deve ser colocado entre aspas para remover seu significado especial.
O manual continua recomendando colocar o regex em uma variável para evitar alguns conflitos entre a análise do shell e a sintaxe do regex.
Segundo, \d
não faz o que você pensa, mas apenas corresponde a um literal d
.
Observe também que ${BASH_REMATCH[0]}
contém toda a string correspondente e os índices 1
e acima contêm os grupos capturados.
Eu também sugiro fortemente o uso de anos de quatro dígitos, então:
modified=$(stat -c %y "$file")
re='^([0-9]{4})-([0-9]{2})'
if [[ $modified =~ $re ]]; then
echo "year: ${BASH_REMATCH[1]}"
echo "month: ${BASH_REMATCH[2]}"
else
echo "invalid timestamp"
fi
Para um arquivo modificado hoje, isso dá year: 2018
e month: 08
. Observe que os números com zero à esquerda serão considerados octais pelo shell e possivelmente por outros utilitários.
(Anos de quatro dígitos apresentam menos problemas se você precisar lidar com datas de 1900, e são mais fáceis de reconhecer como anos e não como dias do mês.)
Responder2
Não precisa de expressões regulares para isso:
$ touch -t 197001010000 myfile
$ ls -l myfile
-rw-rw-r-- 1 jackman jackman 0 Jan 1 1970 myfile
$ IFS='-' read -r year month _rest < <(stat -c %y myfile)
$ echo "$year:${year#??}"$month"
1970:70:01
Responder3
Como alternativa, com GNU date
, você pode fazer:
eval "$(date -r "$file" +'year=%Y month=%-m day=%-d')"
Para ter o componente ano, mês e dia da hora de modificação armazenado em e $year
, respectivamente (como números inteiros decimais, remova o s em e se você se importa com os zeros à esquerda; consulte também para anos de 2 dígitos).$month
$day
-
%-m
%-d
%y
(observe que, ao contrário do GNU stat
, para arquivos do tipo link simbólico, o tempo de modificação do destino do link simbólico é considerado e não o do próprio link simbólico. Com GNU stat
, você usaria stat -L
).