You can do what you need in POSIX shell, but you must protect against numbers with leading zeros being interpreted as octal numbers. To do what you want, you need a way to remove the leading zeros for your conversion to a number. While bash provides a simple built-in parameter expansion that will work, in POSIX shell, you are stuck using the old expr syntax or calling a utility like sed or grep.
To trim the leading zeros using expr, you must first know how many there are. The old POSIX shell expr provides two expressions that will work. The first called index can return the index of the first character in $input_sub that is not 0. Which gives you the index (1-based) where the first non-zero digit is found. The form you can use is:
## get index of first non-zero digit, POSIX compliant
nonzero=$(expr index "$input_sub" [123456789])
With the index of the first non-zero digit in $nonzero, you can use the substr expression to obtain the number without leading zeros (you know the max number of digits is 3, so obtain the substring from the index to 3), e.g.
num=$(expr substr "$input_sub" "$nonzero" 3) ## remove leading 0's
You need to be able to handle 000 as $inpu_sub, so go ahead and add a if .. then ... else ... fi to handle that case, e.g.
if [ "$nonzero" -eq 0 ]; then
num=0
else
num=$(expr substr "$input_sub" "$nonzero" 3) ## remove leading 0's
fi
Now you can simply add 1 to get your new number:
newnum=$((num + 1))
To convert the number back to a string of 3 characters representing the number with leading zeros replaced, just use printf with the "%03d" conversion specifier, e.g.
# then convert that 1 to 001
input_sub=$(printf "%03d" "$newnum")
Putting together a short example showing the progression that takes place, I have replaced your while loop with a loop that will loop 21 times from 0 to 20 to show the operation and I have added printf statements to show the numbers and conversion back to string. You simply restore your while and remove the extra printf statements for your use:
#!/bin/sh
input_sub=000
# while [ -d $input_dir ]
while [ "$input_sub" != "020" ] ## temporary loop 000 to 009
do
printf "input_sub: %s " "$input_sub"
# HERE I would like to fist convert 000 to 0
# then add 1 to it 0-> 1
## get index of first non-zero digit, POSIX compliant
nonzero=$(expr index "$input_sub" [123456789])
if [ "$nonzero" -eq 0 ]; then
num=0
else
num=$(expr substr "$input_sub" "$nonzero" 3) ## remove leading 0's
fi
newnum=$((num + 1))
# then convert that 1 to 001
input_sub=$(printf "%03d" "$newnum")
printf "%2d + 1 = %2d => input_sub: %s\n" "$num" "$newnum" "$input_sub"
done
Example Use/Output
Showing the conversions with the modified while loop, you would get:
$ sh str2int2str.sh
input_sub: 000 0 + 1 = 1 => input_sub: 001
input_sub: 001 1 + 1 = 2 => input_sub: 002
input_sub: 002 2 + 1 = 3 => input_sub: 003
input_sub: 003 3 + 1 = 4 => input_sub: 004
input_sub: 004 4 + 1 = 5 => input_sub: 005
input_sub: 005 5 + 1 = 6 => input_sub: 006
input_sub: 006 6 + 1 = 7 => input_sub: 007
input_sub: 007 7 + 1 = 8 => input_sub: 008
input_sub: 008 8 + 1 = 9 => input_sub: 009
input_sub: 009 9 + 1 = 10 => input_sub: 010
input_sub: 010 10 + 1 = 11 => input_sub: 011
input_sub: 011 11 + 1 = 12 => input_sub: 012
input_sub: 012 12 + 1 = 13 => input_sub: 013
input_sub: 013 13 + 1 = 14 => input_sub: 014
input_sub: 014 14 + 1 = 15 => input_sub: 015
input_sub: 015 15 + 1 = 16 => input_sub: 016
input_sub: 016 16 + 1 = 17 => input_sub: 017
input_sub: 017 17 + 1 = 18 => input_sub: 018
input_sub: 018 18 + 1 = 19 => input_sub: 019
input_sub: 019 19 + 1 = 20 => input_sub: 020
This has been done in POSIX shell given your tag [shell]. If you have bash available, you can shorten and make the script a bit more efficient by using bash built-ins instead of expr. That said, for 1000 directories max -- you won't notice much difference. Let me know if you have further questions.
Bash Solution Per-Request in Comment
If you do have bash available, then the [[ ... ]] expression provides the =~ operator which allows an extended REGEX match on the right hand side (e.g. [[ $var =~ REGEX ]]) The REGEX can contain capture groups (parts of the REGEX enclosed by (..)), that are used to fill the BASH_REMATCH array where ${BASH_REMATCH[0]} contains the total expression matched and ${BASH_REMATCH[1]} ... contain each captured part of the regex.
So using [[ ... =~ ... ]] with a capture on the number beginning with [123456789] will leave the wanted number in ${BASH_REMATCH[1]} allowing you to compute the new number using the builtin, e.g.
#!/bin/bash
input_sub=000
# while [ -d $input_dir ]
while [ "$input_sub" != "020" ] ## temporary loop 000 to 020
do
printf "input_sub: %s " "$input_sub"
# HERE I would like to fist convert 000 to 0
# then add 1 to it 0-> 1
## [[ .. =~ REGEX ]], captures between (...) in array BASH_REMATCH
if [[ $input_sub =~ ^0*([123456789]+[0123456789]*)$ ]]
then
num=${BASH_REMATCH[1]} ## use number if not all zeros
else
num=0 ## handle 000 case
fi
newnum=$((num + 1))
# then convert that 1 to 001
input_sub=$(printf "%03d" "$newnum")
printf "%2d + 1 = %2d => input_sub: %s\n" "$num" "$newnum" "$input_sub"
done
(same output)
Let me know if you have further questions.
printf "%d" "000"and backprintf "%03d" "0"for dir in {000..010}; do echo "dir: $dir"; doneinput_sub=0, then convert to a 0-padded string as necessary, rather than going in the other direction.