Arquivos de classificação de linha de comando ou diretórios por parte de seus nomes

3

Como classifico arquivos ou diretórios por parte de seu nome, especificamente o elemento contido nos parênteses ou separado por um delimitador?

Estou atrás de duas soluções separadas, uma para diretórios com nomes estruturados assim:

Badger Bodger (2001)
Charlie Fisher's (1989)

E arquivos no seguinte formato:

Could Be A Title.2001.prop.ext1
Another Potential Title.1989.prop.ext2

Em ambos os casos, os diretórios ou arquivos com 1989 devem vir antes de 2001. Para os diretórios, o elemento a ser classificado está entre colchetes. Para os arquivos, é o primeiro número de quatro dígitos após o delimitador . .

Estou usando o bash rodando no Debian 8.0. Procurando por soluções de linha de comando, por favor. Scripts curtos, se escritos em bash aceitável.

    
por fswings 29.04.2015 / 02:03

2 respostas

1

Considere estes arquivos:

$ ls  --quoting-style=c -1 *.*
"Another Potential Title.1989.prop.ext2"
"being there.2000.prop.ext3"
"Could Be A Title.2001.prop.ext1"
"Yet Another Potential Title.1989.prop.ext2"

Isso classifica no ano:

$ ls  --quoting-style=c *.* | sort -t. -k2n
"Another Potential Title.1989.prop.ext2"
"Yet Another Potential Title.1989.prop.ext2"
"being there.2000.prop.ext3"
"Could Be A Title.2001.prop.ext1"

Para seus diretórios, uma abordagem semelhante funciona:

$ ls --quoting-style=c -d */ | sort -t'(' -k2n
"Charlie Fisher's (1989)/"
"Badger Bodger (2001)/"

Por causa da opção --quoting-style=c , essa abordagem funcionará mesmo com nomes de arquivos com novas linhas ou outros caracteres difíceis. Se você tiver certeza de que seus nomes de arquivo não contêm novas linhas, você pode omitir essa opção.

Como funciona

sort pode dividir as linhas de entrada nos campos. A opção -t define o separador de campo. Para os arquivos, o separador de campos é um . enquanto para diretórios um separador de campo de ( é usado. A opção -k determina qual campo é classificado. Para ambos os casos acima, pedimos que sort ordene numericamente no segundo campo.

    
por 29.04.2015 / 02:30
1

Suponho que você tenha certeza de que nenhum dos seus nomes de arquivo contém novas linhas, ou que você tenha alguma maneira de lidar com essa possibilidade. Primeiro, manipule seus nomes de arquivos com sed :

% command_to_list_filenames | sed 's/.*\.\([0-9][0-9][0-9][0-9]\)\..*/.&/'
2001.Could Be A Title.2001.prop.ext1
1989.Another Potential Title.1989.prop.ext2
%

O comando s (substitute) no comando sed trata cada linha como uma sequência do seguinte:

  • Qualquer número de qualquer caractere ( .* ),
  • Um período real ( \. ),
  • Quatro dígitos ( [0-9][0-9][0-9][0-9] ),
  • Outro período real ( \. ) e
  • Outra sequência de caracteres ( .* ).

Observe que o ano ( [0-9][0-9][0-9][0-9] ) é incluído entre \( e \) , formando um grupo. O comando substituto substitui a string por

  • Os caracteres agrupados, ou seja, o ano ( ),
  • Um período ( . ) e
  • A linha de entrada inteira ( & ).

Então, é uma questão simples de classificar as linhas até o ano (que agora aparece no começo da linha) e tirando o ano:

% command_to_list_filenames | sed 's/.*\.\([0-9][0-9][0-9][0-9]\)\..*/.&/' | sort
1989.Another Potential Title.1989.prop.ext2
2001.Could Be A Title.2001.prop.ext1
% command_to_list_filenames | sed 's/.*\.\([0-9][0-9][0-9][0-9]\)\..*/.&/' | sort |
                                                            sed 's/^[0-9][0-9][0-9][0-9].//'
Another Potential Title.1989.prop.ext2
Could Be A Title.2001.prop.ext1
%

O comando sed pode ser modificado para lidar com o outro padrão. E sed pode receber entrada de um arquivo em vez de um canal:

% sed 's/.*(\([0-9][0-9][0-9][0-9]\)).*/.&/' list_of_directory_names | sort |
                                                            sed 's/^[0-9][0-9][0-9][0-9].//'
Charlie Fisher's (1989)
Badger Bodger (2001)
%

Observe que isso funciona bem com texto que contém pontos ou parênteses, por exemplo,

Dr. Strangelove.1964.foo
Mrs. Doubtfire.1993.bar

desde que não sejam seguidos por números de quatro dígitos.

Você pode deixar o segundo .* se quiser:

% command_to_list_filenames | sed 's/.*\.\([0-9][0-9][0-9][0-9]\)\./.&/'
2001.Could Be A Title.2001.prop.ext1
1989.Another Potential Title.1989.prop.ext2
%
    
por 29.04.2015 / 04:24