For loops in bash / zsh shells - 01-12-20

Looping directly in the shell is something I do at lease once a week and it’s a great time saver. Here I want to run through a concrete example of how to use for loops to mass move and rename files.

During process of getting this snippet section of my site off the ground I realize I had put a bunch of markdown files into named directories when I could have just named the files better and done without the directories. What I needed to do was mv the files out of these dirs and rename them to the name of the dir plus add the “.en.md” extension.

Here is the old directory structure:

$ tree
.
└── snippets
    ├── _index.en.md
    ├── aws-cloud-front-inval
    │   └── index.en.md
    ├── aws-s3-sync
    │   └── index.en.md
    ├── ffmpeg-screen-casts
    │   └── index.en.md
    ├── find-folder
    │   └── index.en.md
    ├── git-better-git-add
    │   └── index.en.md
    ├── git-log-grep
    │   └── index.en.md
    ├── git-move-branch
    │   └── index.en.md
    .
    .

To start with I preformed the operation in question a single time to prove it works:

$ mv ./who-is-using-that-port/index.en.md ./who-is-using-that-port.en.md && rm -r ./who-is-using-that-port

Then I copy this command to the clipboard for later and use command history pull up a previous for loop command and switch the shell command entry external editing in vim mode, for me <C-x><C-e>. As we are essentially writing a quick bash script in-line we need vim powers! While in vim if you need the file list a quick :r !ls does the trick. These little efficiencies like using command history are not just faster but make it so you don’t have to remember the bash syntax.

Resulting vim buffer with the for loop:

for x in \
aws-s3-sync \
ffmpeg-screen-casts \
find-folder \
git-better-git-add \
git-log-grep \
...
git-move-branch \
vim-window-resize ; do mv ./"$x"/index.en.md ./"$x".en.md && rm -r "$x" ; done

Resulting new file structure:

$ tree
.
└── snippets
    ├── _index.en.md
    ├── aws-cloud-front-inval.en.md
    ├── aws-s3-sync.en.md
    ├── ffmpeg-screen-casts.en.md
    ├── find-folder.en.md
    ├── git-better-git-add.en.md
    ├── git-log-grep.en.md
    ├── git-move-branch.en.md
    .
    .

Perfect, all files have been renamed properly and the empty directories deleted. This technique has lots of other applications besides moving and renaming files. Earlier this week while debugging api at work I dumped bunch of json responses into a file so I could search for translation key.

$ for x in \
https://api.poeditor.com/v2/download/file/xxx \
https://api.poeditor.com/v2/download/file/xxx \
https://api.poeditor.com/v2/download/file/xxx \
https://api.poeditor.com/v2/download/file/xxx \
https://api.poeditor.com/v2/download/file/xxx \
https://api.poeditor.com/v2/download/file/xxx \
https://api.poeditor.com/v2/download/file/xxx \
https://api.poeditor.com/v2/download/file/xxx \
https://api.poeditor.com/v2/download/file/xxx \
https://api.poeditor.com/v2/download/file/xxx ; do curl $x >> /tmp/translations.json; done
\- [ zsh, built-ins ]