以负数命名的文件名的参数扩展错误

以负数命名的文件名的参数扩展错误

我的目录下有一些文件:

$ ls *
-008.png  0052.png -002.jpg  0043.png  -005.png  0044.png ...

我想将文件复制到子目录subdir(不覆盖现有文件),并通过在文件名中添加给定数字(例如 10)来重命名文件,以便文件变为

$ ls subdir/*
0002.png  0062.png 0008.jpg  0053.png  0005.png  0054.png ...

这是我的 bash 命令

for filename in *
do
basename=${filename%.*}
extname=${filename#*.}
basename_new=$(printf %04d $((10#${basename}+10))); # 10#-008: value too great for base (error token is "003")
if [ ! -e subdir/"$basename_new".* ];  # [: subdir/.: binary operator expected
cp "$filename" "$basename_new"."$extname"
fi
done

对于一些名称为负数的文件,我收到错误,例如 for -008.png(但不是 for -002.png,我不确定为什么):

对于分配给 的行basename_new

10#-008: value too great for base (error token is "008")

对于以下行if

# [: subdir/.: binary operator expected

我想知道这些错误是什么意思?我该如何解决它们?

谢谢。

答案1

以破折号开头的单词通常被视为一个选项。当您这样做时ls *,该ls命令会接收ls 001.png -002.png ...并视为-002.png一组它不理解的选项。对于许多命令来说也是如此,例如cp, mv, ...

解决方案#1:在文件前面加上路径前缀。在所有情况下都有效。

ls ./*

解决方案#2:很多命令,尤其是在 GNU 世界中,接受双破折号作为参数,表明后面的内容不是选项

ls -- *

但是,前导破折号不会影响for循环。


至于“值对于基数来说太大”,这是由于-008它以 0 开头而被视为八进制数。但是 8 不是有效的八进制数字。一个快速解决方法是使用bc

printf -v basename_new %04d "$(bc <<< "${basename} + 10")"

您的问题if是由空引起的basename_new,并且通过上述修复将消失。

答案2

zsh

$ autoload zmv
$ zmv -n '((-|)<->).(png|jpg)' '${(l:4::0:)$(($1 + 10))}.$3'
mv -- -002.jpg 0008.jpg
mv -- 0043.png 0053.png
mv -- 0044.png 0054.png
mv -- 0052.png 0062.png
mv -- -005.png 0005.png
mv -- -008.png 0002.png

(删除-n实际执行的操作)。

  • (-|)glob:-或 "": 可选-
  • <->glob:任何十进制数字序列(类似<x-y>但没有界限)。
  • ${(l:4::0:)param}:长度为 4 且带有零的左侧填充(和截断)。
  • $(($1 + 10))(...):模式中第一对捕获的数据,增加 10(zsh不存在以 0 开头的数字被视为八进制的问题;即使您设置了该octalzeroes选项,也不会影响zmv恢复为 sane zsh运行时的选项。

答案3

10#-008不会使-008变成十进制。我想这是因为10#需要位于数字而不是符号前面。

相关内容