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
Quero concatená-los usando o 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 obter 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 fazê-lo funcionar no meu caso de uso específico.
Respostas:
Dependendo do seu ambiente, você pode usar
ls -v
com o GNU coreutils, por exemplo:Ou se você estiver em versões recentes do FreeBSD ou OpenBSD:
fonte
ls -v
vontadenatural sort of (version) numbers within text
para que possa ser usado também ...-V
recurso desort
também não é especificado pelo POSIX. No entanto, parece ter se espalhado mais, por exemplo, tanto o FreeBSD quanto o OpenBSD osort
suportam.ls
usado, verifiquei se ela tinha opção por si só em vez de canalizar para classificar :)Mais uma vez, os qualificadores globais do zsh vêm em socorro.
fonte
Se todos os arquivos em questão tiverem o mesmo prefixo (ou seja, o texto antes do número;
c
nesse caso), você poderá usarc?.pdf
se expande parac0.pdf
c1.pdf
...c9.pdf
.c??.pdf
expande parac10.pdf
c11.pdf
…c20.pdf
(e atéc99.pdf
, conforme aplicável). Enquanto cada palavra da linha de comando que contém caracteres de expansão de nome de caminho é expandida para uma lista de nomes de arquivos classificados (agrupados) de acordo com aLC_COLLATE
variável, as listas resultantes da expansão de curingas adjacentes (globs) não são mescladas; eles são simplesmente concatenados. (Lembro-me de que a página de manual do shell já declarou isso explicitamente, mas não consigo encontrá-lo agora.)Obviamente, se os arquivos puderem subir
c999.pdf
, você deve usá-loc?.pdf c??.pdf c???.pdf
. É certo que isso pode ser entediante se você tiver muitos dígitos. Você pode abreviar um pouco; por exemplo, para (até) cinco dígitos, você pode usarc?{,?{,?{,?{,?}}}}.pdf
. Se sua lista de nomes de arquivos for esparsa (por exemplo, há umc0.pdf
e umc12345.pdf
, mas não necessariamente todos os números intermediários), você provavelmente deve definir anullglob
opção. Caso contrário, se (por exemplo) você não tiver arquivos com números de dois dígitos, obteria umc??.pdf
argumento literal passado para o seu programa.Se você tem vários prefixos (por exemplo, , , e , com os números de um ou dois dígitos), você pode usar a abordagem de força óbvia, bruta:
a<number>.pdf
b<number>.pdf
c<number>.pdf
ou reduza para
{a,b,c}?{,?}.pdf
.fonte
ls
,stat
ou qualquer outra coisa; e também funciona no bash, conforme solicitado.Se não houver lacunas , o seguinte pode ser útil (embora superficial e pouco robusto em relação aos casos extremos e à generalidade) - apenas para se ter uma idéia:
Se não pode ser lacunas, algumas
[ -f c${i}.pdf ]
cheque pode ser adicionado.Editar também veja esta resposta , de acordo com a qual você pode (usando o Bash) usar
fonte
"$FILES"
e"$i"
), a menos que você tenha um bom motivo para não fazê-lo e tenha certeza de que sabe o que está fazendo. (Por outro lado, enquanto chaves podem ser importantes, elas não são tão importantes quanto aspas, portanto, por exemplo,"c$i.pdf"
é bom o suficiente.) Um comando como , onde contém uma lista de arquivos separados por espaço, pode parecer um bom motivo para use sem citá-lo (porque não funcionará nesse contexto). … (Continua)gs [
…args…
] $FILES
$FILES
$FILES
"$FILES"
FILES=("c0.pdf")
eFILES+=("c$i.pdf")
); também esta resposta , que usa a técnica que sugiro.Apenas citando e corrigindo a resposta de Thor ... NUNCA analise ls!
Você pode usar
sort -V
(uma extensão não POSIX para classificar):(para alguns comandos, aparentemente para gs é esse comando, você precisa de "./ " em vez de " " ... se um não funcionar, tente o outro)
fonte
stat
mas adicionando vários outros problemas (como problemas com o início de nomes de arquivos com-
, problema se houver muitos arquivos,stat
sendo um comando não portátil). E como você usou o operador split + glob sem ajustar o IFS ou desativar os globs, ainda terá problemas com nomes de arquivos com caracteres de espaço ou tab ou curinga.sort -V
maneira confiável, você precisaria${(z)"$(printf '%s\0' * | sort -zV)"}
dezsh
(emborazsh
já(n)
exista uma classificação numérica) oureadarray -td '' files < <(printf '%s\0' * | sort -zV)
debash4.4+
.ls
si só (ou seja, sem -l), quais são essas outras preocupações ? Observe que--
não ajudaria em um arquivo chamado-
.touch \"test\"; ls -1
por exemplo, mostra'"test"'
no meu ls. Simplesmente não é para ser analisado ... é uma interface de usuário, não um comando de script.