0

I've got a bunch of files with names like image(1) image(2) image(3) . I'd like to rename those en masse along the lines of image1.jpg image2.jpg etc. I can do it in two steps by means of curly braces , which apparently is some sort of built-in shell provision for string replacement along the lines of

orig="a_string"
mod=${orig/string/new_thing}

which takes a_string to a_new_thing. So using that in a for loop I can take care of turning the ) into .jpg

for f in *; do mv $f "${f/)/.jpg}" ;done

and then

for f in *; do mv $f "${f/\(/}" ;done

removes the (. The open paren has to be escaped , I suppose as otherwise the shell thinks its the start of something else. The close paren doesn't have to be escaped like that. So my question is , is there a one-liner or other better way to do this, like using pipes. If the parens in the filename are mucking things up then assume for the time being these parens are removed , leaving the bare problem of replacing two substrings with two other strings .

icarus
  • 17,920

3 Answers3

1

You can rename multiples files using the command rename. In this case a working solution could be:

rename 's/\(//; s/\)/.jpeg/;' image*
andreatsh
  • 2,025
  • 1
    You should note that this uses the Debian version of rename. The syntax for the Fedora family's rename is quite different. See http://unix.stackexchange.com/a/238862/135943 – Wildcard Nov 22 '16 at 22:09
  • @jeremy_rutman, if this answer solved your question you should accept it by clicking the checkmark to the left of the answer. – Wildcard Nov 22 '16 at 22:14
  • @Wildcard Honestly I didn't know that the syntax for the Fedora family's rename is different. I saw the question of the link and your answer is very accurate, thanks! – andreatsh Nov 22 '16 at 22:36
0

You can change more than one thing at a time by using a double slash.

for f in * ; do mv "$f" "${f//[()]/}.jpg" ; done
icarus
  • 17,920
0

I’ll address your general question of how to do multiple substitutions (specifically, in a rename, although this may be applicable to other contexts).  I’ll suppose that you have a bunch of files whose names include the words “over” and “dog”, and you want to replace them with “under” and “cat”, respectively.

Brute force:

for f in *
do
    g=${f/over/under}
    h=${g/dog/cat}
    mv -- "$f" "$h"
done

(The -- protects you against undesired behavior that could result from a filename that begins with -.  Change the last line to mv -- "$f" "$h".jpg if you want.)  Note that, if a filename contains only “over” or “dog” (but not both), this will do just the one available substitution.  If it contains “dog” and “over” (in that order), it will still do the substitutions.  In the case you presented, where your strings are “(“ and “)”, you might not like these behaviors.

P.S. Realistically, you should probably protect the mv command like this:

if [ "$f" != "$h" ]
then
    if [ -e "$h" ]
    then
        (Error handling)
    else
        mv -- "$f" "$h"
    fi
done

to avoid getting an error message when you try to rename a file to itself (because its name didn’t contain either of the strings), and to avoid clobbering an existing file (e.g., if you have an image(1) file and you also already have an image1.jpg file).

with sed

for f in *
do
    g=$(sed 's/\(.*\)over\(.*\)dog\(.*\)/\1under\2cat\3/' <<< "$f")
    mv -- "$f" "$g"
done

This is the opposite of the first one: it does the substitutions only if “over” and “dog” both appear (in that order) and not otherwise.

The <<< (“here string”) syntax doesn’t work in all shells.  To do the above in a shell that doesn’t support here strings, do:

for f in *
do
    g=$(printf "%s" "$f" | sed 's/\(.*\)over\(.*\)dog\(.*\)/\1under\2cat\3/')
    mv -- "$f" "$g"
done