Encontre o arquivo com o menor número de 4 dígitos

1

Eu tenho muitos, muitos arquivos no formato [a-zA-Z]+\d\.\d{2}\_\d.\d{4}.end e quero encontrar o (s) arquivo (s) com o menor número de 4 dígitos logo antes de .end . (em caso de colisão quero todos os arquivos)

Como você pode fazer isso usando o Bash? sort sozinho não funciona, obviamente, devido à ordenação lexicográfica.

    
por NaCl 16.03.2017 / 12:44

4 respostas

1

Usando o Bash, find e as opções sort -t|--field-separator e -k|--key :

find_files.sh :

#!/bin/bash
first_file=$(find . -iname '*.end' | sort -t '.' -k 4.1 | head -1)
IFS='.'
fields=($first_file)
unset IFS
find . -iname "*${fields[3]}.end"

As opções -k|--key esperam um KEYDEF da forma field_number . character_number . Quando -t|--field-separator está em vigor, os números dos campos são calculados com base no separador especificado (nesse caso, . ), em vez de em um espaço em branco.

Em seguida, extraímos o padrão desejado do primeiro arquivo usando o separador de campos de entrada do Bash e pesquisamos o diretório com find novamente para arquivos correspondentes a esse padrão, no caso de vários arquivos compartilharem o mesmo número de 4 dígitos.

Exemplo:

$ ls -1
abc0.03_1.1921.end
def0.03_9.0311.end
ghi0.03_1.1966.end
jkl1.04_1.1916.end
mno2.04_4.9540.end
pab9.04_1.1994.end
uvx7.04_3.2002.end
yyy1.05_8.0311.end
zzz4.04_1.2097.end
$ ./find_files.sh
./yyy1.05_8.0311.end
./def0.03_9.0311.end
    
por 16.03.2017 / 13:51
2

Com as ferramentas do GNU, você pode fazer algo como:

find . -regextype posix-extended \
  -regex '.*/[a-zA-Z]+[0-9]\.[0-9]{2}_[0-9]\.[0-9]{4}\.end' -print0 |
  awk -v RS='
find . -regextype posix-extended \
  -regex '.*/[a-zA-Z]+[0-9]\.[0-9]{2}_[0-9]\.[0-9]{4}\.end' -print0 |
  awk -v RS='%pre%' -F . '
    NR == 1 || $(NF-1) < min {files=$0; min = $(NF-1); next}
    $(NF-1) == min {files = files "\n" $0}
    END {if (NR) print files}'
' -F . ' NR == 1 || $(NF-1) < min {files=$0; min = $(NF-1); next} $(NF-1) == min {files = files "\n" $0} END {if (NR) print files}'

Esse é um exemplo de um padrão comum: imprimimos a lista de arquivos correspondentes delimitados por NUL (como NUL é o único caractere que não pode ocorrer em um caminho de arquivo) e processamos essa saída com awk onde o separador de registro foi definido como NUL (nem todas as implementações de awk suportam isso).

O separador de campos está definido para . . NF é o número de campos, então $(NF-1) é o último antes do último campo. awk encontra o menor número comparando com o último valor conhecido e armazena os arquivos correspondentes na variável files awk .

À medida que armazenamos a lista separada por nova linha em oposição a NUL separado, isso é destinado apenas à saída do usuário. Se você quisesse pós-processá-lo de maneira confiável, você desejaria usar NUL ( "%code%" no awk).

    
por 16.03.2017 / 13:34
1

sort tem -t e -k , o que permite classificar com base em uma das partes separadas por pontos do nome do arquivo, o que deve ser feito nesse caso.

-t, --field-separator=SEP
    use SEP instead of non-blank to blank transition

-k, --key=KEYDEF
    sort via a key; KEYDEF gives location and type

(citação de a página man do tipo GNU .)

    
por 16.03.2017 / 12:48
0
perl -le '
   for ( grep { /^[a-zA-Z]+\d\.\d{2}\_\d.\d{4}\.end$/ } <*.end> ) {
      ($n) = /(\d{4})\.end$/;
      $min //= $n;
      $n <= $min and $min = $n, push @{$h{$min}}, $_;
   }
   print for @{$h{$min}};
'

<*> coleta todos os arquivos relevantes usando a sintaxe globbing, dos quais, os arquivos de sintaxe apropriados devem ser selecionados pelo for .

Dentro do for primeiro extraimos os últimos 4 dígitos para determinar & compare-o com o minimum em execução e, se encontrado, empurrado para um hash.

No final, simplesmente imprimimos o conteúdo do hash com a chave $min .

    
por 17.03.2017 / 10:47