Search code examples
bashvariableswildcardmv

How to capture and modify digits recognized by regex in bash


Basically, I'm trying to increment each digit in _XtoX of each file below by 20

err_5JUP_N2_UUCCGU_1to2  err_5JUP_N2_UUCCGU_3to4  err_5JUP_N2_UUCCGU_5to6  err_5JUP_N2_UUCCGU_7to8  err_5JUP_N2_UUCCGU_9to10

such that the new file names should look like such:

err_5JUP_N2_UUCCGU_21to22  err_5JUP_N2_UUCCGU_23to24  err_5JUP_N2_UUCCGU_25to26  err_5JUP_N2_UUCCGU_27to28  err_5JUP_N2_UUCCGU_29to30

I came up with the following snippet of code:

for FILE in err*
do
    mv $FILE ${FILE/$"_"*to*/"_$((*+20))to$((*+20))}
done 

I essentially identified the pattern with "_"*to*/, but I'm pretty sure the * is not a reasonable way to capture the values and increment them. What is an alternative solution to this?


Solution

  • Try this Shellcheck-clean code:

    #! /bin/bash -p
    
    shopt -s extglob nullglob
    
    for errfile in err*_+([0-9])to+([0-9]); do
        n1ton2=${errfile##*_}
        n1=${n1ton2%to*}
        n2=${n1ton2#*to}
        new_errfile=${errfile%_*}_$((n1+20))to$((n2+20))
        echo mv -v -- "$errfile" "$new_errfile"
    done
    
    • Remove the echo if you are happy that the code will do what you want.
    • shopt -s ... enables some Bash settings that are required by the code:
      • extglob enables "extended globbing" (including patterns like +([0-9])). See the extglob section in glob - Greg's Wiki.
      • nullglob makes globs expand to nothing when nothing matches (otherwise they expand to the glob pattern itself, which is almost never useful in programs).
    • See Removing part of a string (BashFAQ/100 (How do I do string manipulation in bash?)) for explanations of ${var##pat}, ${var%pat}, and ${var#pat}.
    • Note that ALL_UPPERCASE variable names (like FILE) are best avoided because there is a danger of clashes with the large number of special ALL_UPPERCASE variables that are used in shell programming. See Correct Bash and shell script variable capitalization. That's why I used errfile instead of FILE.