使用Bash重命名表单中文件的最佳方法是什么:
1
| (foo1, foo2, ..., foo1300, ..., fooN) |
使用零填充文件名:
1
| (foo00001, foo00002, ..., foo01300, ..., fooN) |
它不是纯粹的bash,但使用rename命令更容易:
1
| rename 's/\d+/sprintf("%05d",$&)/e' foo* |
如果N不是先验固定的:
1
| for f in foo[0-9]*; do mv $f `printf foo%05d ${f#foo}`; done |
我有一个更复杂的案例,文件名有一个后缀和一个前缀。我还需要对文件名中的数字进行减法。
例如,我希望foo56.webp成为foo00000055.webp。
我希望如果你做的事更复杂,这会有所帮助。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| #!/bin/bash
prefix="foo"
postfix=".webp"
targetDir="../newframes"
paddingLength=8
for file in ${prefix}[0-9]*${postfix}; do
# strip the prefix off the file name
postfile=${file#$prefix}
# strip the postfix off the file name
number=${postfile%$postfix}
# subtract 1 from the resulting number
i=$((number-1))
# copy to a new name with padded zeros in a new folder
cp ${file}"$targetDir"/$(printf $prefix%0${paddingLength}d$postfix $i)
done |
我使用的oneline命令是这样的:
1
| ls * | cat -n | while read i f; do mv"$f" `printf"PATTERN""$i"`; done |
PATTERN可以是例如:
-
使用增量计数器重命名:%04d.${f#*.}(保留原始文件扩展名)
-
使用前缀为photo_%04d.${f#*.}的增量计数器重命名(保留原始扩展名)
-
使用增量计数器重命名并将扩展名更改为jpg:%04d.webp
-
使用带有前缀和文件basename的增量计数器重命名:photo_$(basename $f .${f#*.})_%04d.${f#*.}
-
...
您可以使用例如ls *.webp | ...过滤要重命名的文件
您可以使用作为文件名的变量f和作为计数器的i。
对于您的问题,正确的命令是:
1
| ls * | cat -n | while read i f; do mv"$f" `printf"foo%d05""$i"`; done |
Pure Bash,除了'mv'之外没有任何外部进程:
1 2 3 4 5
| for file in foo*; do
newnumber='00000'${file#foo} # get number, pack with zeros
newnumber=${newnumber:(-5)} # the last five characters
mv $file foo$newnumber # rename
done |
以下将这样做:
1
| for ((i=1; i<=N; i++)) ; do mv foo$i `printf foo%05d $i` ; done |
编辑:改为使用((i = 1,...)),谢谢mweerden!
对于文件名中的左键数字:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| $ ls -l
total 0
-rw-r--r-- 1 victoria victoria 0 Mar 28 17:24 010
-rw-r--r-- 1 victoria victoria 0 Mar 28 18:09 050
-rw-r--r-- 1 victoria victoria 0 Mar 28 17:23 050.zzz
-rw-r--r-- 1 victoria victoria 0 Mar 28 17:24 10
-rw-r--r-- 1 victoria victoria 0 Mar 28 17:23 1.zzz
$ for f in [0-9]*.[a-z]*; do tmp=`echo $f | awk -F. '{printf"%04d.%s
", $1, $2}'`; mv"$f""$tmp"; done;
$ ls -l
total 0
-rw-r--r-- 1 victoria victoria 0 Mar 28 17:23 0001.zzz
-rw-r--r-- 1 victoria victoria 0 Mar 28 17:23 0050.zzz
-rw-r--r-- 1 victoria victoria 0 Mar 28 17:24 010
-rw-r--r-- 1 victoria victoria 0 Mar 28 18:09 050
-rw-r--r-- 1 victoria victoria 0 Mar 28 17:24 10 |
说明
1 2 3
| for f in [0-9]*.[a-z]*; do tmp=`echo $f | \
awk -F. '{printf"%04d.%s
", $1, $2}'`; mv"$f""$tmp"; done; |
-
注意反引号:`echo ... $2}\`(反斜杠,,上面只是为了便于阅读而将单行分为两行)
-
在循环中查找名为具有小写字母扩展名的数字的文件:[0-9]*.[a-z]*
-
回显该文件名($f)以将其传递给awk
-
-F.:awk字段分隔符,句点(.):如果匹配,则将文件名分隔为两个字段($1 = number; $2 = extension)
-
格式为printf:将第一个字段($1,数字部分)打印为4位数(%04d),然后打印句点,然后将第二个字段($2:扩展名)打印为字符串(< X40>)。所有这些都分配给$tmp变量
-
最后,将源文件($f)移动到新文件名($tmp)
我的解决方案替换了字符串中的数字
1 2 3 4 5
| for f in * ; do
number=`echo $f | sed 's/[^0-9]*//g'`
padded=`printf"%04d" $number`
echo $f | sed"s/${number}/${padded}/";
done |
您可以轻松地尝试它,因为它只打印转换后的文件名(不执行文件系统操作)。
说明:
循环遍历文件列表
循环:for f in * ; do ;done,列出所有文件,并将每个文件名作为$f变量传递给循环体。
从字符串中抓取数字
使用echo $f | sed,我们将变量$f传递给sed程序。
在命令sed 's/[^0-9]*//g'中,带有修饰符^的部分[^0-9]*表示与数字0-9(不是数字)相反,然后用空替换//将其删除。为什么不删除[a-z]?因为文件名可以包含点,破折号等。所以,我们剥离所有东西,这不是数字并得到一个数字。
接下来,我们将结果分配给number变量。请记住不要在分配中放置空格,例如number = …,因为你会得到不同的行为。
我们将命令的执行结果分配给变量,用反引号符号`包装命令。
零填充
命令printf"%04d" $number将数字的格式更改为4位,如果我们的数字少于4位,则添加零。
将数字替换为零填充数字
我们再次使用sed替换命令,如s/substring/replacement/。为了解释我们的变量,我们使用双引号并以这种方式替换我们的变量${number}。
上面的脚本只打印转换后的名称,所以,让我们做实际的重命名工作:
1 2 3 4 5 6
| for f in *.js ; do
number=`echo $f | sed 's/[^0-9]*//g'`
padded=`printf"%04d" $number`
new_name=`echo $f | sed"s/${number}/${padded}/"`
mv $f $new_name;
done |
希望这有助于某人。
我花了几个小时来解决这个问题。
这是一个快速的解决方案,假设一个固定长度前缀(您的"foo")和固定长度填充。如果您需要更多的灵活性,这可能至少是一个有用的起点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| #!/bin/bash
# some test data
files="foo1
foo2
foo100
foo200
foo9999"
for f in $files; do
prefix=`echo"$f" | cut -c 1-3` # chars 1-3 ="foo"
number=`echo"$f" | cut -c 4-` # chars 4-end = the number
printf"%s%04d
""$prefix""$number"
done |