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 Jun 12 '14 at 12:08

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}"
|improve this answer|||||
  • 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 Apr 18 '14 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. – a CVn Apr 18 '14 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}
|improve this answer|||||
  • 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 Apr 18 '14 at 10:54
  • Now yes: "for i in images/*.jpg; do j=${i/jpg/png}; echo ${j/file/image}; done". Thanks! – kubilay Apr 18 '14 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"
|improve this answer|||||
  • I still think invoking Perl once for each file is overkill, but at least now this gives an answer to the question. :) – a CVn Apr 18 '14 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). – Gilles 'SO- stop being evil' Apr 18 '14 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. – a CVn Apr 18 '14 at 21:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.