分享
 
 
 

SHELLWarmingup

王朝other·作者佚名  2008-05-18
窄屏简体版  字體: |||超大  

Comments

Comments in shell programming start with # and go until the end of the line. We really recommend you to use comments. If you have comments and you don't use a certain script for some time you will still know immediately what it is doing and how it works.

Variables

As in other programming languages you can't live without variables. In shell programming all variables have the datatype string and you do not need to declare them. To assign a value to a variable you write:

varname=value

To get the value back you just put a dollar sign in front of the variable:

#!/bin/sh

# assign a value:

a="hello world"

# now print the content of "a":

echo "A is:"

echo $a

Type this lines into your text editor and save it e.g. as first. Then make the script executable by typing chmod +x first in the shell and then start it by typing ./first

The script will just print:

A is:

hello world

Sometimes it is possible to confuse variable names with the rest of the text:

num=2

echo "this is the $numnd"

This will not print "this is the 2nd" but "this is the " because the shell searches for a variable called numnd which has no value. To tell the shell that we mean the variable num we have to use curly braces:

num=2

echo "this is the ${num}nd"

This prints what you want: this is the 2nd

There are a number of variables that are always automatically set. We will discuss them further down when we use them the first time.

If you need to handle mathematical expressions then you need to use programs such as expr (see table below).

Besides the normal shell variables that are only valid within the shell program there are also environment variables. A variable preceeded by the keyword export is an environment variable. We will not talk about them here any further since they are normally only used in login scripts.

Shell commands and control structures

There are three categories of commands which can be used in shell scripts:

1)Unix commands:

Although a shell script can make use of any unix commands here are a number of commands which are more often used than others. These commands can generally be described as commands for file and text manipulation.

Command syntax Purpose

echo "some text" write some text on your screen

ls list files

wc -l file

wc -w file

wc -c file count lines in file or

count words in file or

count number of characters

cp sourcefile destfile copy sourcefile to destfile

mv oldname newname rename or move file

rm file delete a file

grep 'pattern' file search for strings in a file

Example: grep 'searchstring' file.txt

cut -b colnum file get data out of fixed width columns of text

Example: get character positions 5 to 9

cut -b5-9 file.txt

Do not confuse this command with "cat" which is something totally different

cat file.txt write file.txt to stdout (your screen)

file somefile describe what type of file somefile is

read var prompt the user for input and write it into a variable (var)

sort file.txt sort lines in file.txt

uniq remove duplicate lines, used in combination with sort since uniq removes only duplicated consecutive lines

Example: sort file.txt | uniq

expr do math in the shell

Example: add 2 and 3

expr 2 "+" 3

find search for files

Example: search by name:

find . -name filename -print

This command has many different possibilities and options. It is unfortunately too much to explain it all in this article.

tee write data to stdout (your screen) and to a file

Normally used like this:

somecommand | tee outfile

It writes the output of somecommand to the screen and to the file outfile

basename file return just the file name of a given name and strip the directory path

Example: basename /bin/tux

returns just tux

dirname file return just the directory name of a given name and strip the actual file name

Example: dirname /bin/tux

returns just /bin

head file print some lines from the beginning of a file

tail file print some lines from the end of a file

sed sed is basically a find and replace program. It reads text from standard input (e.g from a pipe) and writes the result to stdout (normally the screen). The search pattern is a regular expression (see references). This search pattern should not be confused with shell wildcard syntax. To replace the string linuxfocus with linuxFocus in a text file use:

cat text.file | sed 's/linuxfocus/linuxFocus/' > newtext.file

This replaces the first occurance of the string linuxfocus in each line with linuxFocus. If there are lines where linuxfocus appears several times and you want to replace all use:

cat text.file | sed 's/linuxfocus/linuxFocus/g' > newtext.file

awk Most of the time awk is used to extract fields from a text line. The default field separator is space. To specify a different one use the option -F.

cat file.txt | awk -F, '{print $1 "," $3 }'

Here we use the comma (,) as field separator and print the first and third ($1 $3) columns. If file.txt has lines like:

Adam Bor, 34, India

Kerry Miller, 22, USA

then this will produce:

Adam Bor, India

Kerry Miller, USA

