Writing Scripts

Introduction (This intro is repeated in the alias section. It was written by Ed and is presented here with a bit of editing. My comments are in brackets.)
UNIX is text. Most configuration is done by editing plain text files. No one is perfect. And sometimes your changes can make things worse. The best way to save yourself from cursing yourself and saying, "Gee. I REALLY shouldn't have done that" is to take every step to make it possible to roll your changes back. There are many ways to ensure the roll back, but I'd like to concentrate on two of them I use. One is making searchable comments, and another is creating an .orig file.
For one-time changes (eg subtle tuning of a Makefile) I prefer searchable
[This one was a bit over my head. I'm not quite sure what the difference between Ed's two files are, but the method of using comments (a # before a line comments it out, similar to the "rem" in DOS, making it so that the line is not used--it is simply there for you to read and use its information) is fairly straightforward.
original file:
CFLAGS = -g -O2
changed file (I don't want debugging and would like to speed things up abit):
# KN
CFLAGS = -O2 -fomit-frame-pointer -pipe
#CFLAGS = -g -O2
Now I make it and if it works OK, I usually delete the source and leave the original tarball, ie my changes were true one-time, I don't want them anymore. If something goes wrong, I open the Makefile with vim, type /KN to search for my label, then do :d2 to delete two lines- my label and my line, then press Del to remove comment sign in front of original line, 7 keystrokes. Repeat as necessary.
[The above is Ed's explanation. Again, using myself as the guinea pig to test whether or not this is understandable, I feel that a little clarification is in order. (I had to read it twice to figure it out, so I figure it needs more explanation.)
So, he has changed the file. The original one is
CFLAGS= -g -02 (Nope, I dunno what this does.) He changes it to read
CFLAGS= -02 -fomit-frame-pointer -pipe
He hopes that this will work, then he'll be able to get rid of the old file, but hasn't tested it yet. So, he's put in the KN as a comment--note the # before it. This will enable him to find the file easily using vim, a text editor using /KN. The slash serves as a find function in vim. If you're using a different text editor, the chances are it has its own "find" function and just use that to find the KN. I don't use vim so I'm not quite sure about the :d2 thing--I assume it's vim's way to delete selected lines, but at any rate, just delete the new file and the KN with the text editor. Then, remove the # sign from the line with the original file, and you're back in business.]

Now Ed writes:
Tuning configuration files is another story. Sometimes I try pretty wild settings, so having an unmodified config is a must. Usually I just copy it: # cd /etc # cp modules.conf modules.conf.orig

[This is mentioned in the article below. Simply copy the file with a different name. Now, you have the original, which you can modify at will, and the backup which is renamed filename.orig. Now, back to Ed.] Now I can reap modules.conf freely as I have a guaranteed safe backup. If you are changing your configuration often, you can create two scripts, mkorig and rstorig, to create and restore original configuration: #!/bin/bash
# # mkorig -- create a backup file
[note the # mark here--Ed is commenting his script--when scripts get a little more complex, you can never have too many comments to remind you of what you were doing]
ORIG=orig echo "Copying $1 to $1.$ORIG...." cp $1 $1.$ORIG echo "Done." # End of mkorig [You should be able to see the idea. If the $1 and such are confusing, then see the rest of this article, though this script is somewhat more advanced than the ones that I discuss. Echo indicates that something is getting printed to the screen.]
I'd suggest the following rule of thumb: if your goal can be reached with a single command that requires no argument transformation, make it an alias (eg ll=ls -AFl --color), if you need to manipulate your parameters or to call different commands depending upon the result of previous operation, make a script. This rule is not perfect, but hope it helps. However, you can always make an alias mo=mkorig :)
And now, back to Scott.
I've found, in the month or two that I've been playing with Linux, that some things should be easy. However, because books or howto documents often assume that you know something,or it's something that the writer doesn't even think about, you often have to check several sources to get a complete picture. Therefore, hoping to save some people the problems that I've gone through, I'm trying to write a few newbie howtos. Being a newbie myself, I figure that I know what the newbie wants to know.

However, since I am a newbie, my howtos could be dangerous. Therefore, I get my mentor, Ed. who has very kindly taken me under his wing, to look at them, and put in the things that I left out.

Writing scripts is one of those things that should be simply explained.However, to figure out how to do it, I had to go through three or four sources, so I think it's one of those things to add to my newbies tutorial list.

I want to point out that I am using the term scripts here, but what I am referring to, though they are actual scripts are very simple things. This howto is about writing one or two line commands that you use frequently. Ed points out that scripts can easily wreck your whole system if used incorrectly, however, the samples given here should cause no problem. The type of simple scripts covered here are the one or two line commands that you find yourself writing all the time and think, gee, what a pain to keep writing this out. First of all, it's a very very easy thing to do. Secondly, it gives you confidence--if you have several scripts, well, now you're becoming a Linux ace. So, without further ado, let's begin.

Scripting can be quite powerful, doing many things that programming languages can do--there are many excellent tutorials on the web, but for this article, as mentioned, I am keeping to simple one and two line scripts This can be done in an xterm or console.

What is a script? Scripts, in this case, are simply commands that you often use. By calling the script (don't worry, this is easy) you save yourself a lot of typing. We'll use the example of mounting a CDROM. Even though you can do this one on the KDE desktop by clicking on the CDROM icon, it's something that is probably on your computer, so you can do the example step by step. Now, in RedHat and most others, the command to mount a CDROM is:
mount /dev/cdrom -t iso9660 /mnt/cdrom
Now, that's a bit of a pain in the neck to type. To digress for a moment, since I assume that if you weren't a beginner, you wouldn't be reading this, note that there is are spaces after the word "mount" "-t" and after "iso9660".

the -t iso9660 shows the file type. For example,if you're mounting a partition with Win98 fat 32 files on it, you would type
mount -t vfat If you're mounting another linux partition you'd type mount -t ext2, etc. So, first we're going to make a few preperations. You'll only have to do most of this once, and it will save you time in the long run.

Open up an xterm. For this example, we're working as root. A lot of tutorials put # before the command to show that you're doing something as root and $ to show that you're doing it as a regular user. That's a pain in the neck to type, and you're not supposed to type the # anyway--it's there already. (For those who find much of this stuff too obvious, please bear with it--this is written assuming that you know almost nothing about Linux and I feel it's better to have too much than too little.)

So, first we type:
mkdir /usr/bin/scriptx
mkdir creates a directory. We are placing this directory in the /usr/bin file and calling it scriptx. If, after doing this, you open up the graphical file manager, you'll see that there's now a folder in /usr/bin called....yup, scriptx. That's where we're going to keep all our scripts.

The next thing we have to do is make sure that the bash shell (the shell is the name for what we're using in the terminal window) knows that it has to get the scripts from that folder. The way we do this is to modify the PATH. So,open up your text editor, which on most K desktops is in the task bar. Make sure that the "show hidden" box in the lower right is checked. You should see two files marked .bashrc and .bash_profile. The dot before the file name indicates that they are hidden. In my current version of Linux, the root PATH is in .bashrc while the user one is in .bash_profile but at any rate, start by opening .bash_rc and looking for something like the following:
PATH=/sbin:/usr/sbin:/bin:/usr/bin
It might not look exactly like that, but it will be similar enough for you to recognize it. Just make sure it says PATH and not echo $PATH.

Ed added several comments here. However, after consideration, I'm leaving this as is. There are other ways to access and affect the PATH, but these are things the reader will, after more study, learn on their own. My criterion has been, as this is directed towards newbies, is it something that I understood at first reading. (I think I must frustrate Ed a lot).

(Let me insert a word about the bash shell. This is the most commonly used shell in Linux, and is the one selected by default during most applications. There are other shells, but if you selected one of them, you're on your own, at least as far as this howto is concerned.)

As mentioned in Ed's introduction, it never hurts to makea backup--if you hit a few wrong keys, you could mess things up, so first, let's back up the .bash_rc. In the terminal window type:
cp .bash_rc .bash_rc.orig
You now have a duplicate of your .bash_rc file. If something goes drastically wrong,you can simply type in
mv .bash_rc.orig .bash_rc and you'll be back to where you began. Now add the following. After the last item, add a colon and after the colon type:
/usr/bin/scriptx
What we've done here is made sure that the bash shell will look for your scripts. Otherwise, when you call a script you'll get the message command not found which is aggravating. Save the redone file. Now, you might have to restart to have the changes take effect. The way to check this is to type in the terminal window:
echo $PATH
If it includes the /usr/bin/scriptx at the end you're fine. Otherwise, log out, restart X and log in again as root. The dollar sign before PATH indicates that it's a variable--why echo PATH doesn't work, I'm not sure. If you just wanted to change the path for a moment, you can always type PATH=$PATH:/usr/bin/scriptx or whatever different course you want the path to take--that's saying that the current PATH, is a variable (that's what the dollar sign indicates) and that you are changing that variable--$PATH is the current path, whatever it may be. So, adding a colon and /usr/bin/scriptx is the same as writing out the entire current path, adding a colon and adding the new directory that you want it to check.

So, ok, that was a bit of nuisance, but now, hopefully, you have your PATH set so that from now on, bash will check that folder for commands. So, on to our first script.

Before making the cdrom script, we're going to do another one first. Once you write a script and save it into your /usr/bin/scriptx directory, you still aren't able to use it. You will get a permission denied message. To fix that, you have to change the mode by typing: chmod 711 /usr/bin/scriptx/cdrom (The italicized cdrom in this case is the name of the script that we're making--substitute the name of any script that you write. This will allow you, as root, to execute this script. If you want any user to be able to do so, replace the 711 with 755. Well, this chmod 711/usr/bin/scriptx/and the script name is a pain, right? So, let's start by making a script to do it for us.

Open up your text editor. type the following:
#!/bin/bash
chmod 711 /usr/bin/scriptx/$1

Again, this will be if you only want the creator of the script to be able to use it. To allow all to use it, substitute 755 for 711. Save this in your /usr/bin/scriptx directory as modex.

The #!/bin/bash helps the bash shell call the script. From time to time I've accidentally left it out and the script still worked, but it's a good habit to always type that at the beginning of the script. On some systems it should be #! /bin/bash (i.e. with a space after the !. If, when calling your script, if you're getting a command not found (assuming you've edited your path so that it shows the scriptx directory) try putting the space after the ! and see if it helps.

Now, back in the terminal window type:
chmod 711 /usr/bin/scriptx/mode
Now you're able to use that script. Note that there is a space between chmod and 711 and another space after the x.
The "$1" shows that there's a variable. The 1 indicates that it's the first variable. This way, whenever you use your modex script (which we're going to do in about two minutes) you will type modex name of script and it will do the chmod command on your new script.

Ed added a bit of complexity to this, explaining how 0 refers to the current something, 1 the next, etc. but for the moment, we'll skip that. If you've done any playing around with programming you know about this, if not, don't worry, it's not going to affect things at present. Ok, go back to your text editor. Open a new file and type:
#! /bin/bash
mount /dev/cdrom -t iso9660 /mnt/cdrom

Now, save this in your /usr/bin/scriptx directory. I'm assuming that the cdrom is not currently mounted. So, let's try our script---type in the terminal window:
cdrom
OOPS. You got a permission denied, didn't you? This is because we haven't used our modex script. So, now type:
modex cdrom
Now type: cdrom
As you can see, this can make a lot of things easier when you get used to it. I'm pretty lazy and usually make a one or two line script for any command that I find myself using more than two or three times. Now that you understand the procedure, you can make as many scripts as you want.

Since first writing this article, I have actually changed my method. The above (and some of what's below) do it this way--as root you use one script in one location and as ordinary user you use a script that is kept in a different location. However, what one can do instead is this--rather than make the mode script read chmod 711 etc. you could also make it read
chmod 755 /usr/bin/scriptx/$1
What this does (I'm not going into an explanation of chmod here, the info is available all over the place--this is a howto not a whyto. One of my favorite explanations of using the numerical version of chmod is an article John O'Donnell wrote for the egroups linux list and is available here) is give permission for everyone to execute the scripts. The 711 only gives root permission to execute the scripts. So, if you use 711 which gives root read, write and execute permission and everyone else read and execute permission, assuming that security isn't an issue, you save yourself work. Then, each script can be used by all users on the machine.

One more example of using the variable. I find that on my system, both Netscape and Gimp can sometimes freeze up. As the ole Windows control alt del doesn't work here, the usual way to take care of this is to type in a terminal window:
ps ax | grep gimp (or netscape or whatever.) This gives the PID (Process ID I think) of all processes running using gimp. You then type kill 532 if, for example, gimp's PID was 532 and that will close the program. So, one could make a script like the following:
ps ax | grep $1
Save it as something (I call mine axer--the name works for me). Now, if something is locked up I can type
axer netscape
It will give me the PIDs that Netscape is using. If the problem is with gimp I can type
axer gimp to get gimp's PIDs. This is, of course, easier than making two seperate scripts such as ps ax | grep netscape and ps ax | grep gimp.

Now, as an ordinary user, there are some differences. There are two ways to go about it. The easiest, by far, is to, as written above, make the mode script read chmod 755 instead of chmod 711. Then, as user, also check .bashrc and .bash_profile, see where the PATH is, and again add the /usr/bin/scriptx to the current path. However, sometimes, for security or other reasons, one doesn't want to, as root, make scripts accessible to everyone. In that case, continue reading. You will find some differences when you make scripts as a user. Basically, it has to do with where you're able to save files. You can't save them in any directory higher than your home directory without changing to root. While this is easy enough to do, the whole point here is to save typing and time. So, if your user directory is named Scott, you have to save them in there. The preferred way is to make a bin directory in your /home/ directory. Therefore, take something that we're allowed to do as a user. Firstly, we add to the path as we did before. We check either .bashrc or .bash_profile and see where the PATH is and see if /home/scott/bin is in the path. (This varies between distros but in many it's there by default. That is of course, if your user name is scott.) If not, then add it to .bashrc and/or .bash_profile.

PATH=$PATH:/home/scott/bin

I repeat--this howto, if I can call it that, is directed towards the real beginner,and it is hoped that the reader will, after getting a little comfortable with this, will do more research on their own, to be be able to, for example, easily figure out how to store scripts in a higher directory, learn to make more complex scripts, etc.

One last point--recently, doing a lot of fixing up of a system, I constantly had to type the following two lines.

mount /dev/cdrom
cd /mnt/cdrom/RedHat/RPMS

This was becoming a pain in the neck, so I made a script for it. However, it wasn't working. It would mount the CDROM but then leave me in whatever directory I'd been in when I started.

A search on deja revealed the answer--when it mounts the CD, it spawns a new shell--in that shell, it cd's over to the RPMS directory then ends, going back to the original shell. At any rate, the workaround is, if the script's name is cdx is to type, when calling it

. cdx
(Note that there is a space after the period).
This, according to the deja post, tells the script to execute everything in the original shell. Lazy sort that I am, I added an alias in .bashrc

alias cdx='. cdx'

I want to give my thanks to Ed, as always, and hope that he is pleased with his pupil's progress. He did, however, have one more disagreement--he felt that my script names could be improved. Firstly, he said that he didn't feel that they gave a good idea of what the script does--to that one, I can only say it works for me. If however, you forget what a script does, especially if it's only a one or two liner, you can quickly review it with the cat command. Just type (assuming that you are logged on as user, and in your home directory--for example, if I am on as scott and in my /home/scott directory):
cat scripts/modex
The line will then appear in the terminal window and I can remember which script it is, or see if there's some reason it's not working. For example, if I were in a different directory and tried to call the modex script, it wouldn't work as the path would be incorrect.

That's it. With this information, you can make all the scripts you want. If you have any trouble, comments or criticisms, you can email me and I'll help if I can.