Glob com ordem numérica

22

Eu tenho esta lista de arquivos pdf em um diretório:

c0.pdf   c12.pdf  c15.pdf  c18.pdf  c20.pdf  c4.pdf  c7.pdf
c10.pdf  c13.pdf  c16.pdf  c19.pdf  c2.pdf   c5.pdf  c8.pdf
c11.pdf  c14.pdf  c17.pdf  c1.pdf   c3.pdf   c6.pdf  c9.pdf

Eu quero concatenar esses usando ghostscript em ordem numérica (semelhante a isso):

gs -q -sPAPERSIZE=a4 -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=out.pdf *.pdf

Mas a ordem de expansão do shell não reproduz a ordem natural dos números, mas a ordem alfabética:

$ for f in *.pdf; do echo $f; done
c0.pdf
c10.pdf
c11.pdf
c12.pdf
c13.pdf
c14.pdf
c15.pdf
c16.pdf
c17.pdf
c18.pdf
c19.pdf
c1.pdf
c20.pdf
c2.pdf
c3.pdf
c4.pdf
c5.pdf
c6.pdf
c7.pdf
c8.pdf
c9.pdf

Como posso conseguir a ordem desejada na expansão (se possível sem adicionar manualmente 0 -padding aos números nos nomes dos arquivos)?

Encontrei sugestões para usar ls | sort -V , mas não consegui que funcionasse para meu caso de uso específico.

    
por moooeeeep 10.05.2012 / 11:28

5 respostas

11

Dependendo do seu ambiente, você pode usar ls -v com os GNU coreutils, por exemplo:

gs -q -sPAPERSIZE=a4 -dNOPAUSE -dBATCH -sDEVICE=pdfwrite \
   -sOutputFile=out.pdf $(ls -v)

Ou se você estiver em versões recentes do FreeBSD ou do OpenBSD:

gs -q -sPAPERSIZE=a4 -dNOPAUSE -dBATCH -sDEVICE=pdfwrite \
   -sOutputFile=out.pdf $(ls | sort -V)
    
por 10.05.2012 / 14:22
17

Mais uma vez, os qualificadores glob do zsh vêm para o resgate.

echo *.pdf(n)
    
por 11.05.2012 / 02:59
9

Se todos os arquivos em questão tiverem o mesmo prefixo (ou seja, o texto antes do número; c neste caso), você pode usar

gs  …args…  c?.pdf c??.pdf

c?.pdf expande para c0.pdf c1.pdfc9.pdf . c??.pdf expande para c10.pdf c11.pdfc20.pdf (e até c99.pdf , conforme aplicável). Enquanto cada palavra da linha de comando contendo o (s) caractere (s) de expansão do nome do caminho é expandido para uma lista de nomes de arquivos classificados (agrupados) de acordo com a variável LC_COLLATE , as listas resultantes da expansão de curingas adjacentes (globs) não são mesclados; eles são simplesmente concatenados. (Eu pareço lembrar que a página de manual do shell uma vez declarou isso explicitamente, mas não consigo encontrá-lo agora.)

Claro, se os arquivos podem ir até c999.pdf , você deve usar c?.pdf c??.pdf c???.pdf . Evidentemente, isso pode ser entediante se você tiver muitos dígitos. Você pode abreviá-lo um pouco; por exemplo, para (até) cinco dígitos, você pode usar c?{,?{,?{,?{,?}}}}.pdf . Se a sua lista de nomes de arquivos é esparsa (por exemplo, há um c0.pdf e um c12345.pdf mas não necessariamente todos os números entre eles), provavelmente você deve definir a opção nullglob . Caso contrário, se (por exemplo) você não tiver arquivos com números de dois dígitos, você receberia um argumento literal c??.pdf passado para o seu programa.

Se você tiver vários prefixos (por exemplo, a<number>.pdf , %código%, e b<number>.pdf , com números de um ou dois dígitos), você pode usar a abordagem óbvia de força bruta:

a?.pdf a??.pdf b?.pdf b??.pdf c?.pdf c??.pdf

ou reduza para c<number>.pdf .

    
por 26.05.2016 / 06:33
5

Se não houver lacunas , o seguinte pode ser útil (embora incompleto e não robusto em relação a casos-limite e generalidade) - apenas para ter uma ideia:

FILES="c0.pdf"
for i in $(seq 1 20); do FILES="${FILES} c${i}.pdf"; done
gs [...args...] $FILES

Se houver intervalos , pode-se adicionar [ -f c${i}.pdf ] check.

Editar veja também esta resposta , de acordo com o que você pode (usando Bash ) use

gs [..args..] c{1..20}.pdf
    
por 10.05.2012 / 11:49
1

Apenas citando e corrigindo a resposta de Thor ... NUNCA analise ls!

Você pode usar sort -V (uma extensão não POSIX para classificar):

printf '%s
printf '%s%pre%' ./* | sort -zV \
    | xargs -0 gs -q -sPAPERSIZE=a4 -dNOPAUSE -dBATCH \
        -sDEVICE=pdfwrite -sOutputFile=out.pdf
' ./* | sort -zV \ | xargs -0 gs -q -sPAPERSIZE=a4 -dNOPAUSE -dBATCH \ -sDEVICE=pdfwrite -sOutputFile=out.pdf

(para alguns comandos, aparentemente para gs é um comando, você precisa de "./ " ao invés de "" ... se um não funcionar, tente o outro)

    
por 05.09.2017 / 10:33