There is much more you can do with awk but this is a very common use.

2) Concepts: Pipes, redirection and backtick

They are not really commands but they are very important concepts.

pipes (|) send the output (stdout) of one program to the input (stdin) of another program.

grep "hello" file.txt | wc -l

finds the lines with the string hello in file.txt and then counts the lines.

The output of the grep command is used as input for the wc command. You can concatinate as many commands as you like in that way (within reasonable limits).

redirection: writes the output of a command to a file or appends data to a file

> writes output to a file and overwrites the old file in case it exists

>> appends data to a file (or creates a new one if it doesn't exist already but it never overwrites anything).

Backtick

The output of a command can be used as command line arguments (not stdin as above, command line arguments are any strings that you specify behind the command such as file names and options) for another command. You can as well use it to assign the output of a command to a variable.

The command

find . -mtime -1 -type f -print

finds all files that have been modified within the last 24 hours (-mtime -2 would be 48 hours). If you want to pack all these files into a tar archive (file.tar) the syntax for tar would be:

tar xvf file.tar infile1 infile2 ...

Instead of typing it all in you can combine the two commands (find and tar) using backticks. Tar will then pack all the files that find has printed:

#!/bin/sh

# The ticks are backticks (`) not normal quotes ('):

tar -zcvf lastmod.tar.gz `find . -mtime -1 -type f -print`

3) Control structures

The "if" statement tests if the condition is true (exit status is 0, success). If it is the "then" part gets executed:

if ....; then

....

elif ....; then

....

else

....

fi

Most of the time a very special command called test is used inside if-statements. It can be used to compare strings or test if a file exists, is readable etc...

The "test" command is written as square brackets " [ ] ". Note that space is significant here: Make sure that you always have space around the brackets. Examples:

[ -f "somefile" ] : Test if somefile is a file.

[ -x "/bin/ls" ] : Test if /bin/ls exists and is executable.

[ -n "$var" ] : Test if the variable $var contains something

[ "$a" = "$b" ] : Test if the variables "$a" and "$b" are equal

Run the command "man test" and you get a long list of all kinds of test operators for comparisons and files.

Using this in a shell script is straight forward:

#!/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 and this is what we are testing here by comparing it against the string "/bin/bash"

Shortcut operators

People familiar with C will welcome the following expression:

[ -f "/etc/shadow" ] && echo "This computer uses shadow passwors"

The && can be used as a short if-statement. The right side gets executed if the left is true. You can read this as AND. Thus the example is: "The file /etc/shadow exists AND the command echo is executed". The OR operator (||) is available as well. Here is 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 tests first if it can read a given mailfolder. If yes then it prints the "From" lines in the folder. If it cannot read the file $mailfolder then the OR operator takes effect. In plain English you read this code as "Mailfolder readable or exit program". The problem here is that you must have exactly one command behind the OR but we need two:

-print an error message

-exit the program

To handle them as one command we can group them together in an anonymous function using curly braces. Functions in general are explained further down.

You can do everything without the ANDs and ORs using just if-statements but sometimes the shortcuts AND and OR are just more convenient.

The case statement can be used to match (using shell wildcards such as * and ?) a given string against a number of possibilities.

case ... in

...) do something here;;

esac

Let's look at an example. The command file can test what kind of filetype a given file is:

file lf.gz

returns:

lf.gz: gzip compressed data, deflated, original filename,

last modified: Mon Aug 27 23:09:18 2001, os: Unix

We use this now to write a script called smartzip that can uncompress bzip2, gzip and zip compressed files automatically :

#!/bin/sh

ftype=`file "$1"`

case "$ftype" in

"$1: Zip archive"*)

unzip "$1" ;;

"$1: gzip compressed"*)

gunzip "$1" ;;

"$1: bzip2 compressed"*)

bunzip2 "$1" ;;

*) error "File $1 can not be uncompressed with smartzip";;

esac

Here you notice that we use a new special variable called $1. This variable contains the first argument given to a program. Say we run

smartzip articles.zip

then $1 will contain the string articles.zip

The select statement is a bash specific extension and is very good for interactive use. The user can select a choice from a list of different values:

select var in ... ; do

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"; do

break

done

echo "You have selected $var"

Here is what the script does:

