Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Renaming a file using a regular expression and x=${...} in Bash?

I have a bunch of files which contain prefix codes in brackets. I'd like to turn these prefixes into suffixes, like so:

Finance-(4BF)-001.doc   --> Finance-001-4BF.doc
Corporate-(K04)-001.doc --> Corporate-001-K04.doc

I previously wrote a very simple VBScript to do this on a Windows machine but now I need to do this on Linux. After some tedious searching I can't find a simple and elegant way to apply a regular expression to a filename and rename it using the regex matches.

So far I have this:

#!/bin/bash
for i in *.doc
do
    x=${i//[\(\)]/}
    echo "$i renames to: $x"
done

The output of this is:

Corporate-(K04)-001.doc renames to: Corporate-K04-001.doc
Finance-(4BF)-001.doc renames to: Finance-4BF-001.doc

I know the regular expression above is just stripping the brackets () out of the filename... but surely there must be a way to match their contents (e.g. \((\w)\)) and then use that match in the rename command (e.g. $1)?

Also being a Linux novice I don't understand what x=${...} is doing, and since I don't know what it's called I can't Google it. I presume it's applying a regex to the string i but in that case why can't I extract matches from it like $1 and $2 etc?

Thanks!

like image 770
WackGet Avatar asked Jan 15 '23 15:01

WackGet


2 Answers

The construct ${...} is called "parameter expansion" and can be found in the Bash manual.

The replacement feature is very elementary and does not support backreferences ($1). You can use sed instead:

x=$(sed -E 's/\(([[:alnum:]]+)\)-([[:alnum:]]+)/\2-\1/' <<< "$i")

Note that [[:alnum:]] is the same as \w in other languages, but POSIX regular expressions don't have the latter. See man re_format for details.

like image 129
user123444555621 Avatar answered Jan 23 '23 10:01

user123444555621


The ${parameter/pattern/string} syntax in Bash parameter expansion is not a regular expression; it is a glob (with # and % treated specially).

Bash has [[ =~ ]] conditional expressions taking regular expressions, which puts captured groups into the ${BASH_REMATCH[@]} array.

#!/bin/bash
for i in *.doc; do
    if [[ $i =~ ^(.*)-\((.*)\)-([^.]*)(..*)?$ ]]; then
        x="${BASH_REMATCH[1]}-${BASH_REMATCH[3]}-${BASH_REMATCH[2]}${BASH_REMATCH[4]}"
        echo "$i renames to: $x"
    fi
done
like image 21
ephemient Avatar answered Jan 23 '23 11:01

ephemient