用 bash 添加一个常数来移动文件名
shifting the file name with bash adding a constant number
我有一些文件名为:
0001.jpg
0002.jpg
...
0050.jpg
我需要将该数字增加 35,以便获得:
0036.jpg
0037.jpg
...
0085.jpg
我想尝试以下方法:
for i in {0001..0050}; do
mv -n $i $((i+35))
done
但是我收到错误 bash: 0008: value too great for base (error token is "0008")
。我不确定我是否理解 base
在这里的含义或如何绕过它。这个我看过question。尽管它解释了八进制错误,但并不能立即清楚它如何帮助使用移位索引进行迭代。
bash 和 C 一样,当在算术展开中使用时,将以零开头的数字解释为八进制数。这是 POSIX sh 的标准行为。由于“8”不是八进制数中的有效值,因此会出现错误。
由于你想要的是从1数到50再加35,然后格式化为数字,你可以这样做:
#!/bin/sh
for i in $(seq 50 -1 1)
do
mv -n $(printf '%04d.jpg' $i) $(printf '%04d.jpg' $((i + 35)))
done
这从 50 迭代到 1,并使用 printf
程序格式化每个数字。顺便说一句,除了在 bash.
中工作之外,这也是可移植的 POSIX sh
问题是 bash 算法将以 0
开头的数字视为八进制数,八进制系统只允许 0-7 位数字。您可以在数字前添加 10#
前缀,以告诉 bash 接受给定数字作为以 10 为基数的数字并计算您的总和。
您可以使用:
for i in {0010..0001}.jpg; do
f="${i%.jpg}"
echo mv "$i $(printf '%04d' $((10#$f + 10#35))).jog"
done
一旦您对输出感到满意,请删除 mv
之前的 echo
。
mv 0010.jpg 0045.jog
mv 0009.jpg 0044.jog
mv 0008.jpg 0043.jog
mv 0007.jpg 0042.jog
mv 0006.jpg 0041.jog
mv 0005.jpg 0040.jog
mv 0004.jpg 0039.jog
mv 0003.jpg 0038.jog
mv 0002.jpg 0037.jog
mv 0001.jpg 0036.jog
最终我选择了:
for i in {50..1};
do
old=$(printf '%04d.jpg' $i)
new=$(printf '%04d.jpg' $((i + 34)))
mv -i -- "$old" "$new" #-i to avoid overwritting
done
@Massagran 几乎自己的解决方案:
#!/usr/bin/env bash
for i in {50..1}; do
printf -v old_filename '%04d.jpg' $i
printf -v new_filename '%04d.jpg' $((i + 35))
[[ -f $old_filename ]] && mv --no-clobber -- "$old_filename" "$new_filename"
done
它有何不同并改进您的答案:
不是通过 运行 printf
在子 shell 中将 printf
的输出捕获到变量中,而是使用 -v
选项,所以 printf
直接输出到变量中。
在执行重命名之前,它会测试旧文件名是否存在并且是一个实际文件。
为了防止覆盖现有文件,它使用 --no-clobber
而不是 --interactive
选项。
我有一些文件名为:
0001.jpg
0002.jpg
...
0050.jpg
我需要将该数字增加 35,以便获得:
0036.jpg
0037.jpg
...
0085.jpg
我想尝试以下方法:
for i in {0001..0050}; do
mv -n $i $((i+35))
done
但是我收到错误 bash: 0008: value too great for base (error token is "0008")
。我不确定我是否理解 base
在这里的含义或如何绕过它。这个我看过question。尽管它解释了八进制错误,但并不能立即清楚它如何帮助使用移位索引进行迭代。
bash 和 C 一样,当在算术展开中使用时,将以零开头的数字解释为八进制数。这是 POSIX sh 的标准行为。由于“8”不是八进制数中的有效值,因此会出现错误。
由于你想要的是从1数到50再加35,然后格式化为数字,你可以这样做:
#!/bin/sh
for i in $(seq 50 -1 1)
do
mv -n $(printf '%04d.jpg' $i) $(printf '%04d.jpg' $((i + 35)))
done
这从 50 迭代到 1,并使用 printf
程序格式化每个数字。顺便说一句,除了在 bash.
问题是 bash 算法将以 0
开头的数字视为八进制数,八进制系统只允许 0-7 位数字。您可以在数字前添加 10#
前缀,以告诉 bash 接受给定数字作为以 10 为基数的数字并计算您的总和。
您可以使用:
for i in {0010..0001}.jpg; do
f="${i%.jpg}"
echo mv "$i $(printf '%04d' $((10#$f + 10#35))).jog"
done
一旦您对输出感到满意,请删除 mv
之前的 echo
。
mv 0010.jpg 0045.jog
mv 0009.jpg 0044.jog
mv 0008.jpg 0043.jog
mv 0007.jpg 0042.jog
mv 0006.jpg 0041.jog
mv 0005.jpg 0040.jog
mv 0004.jpg 0039.jog
mv 0003.jpg 0038.jog
mv 0002.jpg 0037.jog
mv 0001.jpg 0036.jog
最终我选择了:
for i in {50..1};
do
old=$(printf '%04d.jpg' $i)
new=$(printf '%04d.jpg' $((i + 34)))
mv -i -- "$old" "$new" #-i to avoid overwritting
done
@Massagran 几乎自己的解决方案:
#!/usr/bin/env bash
for i in {50..1}; do
printf -v old_filename '%04d.jpg' $i
printf -v new_filename '%04d.jpg' $((i + 35))
[[ -f $old_filename ]] && mv --no-clobber -- "$old_filename" "$new_filename"
done
它有何不同并改进您的答案:
不是通过 运行
printf
在子 shell 中将printf
的输出捕获到变量中,而是使用-v
选项,所以printf
直接输出到变量中。在执行重命名之前,它会测试旧文件名是否存在并且是一个实际文件。
为了防止覆盖现有文件,它使用
--no-clobber
而不是--interactive
选项。