What is your favourite OS?

1) linux

2) Gnu Hurd

3) Free BSD

4) Other

#? 1

You have selected linux

In the shell you have the following loop statements available:

while ...; do

....

done

The while-loop will run while the expression that we test for is true. The keyword "break" can be used to leave the loop at any point in time. With the keyword "continue" the loop continues with the next iteration and skips the rest of the loop body.

The for-loop takes a list of strings (strings separated by space) and assigns them to a variable:

for var in ....; do

....

done

The following will e.g. print the letters A to C on the screen:

#!/bin/sh

for var in A B C ; do

echo "var is $var"

done

A more useful example script, called showrpm, prints a summary of the content of a number of RPM-packages:

#!/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 $rpmpackage"

fi

done

Above you can see the next special variable, $* which contains all the command line arguments. If you run

showrpm openssh.rpm w3m.rpm webgrep.rpm

then $* contains the 3 strings openssh.rpm, w3m.rpm and webgrep.rpm.

The GNU bash knows until-loops as well but generally while and for loops are sufficient.

Quoting

Before passing any arguments to a program the shell tries to expand wildcards and variables. To expand means that the wildcard (e.g. *) is replaced by the appropriate file names or that a variable is replaced by its value. To change this behaviour you can use quotes: Let's say we have a number of files in the current directory. Two of them are jpg-files, mail.jpg and tux.jpg.

#!/bin/sh

echo *.jpg

This will print "mail.jpg tux.jpg".

Quotes (single and double) will prevent this wildcard expansion:

#!/bin/sh

echo "*.jpg"

echo '*.jpg'

This will print "*.jpg" twice.

Single quotes are most strict. They prevent even variable expansion. Double quotes prevent wildcard expansion but allow variable expansion:

#!/bin/sh

echo $SHELL

echo "$SHELL"

echo '$SHELL'

This will print:

/bin/bash

/bin/bash

$SHELL

Finally there is the possibility to take the special meaning of any single character away by preceeding it with a backslash:

echo *.jpg

echo $SHELL

This will print:

*.jpg

$SHELL

Here documents

Here documents are a nice way to send several lines of text to a command. It is quite useful to write a help text in a script without having to put echo in front of each line. A "Here document" starts with << followed by some string that must also appear at the end of the here document. Here is an example script, called ren, that renames multiple files and uses a here document for its help text:

#!/bin/sh

# we have less than 3 arguments. Print the help text:

if [ $# -lt 3 ] ; then

cat <<HELP

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="$1"

NEW="$2"

# The shift command removes one argument from the list of

# command line arguments.

shift

shift

# $* contains now all the files:

for file in $*; do

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 the most complex script so far. Let's discuss it a little bit. The first if-statement tests if we have provided at least 3 command line parameters. (The special variable $# contains the number of arguments.) If not, the help text is sent to the command cat which in turn sends it to the screen. After printing the help text we exit the program. If there are 3 or more arguments we assign the first argument to the variable OLD and the second to the variable NEW. Next we shift the command line parameters twice to get the third argument into the first position of $*. With $* we enter the for loop. Each of the arguments in $* is now assigned one by one to the variable $file. Here we first test that the file really exists and then we construct the new file name by using find and replace with sed. The backticks are used to assign the result to the variable newfile. Now we have all we need: The old file name and the new one. This is then used with the command mv to rename the files.

Functions

As soon as you have a more complex program you will find that you use the same code in several places and also find it helpful to give it some structure. A function looks like this:

functionname()

{

# inside the body $1 is the first argument given to the function

# $2 the second ...

body

}

You need to "declare" functions at the beginning of the script before you use them.

Here is a script called xtitlebar which you can use to change the name of a terminal window. If you have several of them open it is easier to find them. The script sends an escape sequence which is interpreted by the terminal and causes it to change the name in the titlebar. The script uses a function called help. As you can see the function is defined once and then used twice:

#!/bin/sh

# vim: set sw=4 ts=4 et:

help()

{

cat <<HELP

xtitlebar -- change the name of an 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 error or if -h is given we call the function help:

[ -z "$1" ] && help

[ "$1" = "-h" ] && help

# send the escape sequence to change the xterm titelbar:

echo -e "

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有