Shellmap is a tiny pseudo-xargs script that helps to chain or sequence variants of a shell command using placeholders.
$ python shellmap.py "<base command with N placeholders>" "<placeholder 1>"
"<placeholder 2>" ... "<placeholder N>" [--print|--run]
$ python shellmap.py --help
usage: shellmap.py [-h] [--print] [--run] N [N ...]
Chain/sequence shell scripts.
positional arguments:
N Command string with placeholders, followed by arguments.
optional arguments:
-h, --help show this help message and exit
--print Print the output commands
--run Run the output commands
$ python shellmap.py "echo \$1@ \$2@ \$1@" "%ls" "is,is not" --print
echo LICENSE is LICENSE
echo LICENSE is not LICENSE
echo README.md is README.md
echo README.md is not README.md
echo shellmap.py is shellmap.py
echo shellmap.py is not shellmap.py
$ python shellmap.py "echo \$1@ \$2@ \$1@" "%ls" "is,is not" --run
LICENSE is LICENSE
LICENSE is not LICENSE
README.md is README.md
README.md is not README.md
shellmap.py is shellmap.py
shellmap.py is not shellmap.py
Say we have the following directory structure:
month_reports/
date_reports/
15.csv
16.csv
17.csv
Jan_2015.txt
Feb_2015.txt
We wish to create a new directory final_reports, and make new files for each permutation of the dates, months and one of pre, curr, and post, in the format DD_MMM_YYYY_[pre|curr|post].txt. The final directory structure needs to be like this:
month_reports/
final_reports/
15_Jan_2015_pre.txt
15_Jan_2015_curr.txt
15_Jan_2015_post.txt
16_Jan_2015_pre.txt
16_Jan_2015_curr.txt
16_Jan_2015_post.txt
17_Jan_2015_pre.txt
17_Jan_2015_curr.txt
17_Jan_2015_post.txt
15_Feb_2015_pre.txt
15_Feb_2015_curr.txt
15_Feb_2015_post.txt
16_Feb_2015_pre.txt
16_Feb_2015_curr.txt
16_Feb_2015_post.txt
17_Feb_2015_pre.txt
17_Feb_2015_curr.txt
17_Feb_2015_post.txt
date_reports/
15.csv
16.csv
17.csv
Jan_2015.txt
Feb_2015.txt
We have three positional arguments, one for the date, one for the month_year, and one for [pre|curr|post]. First we'd like to check the output commands to see what's going to run. So here's what we do, using the format \$N@
for positional arguments:
$ mkdir final_reports && cd $_
$ shellmap "touch \$1@_\$2@_\$3@.txt" "15,16,17" "Jan_2015,Feb_2015" "pre,curr,post" --print
touch 15_Jan_2015_pre.txt
touch 15_Jan_2015_curr.txt
touch 15_Jan_2015_post.txt
touch 15_Feb_2015_pre.txt
touch 15_Feb_2015_curr.txt
touch 15_Feb_2015_post.txt
touch 16_Jan_2015_pre.txt
touch 16_Jan_2015_curr.txt
touch 16_Jan_2015_post.txt
touch 16_Feb_2015_pre.txt
touch 16_Feb_2015_curr.txt
touch 16_Feb_2015_post.txt
touch 17_Jan_2015_pre.txt
touch 17_Jan_2015_curr.txt
touch 17_Jan_2015_post.txt
touch 17_Feb_2015_pre.txt
touch 17_Feb_2015_curr.txt
touch 17_Feb_2015_post.txt
Great! The commands look valid. Time to run them.
$ shellmap "touch \$1@_\$2@_\$3@.txt" "15,16,17" "Jan_2015,Feb_2015" "pre,curr,post" --run
$ ls
15_Feb_2015_curr.txt 15_Jan_2015_curr.txt 16_Feb_2015_curr.txt 16_Jan_2015_curr.txt 17_Feb_2015_curr.txt 17_Jan_2015_curr.txt
15_Feb_2015_post.txt 15_Jan_2015_post.txt 16_Feb_2015_post.txt 16_Jan_2015_post.txt 17_Feb_2015_post.txt 17_Jan_2015_post.txt
15_Feb_2015_pre.txt 15_Jan_2015_pre.txt 16_Feb_2015_pre.txt 16_Jan_2015_pre.txt 17_Feb_2015_pre.txt 17_Jan_2015_pre.txt
Suh-weet! That worked. But wait, what if we have 31 date files in date_reports instead of 2? Do we have to type them all out in a comma-separated list? Why can't we just take the output of some shell command that will give us a list of those files? Like ls
?
Prefacing an argument list with %
substitutes the list with the output of the command after the %
. For instance, typing "%ls date_reports/"
in our case would run ls date_reports/
, take the output list, and place it there. Let's try that:
$ python shellmap.py "touch \$1@_\$2@_\$3@.txt" "%ls ../date_reports/" "Jan_2015,Feb_2015" "pre,curr,post" --print
touch 15.csv_Jan_2015_pre.txt
touch 15.csv_Jan_2015_curr.txt
touch 15.csv_Jan_2015_post.txt
touch 15.csv_Feb_2015_pre.txt
touch 15.csv_Feb_2015_curr.txt
touch 15.csv_Feb_2015_post.txt
touch 16.csv_Jan_2015_pre.txt
touch 16.csv_Jan_2015_curr.txt
touch 16.csv_Jan_2015_post.txt
touch 16.csv_Feb_2015_pre.txt
touch 16.csv_Feb_2015_curr.txt
touch 16.csv_Feb_2015_post.txt
touch 17.csv_Jan_2015_pre.txt
touch 17.csv_Jan_2015_curr.txt
touch 17.csv_Jan_2015_post.txt
touch 17.csv_Feb_2015_pre.txt
touch 17.csv_Feb_2015_curr.txt
touch 17.csv_Feb_2015_post.txt
Seems to work, but there's that pesky .csv in that ls
output. That's fine and dandy, we just have to use sed
to get rid of that cruft. So here's the newer version:
$ python shellmap.py "touch \$1@_\$2@_\$3@.txt" "%ls -1 month_reports/date_reports/ | sed -e 's/\..*$//'" "Jan_2015,Feb_2015" "pre,curr,post" --print
touch 15_Jan_2015_pre.txt
touch 15_Jan_2015_curr.txt
touch 15_Jan_2015_post.txt
touch 15_Feb_2015_pre.txt
touch 15_Feb_2015_curr.txt
touch 15_Feb_2015_post.txt
touch 16_Jan_2015_pre.txt
touch 16_Jan_2015_curr.txt
touch 16_Jan_2015_post.txt
touch 16_Feb_2015_pre.txt
touch 16_Feb_2015_curr.txt
touch 16_Feb_2015_post.txt
touch 17_Jan_2015_pre.txt
touch 17_Jan_2015_curr.txt
touch 17_Jan_2015_post.txt
touch 17_Feb_2015_pre.txt
touch 17_Feb_2015_curr.txt
touch 17_Feb_2015_post.txt
And there we go!
$ git clone https://github.com/pranavrc/shellmap.git
$ cd shellmap/
$ python shellmap.py --help
usage: shellmap.py [-h] [--print] [--run] N [N ...]
Chain/sequence shell scripts.
positional arguments:
N Command string with placeholders, followed by arguments.
optional arguments:
-h, --help show this help message and exit
--print Print the output commands
--run Run the output commands
To be globally executable, the script needs to be in the $PATH
.