Como ordenar os arquivos por parte do nome do arquivo?

7

Dados os arquivos abaixo:

ABC38388.SC01.StatueGrade_MKP
ABC38388.SC02.Statue_GKP
DEF38389.SC03.Statue_HKP
XYZ38390.SC00.Statue_WKP

Como posso listar todos eles com base no valor SC , assim:

XYZ38390.SC00.Statue_WKP
ABC38388.SC01.StatueGrade_MKP
ABC38388.SC02.Statue_GKP
DEF38389.SC03.Statue_HKP
    
por MRKR 09.12.2015 / 17:01

4 respostas

7

Neste caso em particular, onde os nomes dos seus arquivos não contêm nenhum espaço em branco ou outros caracteres estranhos, você pode usar ls e canalizá-lo através de sort :

$ ls -d -- *.SC* | sort -t. -k2
XYZ38390.SC00.Statue_WKP
ABC38388.SC01.StatueGrade_MKP
ABC38388.SC02.Statue_GKP
DEF38389.SC03.Statue_HKP

O -t define o delimitador de campo e o -k2 diz sort para classificar com base na parte da linha que começa com o campo 2 nd (use -k2,2 para o segundo campo somente ).

Para casos mais complexos, você poderia imprimir cada nome de arquivo seguido pelo caractere NULL ( sort ), então canalizar para GNU -z usando sua opção tr para dizer a ele ler linhas delimitadas por NULL e, finalmente , use \n para alterar o %code% de volta para %code% :

printf '%s
$ ls -d -- *.SC* | sort -t. -k2
XYZ38390.SC00.Statue_WKP
ABC38388.SC01.StatueGrade_MKP
ABC38388.SC02.Statue_GKP
DEF38389.SC03.Statue_HKP
' *SC* | sort -zt. -k2 | tr '
printf '%s%pre%' *SC* | sort -zt. -k2 | tr '%pre%' '\n'
' '\n'
    
por 09.12.2015 / 17:26
4

Com o zsh, você pode definir sua própria ordem de classificação para globs com os qualificadores oe ou o+ glob:

ls -lUd -- *(oe['REPLY=${REPLY#*.SC}'])

ou:

bysc() REPLY=${REPLY#*.SC}
ls -lUd -- *(o+bysc)

A função de classificação recebe o nome do arquivo em $REPLY e destina-se a retornar uma string em $REPLY em que a globalização será classificada. Aqui, retornamos a parte do nome do arquivo à direita da primeira ocorrência de .SC (ou o nome completo do arquivo, se não contiver .SC ).

    
por 09.12.2015 / 18:00
1

Em um sistema GNU e com zsh ou bash como seu shell, use isto:

find -maxdepth 1 -type f -print0 | sort -z -t. -k3 | \
while IFS="" read -r -d "" f; do
  basename "$f"
done
  • find procura os arquivos no diretório atual ( -maxdepth 1 ) e os imprime delimitado por nulo ( -print0 ).
  • sort lê sua entrada delimitada por byte nulo ( -z ) e ordena a parte do registro que inicia no terceiro campo ( -k3 ) separado por um ponto ( -t. ).
  • while lê a entrada
    • e basename imprime seu nome sem caminho
por 09.12.2015 / 17:27
0

Eu gostaria, como sempre faço, sugerir perl .

perl tem uma função de classificação que permite especificar uma função de comparação. Essa função de comparação é qualquer teste que recebe dois valores e retorna -1 , 0 ou 1 dependendo da posição relativa.

Ele itera a lista definindo cada valor como $a e $b e 'fazendo o teste' para cada elemento.

Então, por padrão:

$a cmp $b 

para comparação com strings, ou sort { $a <=> $b } para numérico.

Mas, como resultado, você pode aplicar critérios de classificação personalizados arbitrariamente complexos:

#!/usr/bin/perl
use strict;
use warnings;

sub sort_by_sc {
   my ( $a_sc ) = $a =~ m/SC(\d+)/;
   my ( $b_sc ) = $b =~ m/SC(\d+)/;
   return $a_sc <=> $b_sc;
}


my @file_list = qw ( 
    ABC38388.SC01.StatueGrade_MKP
    ABC38388.SC02.Statue_GKP
    DEF38389.SC03.Statue_HKP
    XYZ38390.SC00.Statue_WKP
);

print sort sort_by_sc @file_list;

Ou reduzido a um liner, lendo STDIN ou um arquivo (delimitado por alimentação de linha, o que geralmente é bom o suficiente):

perl -e 'print sort {@x = map {/SC(\d+)/}($a,$b); $x[0] <=> $x[1]} <>'

Você poderia, em vez disso, fornecer o resultado de glob de um padrão de diretório:

perl -e 'print sort {@x = map {/SC(\d+)/}($a,$b); $x[0] <=> $x[1]} glob ( "*SC*")'
    
por 09.12.2015 / 20:33