Combinando apenas extensões de arquivo numérico

2

Estou tentando encontrar um padrão UNIX que corresponda apenas a extensões numéricas. Por exemplo, ele corresponderá a

  • arquivo.1
  • arquivo.2
  • arquivo1.1
  • 5file2.52
  • arquivo.25938

mas NÃO corresponderá

  • file1.0.ext
  • file4.csv
  • 6file5.5.2.ext
  • file.1s
  • arquivo.s134

Eu achei que seria fácil, mas parece que não consigo - tentei

  • *. [0-9] * que corresponde ao arquivo1.0.csv
  • *. [0.9] * / > que não corresponde a nada

Algum especialista sabe o que me falta? Eu pensei / > combinado no final de uma palavra.

edit - clarification: Eu estou codificando em python usando um módulo que usa curingas unix estilo shell, então eu só tenho acesso aos ditos wildcards

    
por Nate 16.09.2016 / 17:14

5 respostas

2

com zsh :

echo file.<->

<-> sendo uma forma especial de <x-y> como <1-100> , mas que corresponde a qualquer número inteiro decimal positivo sem restrição (qualquer sequência não vazia de dígitos decimais). Ou com a opção extendedglob :

echo file.[0-9]##

## sendo o equivalente do operador de expressão regular estendida + .

Com ksh ou bash -O extglob (ou depois de shopt -s extglob dentro de bash ) ou zsh -o kshglob (ou depois de setopt kshglob dentro de zsh ):

echo file.+([0-9])

Novamente, +(x) é igual a ERE x+ .

ksh93 também pode usar EREs em seu glob com:

echo ~(E).*\.[0-9]+$

(o .* não é estritamente necessário aqui, é apenas que sem ele, ~(E)\.[0-9]+$ também corresponderia a arquivos ocultos)

Os globs padrão não têm um equivalente. Tudo o que eles têm são:

  • * para corresponder a qualquer número de caracteres
  • ? para corresponder a qualquer caractere único
  • [criteria] para corresponder a um caracter que corresponda aos critérios .

você precisaria filtrar a lista como:

set -- *.*[0-9]
for i do
  case ${i##*.} in
    (*[!0-9]*) ;;
    (*) set -- "$@" "$i"
  esac
  shift
done
echo "$@"

Ou seja, da lista de nomes de arquivos que contêm . e terminam com um dígito, exclua aqueles em que a parte após o último . contenha um não dígito.

    
por 16.09.2016 / 17:18
1

No bash (se $f contiver o nome do arquivo a ser verificado):

[[ "${f##*.}"  == +([0-9]) ]] && echo "Yes" || echo "No"

Onde "${f##*.}" seleciona a última extensão (após o último ponto),
e +([0-9]) é uma regex estendida para corresponder apenas a números.

Um exemplo de script para processar uma lista de nomes de arquivos (dentro de infile ) pode ser:

#!/bin/bash
while read f; do
    printf 'file %-15s ----> %7s ==> ' "$f" "${f##*.}"
    if     [[ "${f##*.}"  == +([0-9]) ]]
    then   echo "Yes"
    else   echo "No"
    fi
done <"infile"

Quais resultados:

file file.1          ---->       1 ==> Yes
file file.2          ---->       2 ==> Yes
file file1.1         ---->       1 ==> Yes
file 5file2.52       ---->      52 ==> Yes
file file.25938      ---->   25938 ==> Yes
file NOT             ---->     NOT ==> No
file file1.0.ext     ---->     ext ==> No
file file4.csv       ---->     csv ==> No
file 6file5.5.2.ext  ---->     ext ==> No
file file.1s         ---->      1s ==> No

O principal obstáculo a ser superado com shells mais simples (UNIX) é encontrar utilitários que entendam e executem regex (Extended).

Você pode tentar com "Regex estendido" em sed :

[ "$(echo "${f##*.}" | sed -nE 's/^([0-9]+)$//p')" ] && echo "Yes" || echo "No"

ou "Basic Regex", também em sed:

[ "$(echo "${f##*.}" | sed -n 's/^\([0-9]\{1,\}\)$//p')" ] && echo "Yes" || echo "No"

ou expr (talvez seja necessário alterar \+ para \{1,\} no Solaris e outros):

expr "${f##*.}" : '^\([0-9]\+\)$' >/dev/null && echo "Yes" || echo "No"

ou até awk :

[ $( echo "${f##*.}" | awk '/^[0-9]+$/' ) ] && echo "Yes" || echo "No"
    
por 18.09.2016 / 01:22
0

O módulo python fnmatch que você deseja usar converte um determinado argumento de tipo "glob" de arquivo para um regex python (re), mas ele não lida com o operador '+' da maneira que eu esperava: ele parece ter escapado pelo re.escape () (olhando a fonte para fnmatch no python 2.6 no meu sistema)

Consequentemente,

fnmatch.filter(['file.007'], '*.[0-9]+')

não funciona como seria de esperar, embora

fnmatch.filter(['file.7'], '*.[0-9]')

dá uma correspondência.

Similarmente

 fnmatch.filter(['file.007'], '*.[0-9]{1,}')

não é bom.

    
por 16.09.2016 / 18:50
0

Isso não pode ser feito diretamente com globbing de nome de arquivo padrão. No entanto, você pode testar a extensão separadamente:

Supondo que você queira testar um nome de arquivo em uma variável:

case ${filename##*.} in
    *[!0-9]*) echo 'This is not the filename you are looking for' ;;
    *[0-9]*)  echo 'This is the file!'
esac

Isso primeiro retira tudo, desde o início do nome do arquivo até o último ponto, deixando apenas o bit de extensão. Em seguida, ele tenta corresponder essa cadeia (possivelmente vazia) com o padrão de glob *[!0-9]* , que será bem-sucedido se a sequência contiver um não-dígito. O segundo teste é apenas para ter certeza de que realmente temos um dígito e não apenas uma string vazia na extensão.

Em seu código Python, você pode primeiro gerar uma lista completa de todos os arquivos, pegar esses nomes e remover o bit antes da extensão, e então testar a extensão com *[!0-9]* , se você realmente precisa usar globbing.

Eu tenho a sensação de que existem maneiras mais eficientes de fazer isso no Python.

    
por 15.06.2018 / 08:51
-2

seus arquivos terminam com dígito, então use * [0-9]

    
por 15.06.2018 / 02:44