I have some files under a directory:

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

I would like to copy the files to a subdirectory subdir (without overwriting existing files), and rename the files by adding a given number (say 10) to their filename, so that the files becomes

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

Here is my bash command

for filename in *
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"

For some files whose names are negative numbers, I got errors, for example for -008.png (but not for -002.png, and I am not sure why):

for the line that assigns to basename_new:

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

for the line with if:

# [: subdir/.: binary operator expected

I was wondering what those errors mean? How may I solve them?


  • 1
    My best direction at this point is to do something like [[ $b =~ ^-0+([0-9]+)$ ]] && b=-${BASH_REMATCH[1]} to strip leading zeroes from possibly-negative numbers – Jeff Schaller Sep 22 '17 at 19:48
  • Thanks. Is [[ $b =~ ^-0+([0-9]+)$ ]] && b=-${BASH_REMATCH[1]} same as [[ $b =~ ^-0+([1-9]+)$ ]] && b=-${BASH_REMATCH[1]}? – Tim Nov 5 '18 at 19:18

A word beginning with a dash is generally considered as an option. When you do ls *, the ls command receives ls 001.png -002.png ... and sees -002.png as a set of options it does not understand. Same for many commands like cp, mv, ...

Solution #1: prefix the files with their path. Will work in all cases.

ls ./*

Solution #2: a lot of commands, especially in the GNU world, accept a double-dash as a parameter, indicating that what follows are not options

ls -- *

However, leading dashes won't affect you for loop.

As for the "value too great for base", it is due to -008 being considered as an octal number because it begins with a 0. However 8 is not a valid octal digit. A quick fix would be to use bc:

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

You issue with if is caused by an empty basename_new and will disappear with the fix above.

  • 1
    though I think the main question seems to be about the negative leading-zero number confusing bash's arithmetic (despite the attempted base conversion), not any option-confusion with ls – Jeff Schaller Sep 22 '17 at 18:58
  • Thanks. The error is from running the for loop at the end, not running ls. – Tim Sep 22 '17 at 19:02
  • Sorry @Tim, I was not careful enough. Answer updated. – xhienne Sep 22 '17 at 19:06
  • Thanks. Why is -008 is considered as an octal number, while other positive numbers are not? – Tim Sep 22 '17 at 20:14
  • @Tim Numbers starting with 0x are hexadecimal numbers. Numbers starting with 0 are octal numbers. Other numbers are decimal numbers. – xhienne Sep 22 '17 at 20:16

With 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

(remove the -n to actually do it).

  • (-|) glob: - or "": an optional -
  • <-> glob: any sequence of decimal digits (like <x-y> but without bounds).
  • ${(l:4::0:)param}: left padding (and truncation) of length 4 with zeros.
  • $(($1 + 10)): the data captured by the first pair of (...) in the pattern, incremented by 10 (zsh doesn't have that issue that numbers with leading 0s are treated as octal; even if you set the octalzeroes option, that doesn't affect zmv which reverts to sane zsh options while it runs.

10#-008 will not make -008 become decimal. I guess it is because 10# needs to be in front of digits instead of signs.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.