BASH中文件名的编号优先级不合理



碰巧我在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(的字符长度。

最新更新