TIL: How to replace keywords in a file name and content with Bash

Cesar Aguirre - Dec 12 '22 - - Dev Community

I originally published this post on my blog. It's part of my personal C# Advent of Code.

These days I needed to rename all occurrences of one keyword with another in source files and file names. In one of my client's projects, I had to query one microservice to list a type of account to store it in an intermediate database. After a change in requirements, I had to query for another type of account and rename every place where I used the old one. This is what I learned.

My original solution was to use Visual Studio to replace "OldAccount" with "NewAccount" in all .cs files in my solution. I used the "Replace in Files" menu by pressing: Ctrl + Shift + h.

With the "Replace in Files" menu, I covered file content. But I still had to change the filenames. For example, I needed to rename IOldAccountService.cs to INewAccountService.cs. I did it by hand. Luckily, I didn't have to replace many of them. There must be a better way!- I thought.

After renaming my files by hand, I thought I could have used the command line to replace both the content and file names. I use Git Bash anyways. Therefore I have access to most of Unix commands.

1. Replace 'old' with 'new' inside all .cs files

This is how to replace "Old" with "New" in all .cs files, Source

grep -irl --include \*.cs "Old" | xargs sed -i 's/Old/New/g'
Enter fullscreen mode Exit fullscreen mode

With the grep command, we look for all .cs files (--include \*.cs) containing the "Old" keyword, no matter the case (-i flag), inside all child folders (-r), showing only the file path (-l flag).

We could use the first command, before the pipe, to only list the .cs files containing a keyword.

Then, with the sed command, we replace the file content in place (-i flag), changing all occurrences of "Old" with "New" (s/Old/New/g). Notice the g option in the replacement pattern.

This first command does what Visual Studio "Find in Files" does.

2. Rename 'old' with 'new' in filenames

Instead of renaming files by hand, this is how to replace "Old" with "New" in file names, Source

find . -path ./TestCoverageReport -prune -type f -o -name "*Old*" \
  | sed 'p;s/Old/New/' \
  | xargs -d '\n' -n 2 mv
Enter fullscreen mode Exit fullscreen mode

This time, we're using the find command to "find" all files (-type f), with "Old" anywhere in their names (-name "*Old*"), inside the current folder (.), excluding the TestCoverageReport folder (-path ./TestCoverageReport -prune).

Optionally, we can exclude multiple files by wrapping them inside parenthesis, like, Source

find . \( -path ./FolderToExclude -o -path ./AnotherFolderToExclude \) \
    -prune -type f -o -name "*Old*"
Enter fullscreen mode Exit fullscreen mode

Then, we feed the sed command to generate new names replacing "Old" with "New." This time, we're using the p option to print the "before" pattern. Up to this point, our command returns something like this,

./Some/Folder/AFileWithOld.cs
./Some/Folder/AFileWithNew.cs
...
Enter fullscreen mode Exit fullscreen mode

With the last part, we split the sed output by the newline character and passed groups of two filenames to the mv command to finally rename the files.

Another alternative to sed followed by mv would be to use the rename command, like this,

find . -path ./TestCoverageReport -prune -type f -o -name "*Old*" \
  | xargs rename 's/Old/New/g'
Enter fullscreen mode Exit fullscreen mode

Voilà! That's how to replace a keyword in the content and name of files. It took me some time to figure this out. But, we can rename files with two one-liners. It will save us time in the future. Kudos to StackOverflow.

Do you use the command line too? What Bash command or one-liners have saved your day? Feel free to leave a comment.

Stay tuned to my C# Advent of Code Posts.


Hey, there! I'm Cesar, a software engineer and lifelong learner. Visit my Gumroad page to download my ebooks and check my courses.

Happy coding!

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .