用 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 选项。