You may have heard that one advantage of Linux is that everything is programmable. You can automate just about any task. There are a lot of ways of doing this. One of the most common is the shell script, which is sort of equivalent to a DOS "batch file".
Simply put, a shell script is a list of commands to run; but it's a lot more flexible than that implies.
If you get into really complicated scripting, especially automatically processing text files, you may be better off learning a scripting language like python or perl or scheme or tcl or...
That's a magic word that tells the system you want to execute the commands in this file using the 'sh' shell, which on most linux systems is actually a link to /bin/bash.
chmod +x foo
This makes the file "executable"; now you can execute it just by typing its name. For more information see using chmod.
#!/bin/sh echo hello world
Make the file executable, then type the file's name as a
command. Guess what... it prints 'hello world.'
Basic Techniques
Comments
You can put comments in your scripts, by typing the '#' character. Anything after the # will be ignored. Use this feature; it will help you remember what your script is supposed to do later, and it can help anyone else who uses your script.
It can confuse you at first, but there's basically only two syntax rules to remember about variables in the bash shell:
- to make use of the variable, put a dollar sign in front of the name;
- To create the variable, use an equal sign immediately after the variable name (no spaces!), and DON'T use the dollar sign before the name.
Example: Let's create and then print a variable. Try typing this at the shell prompt:
foo='hello' ; echo $foo
When you run a shell script, you can give arguments. The arguments are stored in variables called $0, $1, $2, $3, ...The first one, $0, actually gives you the name of the shell script itself. The rest starting with $1 are the ones you're more likely to use right away. To play with this idea, try this script:
#!/bin/sh echo $1 echo $2 echo $3
Example: Type this at the command line: listing=`ls`
Now the variable $listing contains the output of the
command ls, namely, a list of files.
if...then
What if you want your script to do different things under different circumstances? Easy, just use an 'if' block, like this:if some-test-command then do-something fiJust replace some-test-command with a command that either succeeds ("returns true") or fails ("returns false"). And replace do-something with a command you actually want to run if the test command returns true!Notice that you always have to use 'fi' to close the block. ('fi' is 'if' backwards, get it? Ahh, unix humor, ha ha.)
You can also add an else clause, which tells what to do if the test command is false, like this:
if some-test-command then do-something else do-something-else fiYou can also add an elif clause, which is shorthand for "else if", meaning, "on the other hand, if something else is true...". This lets you test for more than one condition.
if some-test-command then do-something elif some-other-test-command then do-something-else else do-something-entirely-different fiHopefully this will all become clear in the Examples below.
for provides a way to do the same action a bunch of times with a bunch of different things. For example, say you have a list of files stored in a variable, and you want to copy all those files. You could do that like this:files="foo bar baz batz" for f in $files do cp $f $f.backup doneOr you could do that all on one line, like this: for f in $files; do cp $f $f.backup ; done
For some really great useful shell scripts, see the Linux Tips-HOWTO, which you may have in /usr/doc/HOWTO/Tips-HOWTO.
#!/bin/sh # if [ ! $1 ] # This means, "if there's no first argument..." then echo " "Usage: `basename $0` output.tar.gz # note that `basename $0` gives the name of this script! echo " This creates a tarred, gzipped archive of all" echo " the hidden files in your home directory." echo " Warning: if an archive by that name exists," echo " it will be overwritten." exit 1 # Quit this script now! fi cd ~ # go home! rm -f /tmp/skip # Make a list of files to skip... add to this as you wish. ls -1d --color=no .gimp/gimpswap* .gimp/tmp >>/tmp/skip ls -1d --color=no .[a-zA-Z]*~ ~/.[a-zA-Z]*bak .[a-zA-Z]*errors >>/tmp/skip ls -1d --color=no .[a-zA-Z0-9_]*/*cache .[a-zA-Z0-9_]*/*tmp >> /tmp/skip ls -1d --color=no .[a-zA-Z0-9_]*/*~ >> /tmp/skip ls -1d --color=no .[a-zA-Z]*/*.bak >>/tmp/skip ls -1d --color=no .[a-zA-Z]*/*.BAK >>/tmp/skip ls -1d --color=no .[a-zA-Z]*/*.backup >>/tmp/skip ls -1d --color=no .[a-zA-Z]*/*.old .[a-zA-Z]*/*.OLD >>/tmp/skip echo "core" >> /tmp/skip # Make the archive, and put it in $OLDPWD, which is the directory we # were in before that cd command above. tar -cvz -X /tmp/skip -f $OLDPWD/$1 `ls -1 -d --color=no .[a-zA-Z]*` # Now clean up and go back where we were rm -f /tmp/skip cd $OLDPWD # go back to where we were before starting the script.
#!/bin/bash # Simple script to throw stuff in a "trash bin" instead of deleting it. # Requires a directory called "trash" in your home directory. # NOTE: Does not work on filenames with embedded spaces. if [ ! $1 ] ; then echo Usage: echo `basename $0` string echo For filenames that contain \"string,\" echo throws all files \(and their contents, if they are directories\) echo into a \"trash\" directory in your home directory. echo Options: echo "-u Disk usage of your trash directory." echo "-ls List files in trash." echo "-empty Delete everything in trash." exit 1 elif [ $1 = "-u" ] 2> /dev/null ; then echo Disk usage of ~/trash: du ~/trash elif [ $1 = "-empty" ] 2> /dev/null ; then echo Emptying trash... rm ~/trash/* ; rm ~/trash/.* 2> /dev/null elif [ $1 = "-ls" ] 2> /dev/null ; then ls -a ~/trash else for file in *$1* ; do mv $file ~/trash done fi
#!/bin/bash # Paul Winkler's second script, for removing spaces from files # that have stupidly been named with them, and substituting # the usual character "_" ... # 'case' is another way of testing things. Basically, the next 3 lines # translate as: "if $1 is '-a' do everything up to the line ';;' ". case $1 in -a) # If $1 is "-a"... for files in *\ * ; do echo mv \"$files\" `echo $files | sed s/\ /_/g` | bash done echo You just removed spaces in all filenames in `pwd`. echo They have been replaced with \"_\". ;; -s) # If $1 is "-s"... for files in *$2* ; do echo mv \"$files\" `echo $files | sed s/\ /_/` | bash done echo You just removed spaces in all filenames containing echo \"$2\". They have been replaced with \"_\". ;; *) # If $1 is anything else, print instructions! echo Usage: \"`basename $0` -a\" to remove spaces from all files in this directory \(`pwd`\). echo \"`basename $0` -s anything\" to remove spaces from files containing echo the string \"anything.\" echo 'Spaces will be replaced with an underscore ("_").' esac # End of the "case" block.
Copyright © 1999 Paul Winkler. All rights reserved. Permission to use, distribute, and copy this document is hereby granted. You may modify this document as long as credit to me is given.