make(s)
Yesterday I told you that today I'll be teaching you how to make a sandwich. This is not really what I meant. What I meant is "Learn how to use make
to build modular scripts".
Imagine this:
- You have a script that runs rsync to backup your Documents folder.
- You run rsync locally and then you want to upload the folder to a FTP server.
- You don't want to upload the files in that folder to the server immediately after uploading them to your backup drive, or you aren't connected to the Internet all the time and running the script will generate a harmless error, but you don't want to redirect the output to that command, etc.
You can't call functions from a script, independently. For example, myscript.sh myfunction()
won't work. You can use arguments in that script to trigger a specific function ( like myscript.sh upload_locally
) but IMHO it's a pain in the butt for 2 simple lines.
I think using a Makefile
and make
command is the simplest, fastest way to do it. Let's find out how to write a Makefile in the lines below.
Makefile
upload_locally:
rsync command for local backup goes here
upload_ftp:
rsync command for FTP backup goes here
Broken down you practically construct 2 "functions" (upload_locally
and upload_ftp
) that when called via make upload_locally
for example, they run the command(s) that are after ":". That's four lines. And this is it. That's the Makefile
.
Yes, you can make the same thing in a shell script, but how many lines are there in it? Let's "port" the Makefile:
myscript.sh
function upload_locally() { rsync command for local backup goes here; }
function upload_ftp() { rsync command for FTP backup goes here; }
$@
Three lines. One less, but far more things to write. And posibly complicated. (Note that #!/bin/bash can be omitted) But can you run it independently? Yes. You can. Though, can you run it altogether? (Like myscript arg1 arg2
) Nope. You can't. (Actually you can, but implementing this for 2 lines, without another function it isn't worth it, trust me.)
function testA(){ echo "Test A"; }
function testB(){ echo "Test B"; }
$@
myscript testA testB
Test A
Running make arg1 arg2
will run the 2 "functions" named arg1
and arg2
inside the Makefile.
Now let's go a little further:
Makefile
all: upload\_locally upload\_ftp
upload_locally:
rsync command for local backup goes here
upload_ftp:
rsync command for FTP backup goes here
Running make all
will run upload_locally and upload_ftp.
And let's do the same with myscript
.
myscript
function testA(){ echo "Test A"; }
function testB(){ echo "Test B"; }
function all() { testA(); testB();}
$@
Condensed and amateurish, the file myscript
has 4 lines. Without #!/bin/bash
.
Running myscript all
will call the functions testA and testB.
The file Makefile
is written correctly from a syntax, indentation and style point of view. Let's write the bash script in a more readable way and let's use a (more) correct style for it.
myscript
#!/bin/env bash
function testA()
{
echo "Test A";
}
function testB()
{
echo "Test B";
}
function all()
{
testA(); testB();
}
$@
I think it isn't worth it using a script with 3 functions when you can use a Makefile
.
Oh, have you noticed how I didn't use the word function for Makefiles? That's because the functions are named "rules" in Makefiles. You are writing a Makefile with rules for make
command to execute.
Now the bonus.
A friend told me that he has a site written entirely in bash. You can visit it here. It's a site that automatically writes jokes on a image and publishes them to his site. The jokes are taken from another site, but I still find it nice.
Below you can find a script that he wrote:
youtube-dl -o "%(title)s.%(ext)s" --extract-audio --audio-format=mp3
for i in *.mp3 ; do ffmpeg -i "$i" -ac 2 -ab 64k -ar 44100 "conv_$i"; done
He also said that he has a lot of other scripts but wanted me to post this specific one here. It's more a wrapper for a program called youtube-dl
.
It uses ffmpeg
and what it does is converting a mp3 file downloaded from YouTube to a lo-fi version of it. In case that you don't care about quality or you don't have much space left on your audio player, this can be useful.
Don't use it on your mp3 files from your PC unless you want quality loss!
You have been warned!
PS: I've uploaded a 3D LEGO model on Images page. Check it out!
Comments !