Score:-2

How to rename files in ubuntu, recursively, using grep and rename not find?

cn flag

There are gazillions of questions and answers regarding how to rename files. I'm new to Linux and this myriad of possible ways and different results and different configurations confuses me.

For example:

  • rename works, but not recursively
  • grep works recursively, but can't be used to search for file and directory names, instead of file contents
  • find works, but has a long ugly syntax when you want to search using regular expressions.

And also a lot of answers on ask ubuntu and stackoverflow do not work for me and I don't know how to debug and troubleshoot them.

So, forgive me to ask it one more time.

I'm searching for a clean, memorizable way of:

Renaming files recursively using simple regular expression.

I already do it for the content of files using this syntax:

grep -rl search_regex | xargs sed -i 's/old/new/g'

It works without a lot of frustration. It works out of the box. It just works. I'm searching for a workable solution that is neat and clean. Can you help me please?

muru avatar
us flag
"Clean", "memorizable", "ugly" all in the eye of the beholder. This question cannot be objectively answered and should be closed as opinion-based
Saeed Neamati avatar
cn flag
@muru, it's already answered.
muru avatar
us flag
I can see that, and by judging the quality of the accepted answer, what I said remains true.
lys avatar
nl flag
lys
Google Search led me here. The answer below using `globstar` helped me fix the same problem.
Score:4
in flag

Cannot find anything long and ugly about find:

find . -regex 'search_regex' -exec rename 's/old/new/g' {} +
Saeed Neamati avatar
cn flag
If you see the answer of @wizardpurple, you realize that this syntax is ugly. Why should I specify `-regex` switch? Also why `-exec` when I can use simple pipe? Also what is that `+` at the end? Also with `grep` I can omit those single quotes from around my regex. `find . | grep search | rename 's/old/new/g'`.
pLumo avatar
in flag
Your arguments are wrong. Why is pipe better than `-exec`? Pipe introduces issues (see my comment on @wizardpurple's answer). Btw: You cannot omit quotes around your regex, this is simply wrong.
pLumo avatar
in flag
If ugly/complicated means *"I don't know the syntax"*, you might be right. I think pipe and `grep` is more complicated, especially, when you care about the issues that come with it (which are not cared about in his answer).
Saeed Neamati avatar
cn flag
ugly and complicated means that after reading almost 20 questions, I couldn't solve my problem. Clean means after reading one simple answer, my problem is solved. I'm not talking about my understanding as the criteria for simplicity. I'm talking about productivity as the criteria here.
pLumo avatar
in flag
and how does this `find` command not suffice your needs for "*my problem is solved*"? This is cleaner, faster and has less issues.
Saeed Neamati avatar
cn flag
I told you the issues in the previous comment. Universality matters. When I use `grep` I don't need to wrap it in single quotes. I'm dealing with **ONE** universal syntax. I also know that I'm always working with regular expressions. Also, piping is just the easiest way to combine stuff. Piping is much easier than knowing switches. These are my reasons for productivity.
pLumo avatar
in flag
Let us [continue this discussion in chat](https://chat.stackexchange.com/rooms/126448/discussion-between-plumo-and-saeed-neamati).
vanadium avatar
cn flag
Add quotes so it handles spaces correctly (`"{}"`). If the number of files is very long, then the argument may become too long. Using `\;` at the end instead of `+` will prevent that, but it will become slower: the `rename` command is then executed each time again for each individual file. However, you can handle an unlimited number of files.
pLumo avatar
in flag
@vanadium --> `find` cares about spaces without quotes around `{}`. Same for max arguments `find -exec ... +` will take care and only send as much arguments as possible.
vanadium avatar
cn flag
@pLumo, so it is quite smart! Good to know!
Score:2
cn flag

You can make rename recursive if that's the syntax you prefer:

shopt -s globstar
rename 's/old/new/' **/*

Bash's globstar option makes ** match 0 or more directories or files recursively, so **/* will recurse down the entire directory tree. You just need to write your search pattern as a glob instead of a regular expression. For example, to rename all files whose name contains foo, you would do:

shopt -s globstar
rename 's/old/new/' **/*foo*
Score:0
cn flag

You should be able to more or less keep the same format you had with grep and sed, though I think you'll still need a tool like find to supply grep with files to search through.

Edit: updated with information from the comments. thanks @pLumo and @terdon for showing it would fail for files with newline characters in the name.

find /some/directory -print0 | grep -zE "search_regex" | rename -0 's/old/new/g'
pLumo avatar
in flag
You should use null as delimiter, as newline is a valid character for a filename. Use: `find -print0`, `grep -z` and `rename -0`.
Saeed Neamati avatar
cn flag
Now, this is clean and memorable. I tested it, and it simply worked. No need to change anything. Thank you so much. `find . | grep search | rename 's/old/new/g'`
terdon avatar
cn flag
This will fail on file names that contain newlines @SaeedNeamati and wizardpurple.
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.