Create a script
There are a lot of different shells in Linux, but we usually use bash (Bourne again shell) for Shell programming because bash is free and easy to use. So the script I've provided in this article is all about using bash (but in most cases these scripts can also be run in Bash's eldest sister, Bourne Shell).
Like any other language, we use any kind of text editor, such as Nedit, Kedit, Emacs, VI
And so on to write our shell program.
The program must start with the following line (must be on the first line of the file):
#!/bin/sh
The symbolic #! is used to tell the system that the parameters behind it are the programs used to execute the file. In this example we use/BIN/SH to execute the program.
When you edit a good script, you must also make it executable if you want to execute the script.
To make the script executable:
chmod +x filename
You can then execute your script by entering:./filename.
Comments
In shell programming, comments are expressed in sentences that begin with # until the end of the line. We sincerely recommend that you use annotations in your programs. If you use annotations, you can understand how the script works and work in a very short period of time, even if you haven't used it for a very long time.
Variable
You must use variables in other programming languages. In shell programming, all variables are composed of strings, and you do not need to declare variables. To assign a value to a variable, you can write this:
Variable name = value
The value of the fetch variable can be added to a dollar sign ($) before the variable:
#!/bin/sh
#对变量赋值:
a= "Hello World"
now print the contents of variable A:
echo "A is:"
Enter the above in your editor, and then save it as a single file. Then execute chmod +x
Make it executable, and finally enter./first executes the script.
This script will output:
A is:
Hello World
Sometimes variable names can easily be confused with other words, such as:
num=2
echo "This is the $NUMND"
This does not print out "This is the 2nd" and only prints "This is the" because the shell searches for the value of the variable numnd, but the variable has no value. You can use curly braces to tell the shell what we want to print is the NUM variable:
num=2
echo "This is the ${num}nd"
This will print: This is the 2nd
There are a number of variables that are automatically set by the system, which will be discussed later when these variables are used.
If you need to deal with mathematical expressions, you need to use programs such as expr (see below).
In addition to the usual shell variables that are valid only within the program, there are environment variables. Variables processed by the EXPORT keyword are called environment variables. We do not discuss environment variables because, in general, environment variables are used only in logon scripts.
Shell command and Process Control
There are three types of commands that can be used in a shell script:
1 Unix Command:
Although arbitrary UNIX commands can be used in shell scripts, there are some relatively more commonly used commands. These commands are usually used for file and text operations.
Common command syntax and functions
echo "Some text": Print text content on screen
LS: File list
Wc–l filewc-w filewc-c file: Calculate the number of words in a file count the number of characters in a file
CP sourcefile destfile: File copy
MV Oldname newname: Renaming a file or moving a file
RM file: Deleting files
grep ' pattern ' file: Search for strings within a file for example: grep ' searchstring ' file.txt
Cut-b colnum File: Specifies the range of files to display and outputs them to standard output devices such as: Output the 5th to 9th characters per line cut-b5-9 file.txt do not confuse with cat commands, this is two completely different command
Cat file.txt: Output file contents to standard output device (screen)
File somefile: Getting files Type
Read Var: Prompts the user for input and assigns the input to the variable
Sort file.txt: Sort the rows in a file.txt file
Uniq: Delete the rows that appear in a text file for example: sort file.txt | Uniq
Expr: Mathematical operations Example:add 2 and 3expr 2 "+" 3
Find: Search for files such as: Search for Find by filename. -name Filename-print
Tee: Output data to standard output devices (screens) and files such as: Somecommand | Tee outfile
basename file: Returns a filename that does not contain a path such as: Basename/bin/tux will return Tux
DirName file: Returns the path where the files are located for example: Dirname/bin/tux will return/bin
Head file: Print the first few lines of a text file
Tail File: Print a few lines at the end of a text file
Sed:sed is a basic search and replace program. You can read text from standard input, such as a command pipe, and output the results to the standard output (screen). The command searches using a regular expression (see Reference). Do not confuse with wildcard characters in the shell. For example: Replace Linuxfocus with Linuxfocus:cat text.file | Sed ' s/linuxfocus/linuxfocus/' > Newtext.file
Awk:awk is used to extract fields from a text file. By default, the field separator is a space, and you can specify additional delimiters using-F. Cat File.txt | Awk-f, ' {print $ ', ' $} ' here we use, as a field separator, to print both the first and third fields. If the contents of the file are as follows: Adam Bor, Indiakerry Miller, USA command output is: Adam Bor, Indiakerry Miller, USA
2 Concept: Pipelines, redirects and Backtick
These are not system commands, but they are really important.
Pipe (|) The output of one command as input to another command.
grep "Hello" file.txt | Wc-l
Searches the file.txt for a row containing "Hello" and calculates its number of rows.
Here the output of the grep command is used as input to the WC command. Of course you can use more than one command.
Redirect: Outputs the results of a command to a file instead of the standard output (screen).
> Write files and overwrite old files
>> add to the end of the file and keep the old file contents.
Anti-Short Slash
Using a backslash, you can use the output of one command as a command line argument for another command.
Command:
Find. -mtime-1-type F-print
Used to find files that have been modified in the last 24 hours (-mtime–2 for the last 48 hours). If you want to make a package of all the files you find, you can use the following script:
#!/bin/sh
# The Ticks are Backticks (') not normal quotes ('):
TAR-ZCVF lastmod.tar.gz ' Find. -mtime-1-type F-print '
3) Process Control
An "if" expression executes the part following then if the condition is true:
If ...; Then
....
Elif ...; Then
....
Else
....
Fi
In most cases, you can use test commands to test conditions. For example, you can compare strings, determine whether a file exists and whether it is readable, and so on ...
You typically use [] to represent a conditional test. Note that the spaces here are important. To ensure that the square brackets are blank.
[f "Somefile"]: To determine whether a file
[-X "/bin/ls"]: Determine if/bin/ls exists and has executable permissions
[-N ' $var]: Determine if the $var variable has a value
["$a" = "$b"]: Determine if $a and $b are equal
Execute man test to see the types that all test expressions can compare and judge.
Execute the following script directly:
#!/bin/sh
If ["$SHELL" = "/bin/bash"]; Then
echo "Your login shell is the bash (Bourne again shell)"
Else
echo "Your login shell is not bash but $SHELL"
Fi
The variable $shell contains the name of the login shell, which we compared with/bin/bash.
Shortcut operators
A friend who is familiar with C may like the following expression:
[f "/etc/shadow"] && echo "This computer uses Shadow Passwors"
Here && is a shortcut operator that executes the statement on the right if the expression on the left is true. You can also think of it as an operation in a logical operation. The example above indicates that "This computer uses Shadow Passwors" is printed if the/etc/shadow file exists. Same OR operation (| |) is also available in Shell programming. Here's an example:
#!/bin/sh
Mailfolder=/var/spool/mail/james
[-R ' $mailfolder] ' {echo ' Can not read $mailfolder '; exit 1;}
echo "$mailfolder has mail from:"
grep "^from" $mailfolder
The script first determines whether the mailfolder is readable. If readable, prints the "from" line in the file. If unreadable or the operation takes effect, the script exits after printing the error message. Here's the problem, which is that we have to have two orders:
-Print error messages
-Exit Program
We use curly braces to put two commands together as a command in the form of anonymous functions. The general functions are mentioned below.
Without the and OR operator, we can do anything with an if expression, but it is much more convenient to use the and or operators.
A case expression can be used to match a given string, not a number.
Case ... in
...) do something here;;
Esac
Let's look at an example. The file command can identify a given file type, such as:
File lf.gz
This will return:
Lf.gz:gzip compressed data, deflated, original filename,
Last Modified:mon Aug 23:09:18 2001, Os:unix
We use this to write a script called Smartzip, which automatically extracts bzip2, gzip, and zip-type compressed files:
#!/bin/sh
Ftype= ' file '
Case "$ftype" in
"$1:zip Archive" *)
Unzip "$";;
"$1:gzip Compressed" *)
Gunzip "$";;
"$1:bzip2 Compressed" *)
Bunzip2 "$";;
*) Error "File uncompressed with Smartzip";
Esac
You may notice that we are using a special variable here. The variable contains the first parameter value passed to the program. In other words, when we run:
Smartzip Articles.zip
$ is a string articles.zip
A select expression is an extended application of bash and is especially good at interactive use. Users can choose from a different set of values.
Select Var in ...; Todo
Break
Done
.... Now $var can be used ....
Here is an example:
#!/bin/sh
echo "What is your favourite OS?"
Select Var in "Linux" "Gnu Hurd", "Free BSD", "other"; Todo
Break
Done
echo "You have selected $var"
The following is the result of the script running:
What is your favourite OS?
1) Linux
2) Gnu Hurd
3) Free BSD
4) Other
#? 1
You have selected Linux
You can also use the following loop expression in your shell:
While ...; Todo
....
Done
While-loop will run until the expression test is true. Would run while the expression so we test is true. The keyword "break" is used to jump out of the loop. The keyword "Continue" is used to skip to the next loop without performing the remaining parts.
The For-loop expression looks at a list of strings (strings separated by spaces) and assigns them to a variable:
for Var in ...; Todo
....
Done
In the following example, ABC is printed separately on the screen:
Copy Code code as follows:
#!/bin/sh
For Var in A B C; Todo
Echo "Var is $var"
Done
Here is a more useful script showrpm that prints some of the RPM packet statistics:
#!/bin/sh
# List A content summary of a number of RPM packages
# usage:showrpm rpmfile1 rpmfile2 ...
# example:showrpm/cdrom/redhat/rpms/*.rpm for
rpmpackage in $*, do
if [R ' $rpmpackage '];then
echo ' = = ============ $rpmpackage ============== "
rpm-qi-p $rpmpackage
else
echo" Error:cannot read file $rpm Package "
fi
Done
Here comes the second special variable $*, which contains all the input command-line parameter values. If you run showrpm openssh.rpm w3m.rpm webgrep.rpm
At this point the $* contains 3 strings, namely openssh.rpm, w3m.rpm and webgrep.rpm.
Quotes
The program expands wildcard characters and variables before passing any arguments to the program. What this means by extension is that the program replaces the wildcard character (such as *) with the appropriate filename, which is replaced with the variable value. To prevent the program from making this substitution, you can use quotes: Let's look at an example, assuming there are some files in the current directory, two JPG files, mail.jpg and tux.jpg.
#!/bin/sh
Echo *.jpg
This will print out the results of the "Mail.jpg tux.jpg".
quotation marks (single and double quotes) prevent this wildcard extension:
#!/bin/sh
echo "*.jpg"
Echo ' *.jpg '
This will print "*.jpg" two times.
Single quotes are more restrictive. It can prevent any variable from being extended. Double quotes can prevent wildcard extensions but allow variable extensions.
#!/bin/sh
Echo $SHELL
echo "$SHELL"
Echo ' $SHELL '
The results of the operation are:
/bin/bash
/bin/bash
$SHELL
Finally, there is a way to prevent this extension by using the escape character--the backslash:
Echo *.jpg
Echo $SHELL
This will output:
*.jpg
$SHELL
Here documents
When you want to pass a few lines of text to a command, here is a good way to find out if you have not seen the right translation for this word. Writing a helpful text for each script is useful, so if we have that here documents, we don't have to use the Echo function to output one line at a time. A "Here document" begins with a <<, followed by a string that must also appear at the end of this document. Here's an example where we rename multiple files and use here documents to print help:
Copy Code code as follows:
#!/bin/sh
# We have less than 3 arguments. Print the Help text:
If [$#-lt 3]; Then
Cat <
Ren--Renames a number of files using SED regular expressions
Usage:ren ' regexp ' replacement ' files ...
Example:rename all *. HTM files in *.html:
ren ' htm$ ' html ' *. Htm
Help
Exit 0
Fi
Old= "$"
New= "$"
# The SHIFT command removes one argument from the list of
# command line arguments.
Shift
Shift
# $* contains now all the files:
for file in $*; Todo
If [-F "$file"]; Then
Newfile= ' echo ' $file | Sed "s/${old}/${new}/g" '
If [-F "$newfile"]; Then
echo "ERROR: $newfile exists already"
Else
echo "Renaming $file to $newfile ..."
MV "$file" "$newfile"
Fi
Fi
Done
This is a complex example. Let's discuss it in detail. The first if expression determines whether the input command line argument is less than 3 (the special variable $# represents the number of parameters). If the input parameter is less than 3, the help text is passed to the Cat command, which is then printed on the screen by the cat command. The program exits after printing the help text. If the input parameter is equal to or greater than 3, we assign the first parameter to the variable old, and the second parameter assigns to the variable new. Next, we use the shift command to remove the first and second arguments from the argument list so that the original third argument becomes the first argument in the argument list $*. Then we start the loop, and the command line argument list is assigned one after another to the variable $file. We then determine if the file exists, and if so, search and replace it with the SED command to produce a new filename. The command result in the backslash is then assigned to NewFile. So we have achieved our goal: to get the old file name and the new file name. The MV command is then used to rename it.
Function
If you write some slightly more complex programs, you'll find that the same code can be used in several places in your program, and you'll find it much easier if we use a function. A function is like this:
Copy Code code as follows:
functionname ()
{
# inside the ' body ' is the ' the ' the ' the ' the ' the ' the ' the '
# $ second ...
Body
}
You need to declare the function at the beginning of each program.
Here is a script called Xtitlebar, which you can use to change the name of the terminal window. A function called Help is used here. As you can see, this defined function was used two times.
Copy Code code as follows:
#!/bin/sh
# Vim:set sw=4 ts=4 et:
Help ()
{
Cat <
Xtitlebar--Change the name of a xterm, gnome-terminal or KDE konsole
Usage:xtitlebar [-h] "String_for_titelbar"
OPTIONS:-H Help text
Example:xtitlebar "CVS"
Help
Exit 0
}
# in case of an error or if-h is given we call the function Help:
[-Z ' $] && Help
["$" = "-H"] && Help
# Send the escape sequence to the xterm Titelbar:
Echo-e "33]0;$107"
#
Providing help in scripting is a good programming practice that facilitates the use and understanding of scripts by other users (and you).
Command line arguments
We've seen special variables such as $* and $ $, which contain the parameters that the user enters from the command line. So far, we've only learned a few simple command-line syntax (such as some mandatory arguments and the-H option to view Help). But when writing more complex programs, you may find that you need more customization options. The usual practice is to add a minus sign before all optional parameters, followed by the value of the parameter (such as the filename).
There are many ways to analyze input parameters, but the following examples of case expressions are a good way to go.
Copy Code code as follows:
#!/bin/sh
Help ()
{
Cat <
This is a generic command line parser demo.
USAGE example:cmdparser-l hello-f---somefile1 somefile2
Help
Exit 0
}
While [-N ' $]; Todo
Case is in
-h) Help;shift 1;; # function Help is called
-f) Opt_f=1;shift 1;; # variable Opt_f is set
-L) Opt_l=$2;shift 2;; # L takes a argument-> shift by 2
-Shift;break;; # End of options
-*) echo "error:no such option $. -h for help; exit 1;;
*) break;;
Esac
Done
echo "Opt_f is $opt _f"
echo "opt_l is $opt _l"
echo "The ' is $"
echo "2nd Arg is $"
You can run the script this way:
Cmdparser-l hello-f---somefile1 somefile2
The result returned is:
Opt_f is 1
opt_l is Hello
Is-somefile1 of the A-arg
2nd Arg is Somefile2
How does this script work? The script first loops through all the input command-line arguments, compares the input parameter with the case expression, sets a variable if it matches, and removes the parameter. According to the practice of UNIX systems, the first input should be an argument containing a minus sign.
Instance
General programming steps
Now let's discuss the general steps to write a script. Any good script should have help and input parameters. and write a pseudo script (framework.sh) that contains the framework structure that most scripts require, and is a very good idea. At this point, we only need to execute the copy command when writing a new script:
CP framework.sh MyScript
And then insert your own function.
Let's look at two more examples:
Binary to decimal conversion
The script b2d converts the binary number (for example, 1101) to the corresponding decimal number. This is also an example of a mathematical operation using the expr command:
Copy Code code as follows:
#!/bin/sh
# Vim:set sw=4 ts=4 et:
Help ()
{
Cat <
B2H-Convert binary to Decimal
USAGE:B2H [-h] Binarynum
OPTIONS:-H Help text
EXAMPLE:B2H 111010
would return 58
Help
Exit 0
}
Error ()
{
# Print an error and exit
echo "$"
Exit 1
}
Lastchar ()
{
# return ' last character ' a string in $rval
If [-Z "$"]; Then
# empty string
Rval= ""
Return
Fi
# WC puts some space behind the ' output ' is why we need sed:
Numofchar= ' Echo-n ' "$" | wc-c | Sed ' s///g '
# now cut out of the last Char
Rval= ' Echo-n ' "$" | Cut-b $numofchar '
}
Chop ()
{
# Remove the last character in string and return it in $rval
If [-Z "$"]; Then
# empty string
Rval= ""
Return
Fi
# WC puts some space behind the ' output ' is why we need sed:
Numofchar= ' Echo-n ' "$" | wc-c | Sed ' s///g '
If ["$numofchar" = "1"]; Then
# only one char in string
Rval= ""
Return
Fi
numofcharminus1= ' expr $numofchar '-"1"
# now cut all but char:
Rval= ' Echo-n ' "$" | Cut-b 0-${numofcharminus1} '
}
While [-N ' $]; Todo
Case is in
-h) Help;shift 1;; # function Help is called
-Shift;break;; # End of options
-*) Error "error:no such option $. -H for help ";;
*) break;;
Esac
Done
# The main program
Sum=0
Weight=1
# One ARG must be given:
[-Z ' $] && Help
Binnum= "$"
Binnumorig= "$"
While [-N "$binnum"]; Todo
Lastchar "$binnum"
If ["$rval" = "1"]; Then
sum= ' expr ' $weight ' "+" "$sum"
Fi
# Remove the last position in $binnum
Chop "$binnum"
Binnum= "$rval"
weight= ' expr ' $weight ' "*" 2 '
Done
echo "Binary $binnumorig is decimal $sum"
#
The script uses an algorithm that uses decimal and binary number weights (1,2,4,8,16,..), such as binary "10" to be converted to decimal:
0 * 1 + 1 * 2 = 2
In order to get a single binary number, we used the Lastchar function. The function calculates the number of characters using WC–C and then uses the Cut command to remove the end of a character. The function of the chop function is to remove the last character.
File Loop procedure
Perhaps you want to save all messages sent to one of the people in a file, but after a few months, the file may become so large that it slows down access to the file. The following script rotatefile can solve this problem. This script can rename the Mail save file (assumed to be outmail) as OUTMAIL.1, and for OUTMAIL.1 becomes outmail.2 and so on ...
Copy Code code as follows:
#!/bin/sh
# Vim:set sw=4 ts=4 et:
Ver= "0.1"
Help ()
{
Cat <
Rotatefile--Rotate the file name
Usage:rotatefile [-h] FileName
OPTIONS:-H Help text
Example:rotatefile out
This is e.g rename out.2 to Out.3, Out.1 to Out.2, out to Out.1
and create an empty out-file
The max number is 10
Version $ver
Help
Exit 0
}
Error ()
{
echo "$"
Exit 1
}
While [-N ' $]; Todo
Case is in
-h) Help;shift 1;;
-) break;;
-*) echo "error:no such option $. -h for help; exit 1;;
*) break;;
Esac
Done
# input Check:
If [-Z "$"]; Then
Error "Error:you must specify a file, use-h for help"
Fi
Filen= "$"
# Rename any. 1,. 2 etc File:
For N in 9 8 7 6 5 4 3 2 1; Todo
If [-F "$filen. $n"]; Then
p= ' expr $n + 1 '
echo "MV $filen. $n $filen. $p"
MV $filen. $n $filen. $p
Fi
Done
# Rename the original file:
If [-F "$filen"]; Then
echo "MV $filen $filen. 1"
MV $filen $filen. 1
Fi
echo Touch $filen
Touch $filen
How does this script work? After testing the user for a filename, we have a 9 to 1 loop. File 9 is named 10, file 8 is renamed 9, and so on. After the loop completes, we name the original file as file 1 and create an empty file with the same name as the original file.
Debugging
The simplest debugging command, of course, is to use the echo command. You can use Echo to print any variable values in any suspect error area. This is why most shell programmers spend 80% of their time debugging programs. The advantage of a shell program is that you don't need to recompile, and it doesn't take much time to insert an echo command.
The shell also has a real debug mode. If there are errors in the script "Strangescript", you can debug this:
Sh-x Strangescript
This executes the script and displays the values of all the variables.
The shell also has a pattern that does not need to execute a script just to check the syntax. You can use this:
Sh-n Your_script
This will return all syntax errors.
We hope you can start writing your own shell script now and hope you enjoy yourself.