En bash, ¿cómo ordenar cadenas con números en ellas?

37

Si tengo estos archivos en un directorio

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

¿Cómo puedo enumerarlos en Bash para que estén en orden numérico ascendente en función de la parte del número de la cadena. Entonces el orden resultante es cwcch1.pdf, cwcch2.pdf, ..., cwcch9.pdf, cwcch10.pdf, etc.

Lo que finalmente intento hacer es concatenar los archivos PDF pdftkcon algo como lo siguiente

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

pero eso no funciona ya que mi clasificación es incorrecta.

ngm
fuente
Gracias por todas las excelentes respuestas a esto. Como siempre con Unix, hay muchas maneras excelentes de desollar este gato.
ngm
stackoverflow.com/questions/13088370/sort-numerically
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件

Respuestas:

7

Algo como esto podría hacer lo que quieras, aunque tiene un enfoque ligeramente diferente:

pdftk $(for n in {1..18}; do echo cwcch$n.pdf; done) cat output output.pdf
retroceder
fuente
Ajá, buen enfoque! De hecho, hace lo que yo, gracias.
ngm
62

Es sortposible que tenga la capacidad de hacer esto por usted:

sort --version-sort
Pausado hasta nuevo aviso.
fuente
Extracto de la entrada relevante en la página de manual de clasificación: -V, --version-sort natural sort of (version) numbers within text
panmari
Esto es lo que necesitas. Pero si su orden no proporciona esta opción, eche un vistazo a esta publicación: stackoverflow.com/a/4495368/1240018
eventhorizon
30

Para este ejemplo en particular, también podría hacer esto:

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

Es decir, ordenar numéricamente (-n) en el segundo campo (-k2) usando 'h' como separador de campo (-th).

larsks
fuente
Dividir y luego ordenar en un campo: es un gran consejo que estoy seguro será útil en el futuro, gracias.
ngm
6

Puede usar la -vopción en GNU ls: tipo natural de números (versión) dentro del texto.

ls -1v cwcch*

Esto no funciona con BSD ls(por ejemplo, en OS X), donde la -vopción tiene un significado diferente.

Ashutosh Vishwa Bandhu
fuente
Esta es la solución más simple, ¡necesita más votos a favor, amigos!
davidparks21
2

Use la expansión de shell directamente en una línea de comandos. La expansión debería ordenarlos correctamente. Si entiendo pdftkla sintaxis de la línea de comandos correctamente, esto hará lo que desee:

# 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

O puede intentar un enfoque diferente. Cuando necesito hacer algo como esto, generalmente trato de formatear mis números correctamente antes de tiempo. Si llego tarde y los archivos PDF ya están numerados como su ejemplo, lo usaré para volver a numerar:

# 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

Ahora la lsclasificación estándar funcionará correctamente.

quijote curandero
fuente
2
Quizás un poco más sucintamente:pdftk cwcch{{1..9},{10..18}}.pdf ...
Pausado hasta nuevo aviso.
Un buen consejo, agregado. ¿Es esa una sintaxis de expansión de shell Bourne estándar o una bashextensión?
quack quijote
2

Aquí hay un método que solo usa sort:

ls | sort -k1.6n
escocés
fuente
0

Ordenar -g se usa para ordenar los números en orden ascendente.

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


El siguiente delineador itera sobre un archivo con los nombres de los archivos PDF y toma los números solo con egrep -o y usa sort -g para ordenar los números en orden ascendente . Luego alimenta estos números para sed y los conecta. Luego elimina la salida de duplicados con uniq.


En lugar de uniq, también puedes usar awk:

awk '!x[$0]++'

Lo anterior es equivalente a uniq.


Lo que estás buscando es este revestimiento:

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


Contenido de 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:

Salida de 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
fuente
¿ Este forro funciona en el tmparchivo? ¿Alguna salida para pegar en la respuesta?
Xen2050
Sí. Incluí el resultado en mi OP en la sección de edición.
Aguevara