Di bash, bagaimana cara mengurutkan string dengan angka di dalamnya?

37

Jika saya memiliki file-file ini di direktori

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

bagaimana saya bisa mendaftar mereka di Bash sehingga mereka dalam urutan numerik naik berdasarkan bagian nomor dari string. Jadi pesanan yang dihasilkan adalah cwcch1.pdf, cwcch2.pdf, ..., cwcch9.pdf, cwcch10.pdf, dll.

Apa yang akhirnya saya coba lakukan adalah menggabungkan pdf pdftkdengan sesuatu seperti berikut ini

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

tapi itu tidak berhasil karena pengurutan saya salah.

ngm
sumber
Terima kasih atas semua jawaban bagus untuk ini. Seperti biasa dengan Unix, ada banyak cara bagus untuk menguliti kucing ini.
ngm
stackoverflow.com/questions/13088370/sort-numerically
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件

Jawaban:

7

Sesuatu seperti ini mungkin melakukan apa yang Anda inginkan, meskipun dibutuhkan pendekatan yang sedikit berbeda:

pdftk $(for n in {1..18}; do echo cwcch$n.pdf; done) cat output output.pdf
retracile
sumber
Aha, pendekatan yang bagus! Memang melakukan apa yang saya apa, terima kasih.
ngm
62

Anda sortmungkin memiliki kemampuan untuk melakukan ini untuk Anda:

sort --version-sort
Dijeda sampai pemberitahuan lebih lanjut.
sumber
Kutipan dari entri yang relevan di halaman man sort: -V, --version-sort natural sort of (version) numbers within text
panmari
Ini yang kamu butuhkan. Tetapi jika jenis Anda tidak menyediakan opsi ini, lihat posting ini: stackoverflow.com/a/4495368/1240018
eventhorizon
30

Untuk contoh khusus ini Anda juga bisa melakukan ini:

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

Yaitu, urutkan secara numerik (-n) pada bidang kedua (-k2) menggunakan 'h' sebagai pemisah bidang (-th).

larsks
sumber
Memisahkan dan kemudian menyortir pada satu bidang - itu tip yang bagus yang saya yakin akan berguna di masa depan, terima kasih.
ngm
6

Anda dapat menggunakan -vopsi dalam GNU ls: semacam sortir (versi) angka dalam teks.

ls -1v cwcch*

Ini tidak bekerja dengan BSD ls(misalnya pada OS X), di mana -vopsi memiliki arti yang berbeda.

Ashutosh Vishwa Bandhu
sumber
Ini adalah solusi yang paling sederhana, butuh lebih banyak orang upvotes!
davidparks21
2

Gunakan ekspansi shell secara langsung di commandline. Perluasan harus memesannya dengan benar. Jika saya memahami pdftksintaks baris perintah dengan benar, ini akan melakukan apa yang Anda inginkan:

# 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

Atau Anda dapat mencoba pendekatan yang berbeda. Ketika saya perlu melakukan sesuatu seperti ini, saya biasanya mencoba untuk mendapatkan nomor saya diformat dengan benar sebelumnya. Jika saya datang terlambat dan PDF sudah diberi nomor seperti contoh Anda, saya akan menggunakan ini untuk memberi nomor baru:

# 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

Sekarang lspenyortiran standar akan berfungsi dengan baik.

quack quixote
sumber
2
Mungkin sedikit lebih ringkas:pdftk cwcch{{1..9},{10..18}}.pdf ...
Dijeda sampai pemberitahuan lebih lanjut.
Tip yang baik, ditambahkan. Apakah itu sintaks ekspansi shell Bourne standar atau bashekstensi?
quack quixote,
2

Berikut metode yang hanya menggunakan sortir:

ls | sort -k1.6n
Scot
sumber
0

Sortir -g digunakan untuk mengurutkan angka dalam urutan menaik.

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


Satu liner berikut ini mengulangi file dengan nama file PDF dan mengambil angka hanya dengan egrep -o dan menggunakan sort -g untuk mengurutkan angka dalam urutan menaik . Kemudian ia memberi makan angka-angka ini ke sed dan colokkan mereka. Kemudian rids output duplikat dengan uniq.


Di tempat uniq, Anda juga dapat menggunakan awk:

awk '!x[$0]++'

Di atas setara dengan uniq.


Apa yang Anda cari adalah liner satu ini :

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


Isi 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 

EDIT:

Output dari perintah:

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
sumber
Apakah liner yang satu ini berfungsi pada tmpfile? Adakah keluaran untuk ditempel ke dalam jawaban?
Xen2050
Iya nih. Saya memasukkan output dalam OP saya di bawah bagian edit.
Aguevara