I have a directory contains image files that are to be echoed in bash. While echoing, I want to replace both file name and extension in single line command.

Example files:


Normally, I can do single replacement like this:

for i in images/*; do echo ${i/file/image}; done

And the output becomes like:


How can I keep it in for loop and replace the "jpg" string to "png" also? It's just an instance, I could replace the dot to comma etc.

When I try this:

for i in images/*; do echo ${{i/jpg/png}/file/image}; done

It doesn't work. I coulnd't find any other solution or idea. Is this possible -if so, how?

  • I don't know why this didn't work in bash, but nested replacements do work just like you expected in zsh. Depending on your environment you might consider using a better shell ;)
    – Caleb
    Commented Jun 12, 2014 at 12:08

3 Answers 3


The simple approach would be to assign the result to a variable, then work with that variable. Example:

for filename in images/*
    echo "filename is now $filename"
    filename=${filename/jpg/png}; echo "filename is now $filename"
    filename=${filename/file/image}; echo "filename is now $filename"
    echo "final filename is ${filename}"
  • 1
    This answer is not complete. the substitutions will apply anywhere in the filename strings. Based on the question, Kubilay wants to replace a prefix and an extension (suffix). can you modify and take this into consideration: ${var/#Pattern/Replacement} If prefix of var matches Pattern, then substitute Replacement for Pattern. ${var/%Pattern/Replacement} If suffix of var matches Pattern, then substitute Replacement for Pattern.
    – UnX
    Commented Apr 18, 2014 at 11:49
  • @rMistero There's no rule against posting another answer just because an answer has been accepted. In fact, I think you should, especially since the semantics of what you are proposing are different. That said, this is the way to do what the OP said having tried, so even if there are other results that could also be valid, I believe it is safe to assume that this is in line with what the OP wanted to accomplish.
    – user
    Commented Apr 18, 2014 at 16:41

You can assign the previous replacement to a variable and run replace on that variable instead

for i in images/*
    echo ${j/file/image}
  • Not sure if it works. "for i in images/*; do j={i/jpg/png} echo ${j/file/image}; done" echoes "{i/jpg/png}" repeatedly.
    – kubilay
    Commented Apr 18, 2014 at 10:54
  • Now yes: "for i in images/*.jpg; do j=${i/jpg/png}; echo ${j/file/image}; done". Thanks!
    – kubilay
    Commented Apr 18, 2014 at 11:10

to change any string:

$ echo "images/file_name_1.jpg" | perl -pE 's/file/image/;s/jpg$/png/;'

a shortcut to rename (which may be the ultimate goal:

$ rename 's/file/image/;s/jpg$/png/;' "$i"
  • I still think invoking Perl once for each file is overkill, but at least now this gives an answer to the question. :)
    – user
    Commented Apr 18, 2014 at 10:54
  • @MichaelKjörling You don't need to invoke Perl for each file, you can do rename … images/*. But this requires a Debian-based distribution (rename on other Linux variants is a completely different command). Commented Apr 18, 2014 at 21:29
  • @Gilles I was thinking more about the first version, particularly since there's nothing in the question as asked about renaming files. The original (grace period edited) version of this answer had only the rename command suggestion.
    – user
    Commented Apr 18, 2014 at 21:30

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .