W bash, jak sortować ciągi znaków z liczbami?

37

Jeśli mam te pliki w katalogu

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

jak mogę wyświetlić je w Bash, aby były w porządku rosnącym numerycznie w oparciu o część liczbową ciągu? Tak więc wynikowa kolejność jest cwcch1.pdf, cwcch2.pdf, ..., cwcch9.pdf, cwcch10.pdfitd.

To, co ostatecznie próbuję zrobić, to połączyć pliki PDF pdftkz czymś takim, jak poniżej

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

ale to nie działa, ponieważ moje sortowanie jest nieprawidłowe.

ngm
źródło
Dzięki za wszystkie świetne odpowiedzi na to. Jak zawsze w przypadku Uniksa, istnieje wiele różnych doskonałych sposobów na skórowanie tego kota.
ngm
stackoverflow.com/questions/13088370/sort-numerically
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件

Odpowiedzi:

7

Coś takiego może zrobić to, co chcesz, choć ma nieco inne podejście:

pdftk $(for n in {1..18}; do echo cwcch$n.pdf; done) cat output output.pdf
retracile
źródło
Aha, fajne podejście! Rzeczywiście robi to, co ja, dzięki.
ngm
62

Twoja sortmoże mieć możliwość zrobić to za Ciebie:

sort --version-sort
Wstrzymano do odwołania.
źródło
Fragment odpowiedniego wpisu na stronie -V, --version-sort natural sort of (version) numbers within text
podręcznika
Właśnie tego potrzebujesz. Ale jeśli twój rodzaj nie zapewnia tej opcji, spójrz na ten post: stackoverflow.com/a/4495368/1240018
eventhorizon
30

W tym konkretnym przykładzie możesz również to zrobić:

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

Oznacza to, że sortuj numerycznie (-n) na drugim polu (-k2), używając „h” jako separatora pól (-th).

Larsks
źródło
Dzielenie, a następnie sortowanie według jednego pola - to świetna wskazówka, która na pewno przyda się w przyszłości, dzięki.
ngm
6

Możesz użyć -vopcji w GNU ls: naturalny rodzaj (wersji) liczb w tekście.

ls -1v cwcch*

Nie działa to z BSD ls(np. W OS X), gdzie -vopcja ma inne znaczenie.

Ashutosh Vishwa Bandhu
źródło
To najprostsze rozwiązanie, potrzebuje więcej pozytywnych opinii!
davidparks21
2

Użyj rozszerzenia powłoki bezpośrednio w wierszu polecenia. Rozszerzenie powinno porządkować je poprawnie. Jeśli dobrze rozumiem pdftkskładnię wiersza poleceń, zrobi to, co chcesz:

# 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

Lub możesz spróbować innego podejścia. Kiedy muszę zrobić coś takiego, zwykle staram się odpowiednio sformatować swoje liczby przed czasem. Jeśli się spóźnię, a pliki PDF są już ponumerowane jak twój przykład, użyję tego do zmiany numeracji:

# 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

Teraz standardowe lssortowanie będzie działać poprawnie.

quack quixote
źródło
2
Być może nieco bardziej zwięźle:pdftk cwcch{{1..9},{10..18}}.pdf ...
Wstrzymano do odwołania.
dobra wskazówka, dodane. czy to standardowa składnia rozszerzenia powłoki Bourne'a czy bashrozszerzenie?
quack quixote
2

Oto metoda wykorzystująca sortowanie:

ls | sort -k1.6n
Szkot
źródło
0

Sortuj -g służy do sortowania liczb w porządku rosnącym.

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


Poniższa linijka iteruje plik z nazwami plików PDF i pobiera liczby tylko za pomocą egrep -o i używa sort -g do sortowania liczb w porządku rosnącym . Następnie podaje te liczby do sed i podłącza je. Następnie usuwa dane wyjściowe duplikatów z uniq.


Zamiast uniq możesz także użyć awk:

awk '!x[$0]++'

Powyższe jest równoważne z uniq.


To, czego szukasz, to jedna wkładka:

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


Zawartość 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 

EDYTOWAĆ:

Wyjście polecenia:

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
źródło
Czy ten jeden liner działa na tmppliku? Jakieś dane wyjściowe do wklejenia w odpowiedzi?
Xen2050,
Tak. Uwzględniłem wyniki w moim OP w sekcji edycji.
Aguevara,