One-Liner for git mv

Here's a one-liner for changing a bunch of filenames all at once. Say you've got a bunch of `.jsx` files, but you agree with the React team that the `.jsx` file extension has outlived its usefulness. How do you rename all those files to end in `.js` in just one line of bash code?

Like this:

for filename in $(ls src/*.jsx); do git mv $filename $(echo $filename | sed -E "s/jsx/js/"); done

For readability, on multiple lines it looks like this:

$ for filename in $(ls src/*.jsx)
> do git mv $filename $(echo $filename | sed -E "s/jsx/js/")
> done

This code works by embedding the output of subshells as strings. The first subshell runs a very simple command which gets a list of files:

ls src/*.jsx

The next does something more complicated:

echo $filename | sed -E "s/jsx/js/"

This runs the s/jsx/js regular expression pattern substitution through sed. Note that the -E option is specific to macOS bash. In other shells, you might need -e or other command-line flags instead. When I wrote this command, I spent ten seconds writing everything else, and about 15 minutes tracking down the right syntax for sed.

Anyway, sed stands for "stream editor", so if you pipe the output of echo SomeComponent.jsx into sed like this, it's going to edit that stream and pass it through as the string SomeComponent.js. Since $() passes along its subshell output as a string, that becomes:

git mv SomeComponent.jsx SomeComponent.js

And because it's iterating over your ls subshell, you'll run that for every .jsx file in your src/ directory.