No bash, como classificar strings com números?

37

Se eu tiver esses arquivos em um diretório

cwcch10.pdf
cwcch11.pdf
cwcch12.pdf
cwcch13.pdf
cwcch14.pdf
cwcch15.pdf
cwcch16.pdf
cwcch17.pdf
cwcch18.pdf
cwcch1.pdf
cwcch2.pdf
cwcch3.pdf
cwcch4.pdf
cwcch5.pdf
cwcch6.pdf
cwcch7.pdf
cwcch8.pdf
cwcch9.pdf

como posso listá-los no Bash para que eles estejam em ordem numérica crescente com base na parte numérica da string. Portanto, a ordem resultante é cwcch1.pdf, cwcch2.pdf, ..., cwcch9.pdf, cwcch10.pdfetc.

No final, estou tentando concatenar os PDFs pdftkcom algo como o seguinte

pdftk `ls *.pdf | sort -n` cat output output.pdf

mas isso não funciona, pois minha classificação está errada.

ngm
fonte
Obrigado por todas as ótimas respostas para isso. Como sempre no Unix, existem várias maneiras excelentes de esfolar esse gato.
ngm
stackoverflow.com/questions/13088370/sort-numerically
Ciro Santilli新疆改造中心法轮功六四事件

Respostas:

7

Algo assim pode fazer o que você deseja, embora seja necessário uma abordagem um pouco diferente:

pdftk $(for n in {1..18}; do echo cwcch$n.pdf; done) cat output output.pdf
retrátil
fonte
Ah, boa abordagem! Realmente faz o que eu o que, obrigado.
ngm
62

Você sortpode ter a capacidade de fazer isso por você:

sort --version-sort
Pausado até novo aviso.
fonte
Trecho de entrada relevante na página de manual de classificação: -V, --version-sort natural sort of (version) numbers within text
panmari 14/01
Isto é o que você precisa. Mas se o seu tipo não fornecer essa opção dar uma olhada neste post: stackoverflow.com/a/4495368/1240018
EventHorizon
30

Para este exemplo em particular, você também pode fazer isso:

ls *.pdf | sort -k2 -th -n

Ou seja, classifique numericamente (-n) no segundo campo (-k2) usando 'h' como o separador de campos (-th).

larsks
fonte
Dividir e classificar em um campo - é uma ótima dica que, com certeza, será útil no futuro, obrigado.
ngm
6

Você pode usar a -vopção no GNU ls: tipo natural de (versão) números dentro do texto.

ls -1v cwcch*

Isso não funciona com o BSD ls(por exemplo, no OS X), onde a -vopção tem um significado diferente.

Ashutosh Vishwa Bandhu
fonte
Esta é a solução mais simples, ela precisa de mais votos positivos!
davidparks21
2

Use a expansão do shell diretamente em uma linha de comando. A expansão deve ordená-los corretamente. Se eu entendo pdftka sintaxe da linha de comando corretamente, isso fará o que você deseja:

# shell expansion with square brackets
pdftk cwcch[1-9].pdf cwcch1[0-9].pdf cat output output.pdf

# shell expansion with curly braces
pdftk cwcch{{1..9},{10..18}}.pdf cat output output.pdf

Ou você pode tentar uma abordagem diferente. Quando preciso fazer algo assim, geralmente tento meus números formatados corretamente com antecedência. Se eu chegar atrasado e os PDFs já estiverem numerados como o seu exemplo, usarei isso para renumerar:

# rename is rename.pl aka prename -- perl rename script
# this adds a leading zero to single-digit numbers
rename 's/(\d)/0$1/' cwcch[1-9].pdf

Agora a lsclassificação padrão funcionará corretamente.

charlatão quixote
fonte
2
Talvez um pouco mais sucintamente:pdftk cwcch{{1..9},{10..18}}.pdf ...
Pausado até novo aviso.
boa dica, acrescentou. É uma sintaxe de expansão de shell Bourne padrão ou uma bashextensão?
quack quixote
2

Aqui está um método apenas usando sort:

ls | sort -k1.6n
Scot
fonte
0

Classificar -g é usado para classificar números em ordem crescente.

anthony@mtt3:~$ sort --help | egrep "\-g"
-g, --general-numeric-sort  compare according to general numerical value


O liner a seguir itera sobre um arquivo com os nomes dos arquivos PDF e captura os números apenas com egrep -o e usa sort -g para classificar os números em ordem crescente . Em seguida, ele alimenta esses números para sed e os conecta. Em seguida, libera a saída de duplicatas com uniq.


No lugar do uniq, você também pode usar o awk:

awk '!x[$0]++'

O acima é equivalente a uniq.


O que você está procurando é este liner:

for i in `cat tmp | egrep -o "[0-9]*" | sort -g`; do cat tmp | sed "s/\(^[a-z]*\)\([0-9]*\)\(\.pdf\)/\1$i\3/g" | uniq; done


Conteúdo do tmp:

anthony@mtt3:~$ cat tmp
cwcch10.pdf
cwcch11.pdf
cwcch12.pdf
cwcch13.pdf
cwcch14.pdf
cwcch15.pdf
cwcch16.pdf
cwcch17.pdf
cwcch18.pdf
cwcch1.pdf
cwcch2.pdf
cwcch3.pdf
cwcch4.pdf
cwcch5.pdf
cwcch6.pdf
cwcch7.pdf
cwcch8.pdf
cwcch9.pdf 

EDITAR:

Saída do comando:

anthony@mtt3:~$ for i in `cat tmp | egrep -o "[0-9]*" | sort -g`; do cat tmp | sed "s/\(^[a-z]*\)\([0-9]*\)\(\.pdf\)/\1$i\3/g" | uniq; done

cwcch1.pdf
cwcch2.pdf
cwcch3.pdf
cwcch4.pdf
cwcch5.pdf
cwcch6.pdf
cwcch7.pdf
cwcch8.pdf
cwcch9.pdf
cwcch10.pdf
cwcch11.pdf
cwcch12.pdf
cwcch13.pdf
cwcch14.pdf
cwcch15.pdf
cwcch16.pdf
cwcch17.pdf
cwcch18.pdf
Aguevara
fonte
Será que este trabalho um forro sobre o tmparquivo? Alguma saída para colar na resposta?
Xen2050 30/11/2015
Sim. Incluí a saída no meu OP na seção de edição.
Aguevara 30/11/2015