碰巧我在BASH中编写了一个脚本,其中一部分应该按照数字顺序从指定的目录中获取文件。显然,该目录中的文件命名如下:1、2、3、4、5等。问题是,我发现在运行该目录中有10个文件的脚本时,出现了一些对我来说非常不合逻辑的事情,因为脚本以奇怪的顺序接收文件:10、1、2和3等。
如何使它从文件名的最小值运行到以小数表示的最大值?
此外,我使用以下代码行来定义循环和路径:
for file in /dir/*
不知道这是否重要,但我使用Fedora 33作为操作系统。
目录按字母顺序排序。所以"10〃;在";2〃;。如果我列出20个文件,它们的名称对应于20个第一个整数,我得到:
1 10 11 12 13 14 15 16 17 18 19 2 20 3 4 5 6 7 8 9
我可以调用函数"sort-n",这样我就可以用数字而不是字母顺序对它们进行排序。以下命令:
for i in $(ls | sort -n) ; do echo $i ; done
产生以下输出:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
即您的命令:
for file in /dir/*
应重写:对于"中的文件;dir/"$(ls/dir/*|sort-n(
如果您有GNUsort
,则使用-V
标志。
for file in /dir/* ; do echo "$file" ; done | sort -V
或者将数据存储在数组中。
files=(/dir/*); printf '%sn' "${files[@]}" | sort -V
顺便说一句,如果你有这个选项,并且提前一次工作比每次排序更可取,你也可以用前导零格式化目录名称。在可能的情况下,这通常是一个更好的设计。
我把两者都做了比较。
$: echo [0-9][0-9]/ # perfect list based on default string sort
00/ 01/ 02/ 03/ 04/ 05/ 06/ 07/ 08/ 09/ 10/ 11/ 12/ 13/ 14/ 15/ 16/ 17/ 18/ 19/ 20/
它还过滤掉任何非数字名称和任何非目录。
$: for d in [0-9][0-9]/; do echo "${d%/}"; done
00
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
如果我同时显示单位数和两位数的版本(我都做了(
$: shopt -s extglob
$: echo @(?|??)
0 00 01 02 03 04 05 06 07 08 09 1 10 11 12 13 14 15 16 17 18 19 2 20 3 4 5 6 7 8 9
只有没有前导零的个位数版本才会出现故障。
shell根据每个字符的区域设置顺序(不一定是字节值(对名称进行排序。以1
开头的任何内容都将先于以2
开头的任何对象,依此类推
有两种主要方法可以解决您的问题:
sort -n
(数字排序(文件列表,并对其进行迭代- 重命名或重新创建目标文件(如果可以的话(,使所有数字的长度相同(以字节/字符为单位(。用
0
(例如01
(向左填充较短的数字。然后它们会像你想要的那样膨胀
使用sort
(正确(:
mapfile -td '' myfiles <(printf '%s ' * | sort -zn)
for file in "${myfiles[@]}"; do
# what you were going to do
用于零/零端接线路的sort
-z
是常见的,但不是posix。它使处理包含新行的路径/数据变得安全。无-z
:
mapfile -t myfiles <(printf '%sn' * | sort -n)
# Rest is the same.
重命名目标文件:
#!/bin/bash
cd /path/to/the/number/files || exit 1
# Gets length of the highest number. Or you can just hardcode it.
length=$(printf '%sn' * | sort -n | tail -n 1)
length=${#length}
for i in *; do
mv -n "$i" "$(printf "%.${length}d" "$i")"
done
制作名称为零填充数字的新文件的示例:
touch {000..100} # Or
for i in {000..100}; do
> "$i"
done
如果是您的脚本生成了目标文件,则可以使用类似$(printf %.Nd [file])
的东西在写入之前对名称进行左填充。但您需要首先知道最高数字(N
(的字符长度。