Welcome back to my Shell Scripting vs Programming series. This is part deux.
In the introduction, I gave you a taste of just how simple it can be to create a shell script. Add a few commands to a file, save it, then execute the file. That’s it. The shell, bash, executes the three commands in that file and exits. Sometimes, the simplest shell script imaginable is the command itself. Imagine a command with a number of options and flags. In previous series on Mastering the Linux Shell, I had a tutorial on using the find command to locate large files that haven't been modified in quite some time. The rather long command looks something like this.
find /path/starting_folder -size +1024 \( -mtime +365 -o -atime +365 \) -ls
To make life easier, you could create an alias for the command and put in in your local .bashrc file so that the command is available whenever you log in.
alias findbig='find /path/starting_folder -size +1024 \( -mtime +365 -o -atime +365 \) -ls'
I could make several aliases for different starting folders and call them findbig_downloads, findbig_home, findbig_wherever and so on. Now all I had to do was type the appropriate findbig command and I'd have my list of big old files without having to type the long find command each time. Another way to do this would have been to type the command into a file called findbig_whatever, save it in /usr/local/bin, and make it executable, which would have produced the same effect. Rather than an alias, I would have had a shell script. Here are the steps:
Once you have typed in the command, save your work. The next step is to make it executable.
chmod +x /usr/local/bin/findbig_whatever
I then create one shell script for each of the incarnations of finding big old files I want, save those, and make each and every one of them executable as well. But wait! Wouldn't it be a lot nicer to have just one script and supply the path I want to search as a parameter to that one command. Sounds great, but how do I pass the path that I want to search? If I just run this script by typing /usr/local/bin/findbig_whatever marcel, it doesn’t search anything other than /path/starting_folder. That’s because the script isn’t using the information being passed to it. This brings us to the subject of parameters.
Here’s a really simple way to experience how the shell interprets parameters passed to it. Write this little script and call it paramtest:
#!/bin/bash # This script demonstrates positional parameters # echo "This is parameter 0 : $0" echo "This is parameter 1 : $1" echo "This is parameter 2 : $2" echo "This is parameter 3 : $3" echo "Here are all the parameters : $*"
Make it executable with chmod +x paramtest. Now, execute it like this:
./paramtest this is a shell script
This is the output you will see:
This is parameter 0 : ./paramtest This is parameter 1 : this This is parameter 2 : is This is parameter 3 : a Here are all the parameters : this is a shell script
The first thing you should notice is that the script name (or the command, if you prefer) is parameter $0. Parameters $1, $2, and $3 are the first three words passed to the script. Notice also that the last two words, “shell script,” have simply been absorbed by the script. These would have been represented by $4 and $5, which you did not ask to have echoed to the screen. How about the last line? As you can see, the entire list of parameters (not counting the program name) is echoed back.
A First Look at Variables
The $0, $1, $2, and so on, are variables. In other words, they can represent different values depending on what parameters are passed to your script. The $* variable is a special one in that it represents all the parameters passed to the shell. Like the $number variables, this is one is built into the shell itself. You do not have to define it.
So, going back to the findbig example, I could modify the script by simply adding a $1 where the command is expecting the pathname. Then, passing a pathname would work. Here’s the resulting script now:
find $1 -size +1024 \( -mtime +365 -o -atime +365 \) -ls
To make the script more intelligent, I could add a check for a parameter using the “if” construct. The following is my updated script. I am also going to specify that I always want to use the bash shell for execution. Enter the information as you see it, save the file and make it executable as before.
#!/bin/bash # This script will look for and list big old files in a folder if [ $# -eq 0 ] then echo "findbig : You must specify a pathname" exit 0 else find $1 -size +1024 \( -mtime +365 -o -atime +365 \) -ls fi
Lots of stuff here. The script checks to see if there are any parameters at all. If the count of parameters (that’s what the variable, $# means) is zero, it prints an error message and exits. If I remembered to pass it a pathname, I get a nice list of big old files, using whatever starting folder I chose.
$ findbig /home/marcel . . . long file listing will appear here . . .
You've gone from creating several scripts to a single, all purpose one. This is where I will leave it until next time.
As usual, if you wish to comment, please do so on Google Plus in the comment form below, or over here on Facebook and add me to your circles or friend list if you haven't already done so; oh yeah, if you're on Twitter, follow me there. Also, make sure you sign up for the mailing list over here so that you're always on top of what you want to be on top of. And a final request, please share this article with your favorite Linux and FOSS group or news site; I would sincerely appreciate it. Until next time . . .
A votre santé! Bon appétit!