我的目录下有一些文件:
$ 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#
需要位于数字而不是符号前面。