Rename/move (mv) multiple files starting with name

Viewed 745

I'm trying to rename multiple files that match a pattern in one directory.

Files:

stack_overflow_one.xml
stack_overflow_two.xml
stack_overflow_one.html

I would like to rename stack_overflow to heap_graph

heap_graph_one.xml
heap_graph_two.xml
heap_graph_one.html

I have tried the following:

Using rename:

rename stack_overflow heap_graph stack_overflow* # returns 'The syntax of the command is incorrect.'

Using for loop in Bash

# how can I write this in one line? I've tried wrapping in one line, but also does not work
for i in stack_overflow* do
    mv "$i" "${i/stack_overflow/heap_graph}"
done

However, none of these are working.

2 Answers

What you have is a trivial syntax error in the for loop. The rest of your script should work fine without any problem.

for i in stack_overflow*; do
#                      ^^^ missing semi-colon
# The below condition to handle graceful loop termination when no files are found
    [ -f "$i" ] || continue
    mv "$i" "${i/stack_overflow/heap_graph}"
done

As noted by ghoti below if you are in the bourne again shell bash and not the POSIX bourne shell (sh) for which the solution above is portable, you can use special globbing options to avoid the condition of having to deal with case when no files are returned by the glob.

shopt -s nullglob
for i in stack_overflow*; do
    mv "$i" "${i/stack_overflow/heap_graph}"
done

shopt -u nullglob

The -s option sets it and -u unsets it. More on shopt built-in from the GNU bash page

The semi-common utility mmv (article) is useful for the "multi-move" case you've described.

$ mmv -n 'stack_overflow_*' 'heap_graph__#' # remove -n after testing
mv -- stack_overflow_one.html heap_graph_one.html
mv -- stack_overflow_one.xml heap_graph_one.xml
mv -- stack_overflow_two.xml heap_graph_two.xml

As you can see, it's just calling down to mv multiple times for the pattern(s) matched.

The * is a wildcard like Bash uses, but it's quote-escaped to be passed to mmv. The _# is the reference to the match, also escaped (though the docs suggest #1 would work instead).

This family of commands is also handy for copying (cp) and linking (ln).


If you happen to have Zsh (a common Bash upgrade/replacement), you've already got zmv, which would similarly do the job with:

% zmv -n 'stack_overflow_(*)' 'heap_graph_$1'
Related