带数字顺序的 Glob

moo*_*eep 34 bash filenames wildcards

我在一个目录中有这个 pdf 文件列表:

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
Run Code Online (Sandbox Code Playgroud)

我想按数字顺序使用 ghostscript 连接这些(类似于此):

gs -q -sPAPERSIZE=a4 -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=out.pdf *.pdf
Run Code Online (Sandbox Code Playgroud)

但是 shell 扩展顺序不会重现数字的自然顺序,而是按字母顺序:

$ 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
Run Code Online (Sandbox Code Playgroud)

如何在扩展中实现所需的顺序(如果可能,无需手动将0-padding添加到文件名中的数字)?

我找到了使用建议ls | sort -V,但我无法让它适用于我的特定用例。

Tho*_*hor 17

根据您的环境,您可以使用ls -vGNU coreutils,例如:

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

或者,如果您使用的是最新版本的 FreeBSD 或 OpenBSD:

gs -q -sPAPERSIZE=a4 -dNOPAUSE -dBATCH -sDEVICE=pdfwrite \
   -sOutputFile=out.pdf $(ls | sort -V)
Run Code Online (Sandbox Code Playgroud)


G-M*_*ca' 15

如果所有有问题的文件都具有相同的前缀(即数字之前的文本;c在这种情况下),您可以使用

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

c?.pdf扩展到c0.pdf c1.pdf…… c9.pdf。  c??.pdf扩展到c10.pdf c11.pdf... c20.pdf (并且最多扩展到c99.pdf,如适用)。虽然每个包含路径名扩展字符的命令行单词都被扩展为根据LC_COLLATE变量排序(整理)的文件名列表,但不会合并由相邻通配符(globs)扩展产生的列表;它们只是连接在一起。(我似乎记得 shell 手册页曾经明确说明了这一点,但我现在找不到了。)

当然,如果文件可以达到c999.pdf,你应该使用c?.pdf c??.pdf c???.pdf. 诚然,如果您有很多数字,这会变得乏味。你可以稍微缩写一下;例如,对于(最多?至)五位数字,您可以使用c?{,?{,?{,?{,?}}}}.pdf. 如果您的文件名列表很少(例如,有 ac0.pdf和 a c12345.pdf,但不一定是中间的每个数字),您可能应该设置该nullglob选项。否则,如果(例如)你没有两位数字的文件,你会得到一个c??.pdf传递给你的程序的文字参数。

如果您有多个前缀(例如,, 和,带有一位或两位数字),您可以使用明显的蛮力方法:a<number>.pdfb<number>.pdf c<number>.pdf

a?.pdf a??.pdf b?.pdf b??.pdf c?.pdf c??.pdf
Run Code Online (Sandbox Code Playgroud)

或将其折叠为{a,b,c}?{,?}.pdf.

  • 这是最好的答案,因为它超出了对 `ls`、`stat` 或其他任何东西的粗略使用的任何声称;并且还可以根据要求在 bash 中工作。 (2认同)

sr_*_*sr_ 5

如果没有差距,以下内容可能会有所帮助(尽管在边缘情况和一般性方面粗略且不稳健)——只是为了得到一个想法:

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

如果可能有差距,[ -f c${i}.pdf ]可以添加一些检查。

编辑也看到这个答案,根据它你可以(使用 Bash)使用

gs [..args..] c{1..20}.pdf
Run Code Online (Sandbox Code Playgroud)