In bash, come ordinare le stringhe con i numeri in esse?


37

Se ho questi file in una directory

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

come posso elencarli in Bash in modo che siano in ordine numerico crescente in base alla parte numerica della stringa. Quindi l'ordine risultante è cwcch1.pdf, cwcch2.pdf, ..., cwcch9.pdf, cwcch10.pdf, ecc.

Quello che sto cercando di fare è concatenare i pdf pdftkcon qualcosa di simile al seguente

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

ma non funziona perché il mio ordinamento è sbagliato.


Grazie per tutte le ottime risposte a questo. Come sempre con Unix, ci sono molti modi eccellenti per scuoiare questo gatto.
ngm,

Risposte:


7

Qualcosa del genere potrebbe fare quello che vuoi, anche se adotta un approccio leggermente diverso:

pdftk $(for n in {1..18}; do echo cwcch$n.pdf; done) cat output output.pdf

Ah, bel approccio! Fa davvero quello che io, grazie.
ngm

60

Potresti sortavere la possibilità di farlo per te:

sort --version-sort

Estratto della voce pertinente nella pagina man di ordinamento: -V, --version-sort natural sort of (version) numbers within text
panmari

Questo è quello di cui hai bisogno. Ma se il vostro tipo non fornisce questa opzione dare un'occhiata a questo post: stackoverflow.com/a/4495368/1240018
eventhorizon

30

Per questo esempio particolare potresti anche fare questo:

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

Ossia, ordina numericamente (-n) sul secondo campo (-k2) usando 'h' come separatore di campo (-th).


Dividere e quindi ordinare su un campo: questo è un ottimo consiglio che sono sicuro che sarà utile in futuro, grazie.
ngm,

6

È possibile utilizzare l' -vopzione in GNU ls: ordinamento naturale di numeri (versione) all'interno del testo.

ls -1v cwcch*

Questo non funziona con BSD ls(ad es. Su OS X), dove l' -vopzione ha un significato diverso.


Questa è la soluzione più semplice, ha bisogno di più voti gente!
davidparks21

2

Utilizzare l'espansione della shell direttamente in una riga di comando. L'espansione dovrebbe ordinarli correttamente. Se capisco pdftkcorrettamente la sintassi della riga di comando, questo farà quello che vuoi:

# 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

Oppure puoi provare un approccio diverso. Quando devo fare una cosa del genere, di solito cerco di formattare i miei numeri in anticipo. Se ci arrivo tardi e i PDF sono già numerati come il tuo esempio, lo userò per rinumerare:

# 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

Ora l' lsordinamento standard funzionerà correttamente.


2
Forse un po 'più concisamente:pdftk cwcch{{1..9},{10..18}}.pdf ...
Dennis Williamson il

buon consiglio, aggiunto. È una sintassi di espansione della shell Bourne standard o bashun'estensione?
Quack Quixote il

2

Ecco un metodo che utilizza solo l'ordinamento:

ls | sort -k1.6n

0

Ordina -g è usato per ordinare i numeri in ordine crescente.

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


La seguente riga passa su un file con i nomi dei file PDF e prende i numeri solo con egrep -o e usa sort -g per ordinare i numeri in ordine crescente . Quindi alimenta questi numeri per sed e li collega. Quindi elimina l'output dei duplicati con uniq.


Al posto di uniq, puoi anche usare awk:

awk '!x[$0]++'

Quanto sopra equivale a uniq.


Quello che stai cercando è questa fodera:

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


Contenuto di 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 

MODIFICARE:

Uscita del 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

Fa questo lavoro uno di linea sulla tmplima? Qualche output da incollare nella risposta?
Xen2050,

Sì. Ho incluso l'output nel mio OP nella sezione modifica.
Aguevara,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.