接详细介绍Linux shell脚本基础学习(一)我们来看一下shell中Here documents和函数的使用。
6. Here documents
HERE Document是bash里面定义块变量的途径之一
定义的形式为:
命令<
...
...
...
HERE
它的作用即可以用来定义一段变量,会把命令和HERE之间的内容利用转向输入的方式交给该命令去处理。其中HERE相当于标记,可以是任何的字符串。注意后一个HERE的最后不要有空格,否则会报错。
使用HERE Document用在变量设定:
view sourceprint?
2 [aa@aa shell]$ m1=$(cat <
3 > Line 1 is good.
4 > They are jack,marry and john.
5 > $wow
6 > Here
7 > )
8 [aa@aa shell]$ echo $m1
9 Line 1 is good. They are jack,marry and john. Wow,great!
view sourceprint?
2 [aa@aa shell]$ m1=$(cat <<'Here'
3 > Line 1 is good.
4 > They are jack,marry and john.
5 > $wow
6 > Here
7 > )
8 [aa@aa shell]$ echo $m1
9 Line 1 is good. They are jack,marry and john. $wow
它也可以用来定义一段注释 ,利用HERE Document做多行批注,方法是:
:<
当要将几行文字传递给一个命令时,here documents是一种不错的方法。对每个脚本写一段帮助性的文字是很有用的,此时如果我们四有那个 here documents就不必用echo函数一行行输出。 一个 "Here document" 以 <<开头,后面接上一个字符串,这个字符串还必须出现在here document的末尾。
下面我们来看一个例子,在该例子中,我们对多个文件进行重命名,并且使用here documents打印帮助:
view sourceprint?
02 # we have less than 3 arguments. Print the help text:
03 if [ $# -lt 3 ] ; then
04 cat <
05 -- renames a number of files using sed regular expressions
06 USAGE: $0 'regexp' 'replacement' files...
07 EXAMPLE: rename all *.HTM files in *.html:
08 $0 'HTM$' 'html' *.HTM
09 help
10 exit 0
11 fi
12
13 OLD="$1"
14 NEW="$2"
15 # The shift command removes one argument from the list of
16 # command line arguments.
17 shift
18 shift
19 # $* contains now all the files:
20 for file in $*; do
21 if [ -f "$file" ] ; then
22 newfile=`echo "$file" | sed "s/${OLD}/${NEW}/g"`
23 if [ -f "$newfile" ]; then
24 echo "ERROR: $newfile exists already"
25 else
26 echo "renaming $file to $newfile ..."
27 mv "$file" "$newfile"
28 fi
29 fi
30 done
view sourceprint?
2 总用量 4
3 -rw-rw-r--. 1 yongli yongli 0 2月 17 14:06 a.html
4 -rw-rw-r--. 1 yongli yongli 0 2月 17 14:06 b.html
5 -rw-rw-r--. 1 yongli yongli 0 2月 17 14:06 c.html
6 -rwxrwxr-x. 1 yongli yongli 681 2月 17 14:21 here_doc.sh
2
3 -- renames a number of files using sed regular expressions
4 USAGE: /data/shell/here_doc.sh 'regexp' 'replacement' files...
5 EXAMPLE: rename all *.HTM files in *.html:
6 /data/shell/here_doc.sh 'HTM$' 'html' *.HTM
2
3 renaming a.htm to a.html ...
4 renaming b.htm to b.html ...
5 renaming c.htm to c.html ...
第一个if表达式判断输入命令行参数是否小于3个 (特殊变量$#表示包含参数的个数) 。如果输入参数小于3个,则将帮助文字传递给cat命令,然后由cat命令将其打印在屏幕上。打印帮助文字后程序退出($0: 表示当前脚本的名称)。
如果输入参数等于或大于3个,我们 就将第一个参数赋值给变量OLD,第二个参数赋值给变量NEW。
下一步,我们使用shift命令将第一个和第二个参数从参数列表中删除,这样原来的第三个参数就成为参数列表$*的第一个参数。
然后我们开始循环,命令行参数列表被一个接一个地被赋值给变量$file。
接着我们判断该文件是否存在,如果存在则通过sed命令搜索和替换来产生新的文件名。然后将反短斜线内命令结果赋值给newfile。这样我们就达到了我们的目的:得到了旧文件名和新文件名。然后使用mv命令进行重命名。
这里我们再看一个实例,利用HERE Document,打包C(或其它程序语言)的原始码。这是Cracker散布安全漏洞程序,最喜欢的方法。
view sourceprint?
02 # Filename:create_prg.sh
03 echo "creating hello.c..."
04 echo
05 cat <<'EOF' > hello.c
06 #include
07 int main()
08 {
09 printf("Hello world!\n");
10 return 0;
11 }
12 EOF
13 echo "compiling hello.c..."
14 #compile hello.c,create the excutable file
15 gcc -o hello hello.c
16
17 #if compile successfully,then excute it
18 if [ $? -eq 0 ];then
19 echo "excute hello..."
20 chmod u+x hello
21 ./hello
22 else
23 echo 'Compile Error:hello.c'
24 fi
函数是一串命令的集合,函数可以把大的命令集合分解成若干较小的任务。编程人员可以基于函数进一步的构造更复杂的Shell 程序,而不需要重复编写相同的代码。
基本形式:
function_name()
对函数结构进行解释:
function1.sh
view sourceprint?
02
03 half()
04 {
05 let "n = $1"
06 let "n = n/2"
07 echo "In function half() n is $n"
08 }
09 if [ -z $1 ];then
10 echo 'Please input number m.'
11 echo "Uage:$0 number"
12 echo "Example:$0 2"
13 exit 0
14 fi
15 let "m = $1"
16 echo "Before the function half() is called, m is $m"
17 half $m
18 echo "After the function half() is called, m is $m"
function2.sh
view sourceprint?
02
03 ind_func()
04 {
05 echo " $1"
06 }
07
08 if [ -z $1 ];then
09 echo 'Please input arguments.'
10 echo "Uage:$0 args"
11 echo "Example:$0 a"
12 exit 0
13 fi
14
15 parameter=ind_arg
16 ind_arg=Hello
17
18 ind_func "$parameter"
19
20 ind_func "${!parameter}"
21
22 echo "***********************"
23
24 ind_arg=World
25 ind_func "$parameter"
26 ind_func "${!parameter}"
function3.sh
view sourceprint?
02
03 show_week()
04 {
05 echo -n "What you input is: "
06 echo "$1"
07
08 case $1 in
09 )
10 echo "Today is Sunday. "
11 return 0;;
12 )
13 echo "Today is Monday. "
14 return 0;;
15 )
16 echo "Today is Tuesday. "
17 return 0;;
18 )
19 echo "Today is Wednesday. "
20 return 0;;
21 )
22 echo "Today is Thursday. "
23 return 0;;
24 )
25 echo "Today is Friday. "
26 return 0;;
27 )
28 echo "Today is Saturday. "
29 return 0;;
30 *)
31 return 1;;
32 esac
33 }
34
35 if show_week "$1"
36 then
37 echo "What you input is right! "
38 else
39 echo "What you input is wrong! "
40 fi
41 exit 0
function4.sh
view sourceprint?
02
03 show_week()
04 {
05 for day in Monday Tuesday Wednesday Thursday Friday Saturday Sunday
06 do
07 echo -n "$day "
08 done
09 echo ""
10 }
11
12 show_number()
13 {
14 for(( integer = 1; integer <= 7; integer++ ))
15 do
16 echo -n "$integer "
17 done
18
19 echo ""
20 }
21
22 show_square()
23 {
24 i=0
25
26 until [[ "$i" -gt 7 ]]
27 do
28 let "square=i*i"
29 echo "$i * $i = $square"
30 let "i++"
31 done
32 }
33
34 show_week
35 show_number
36 show_square
function5.sh
view sourceprint?
02
03 #递归调用函数
04 foo()
05 {
06 read y
07 foo $y
08 echo "$y"
09 }
10
11 #调用函数
12 foo
13 exit 0
function6.sh
view sourceprint?
02 #$1的阶乘
03
04 fact ()
05 {
06 local num=$1
07 if [ "$num" -eq 0 ]
08 then
09 factorial=1
10 else
11 let "decnum=num-1"
12 fact $decnum
13 let "factorial=$num * $?"
14 fi
15 return $factorial
16 }
17
18 if [ -z $1 ];then
19 echo 'Please input an intger number argument.'
20 echo "Uage:[$0 args]"
21 echo "Example:[$0 5]"
22 exit 0
23 fi
24
25 fact $1
26 echo "Factorial of $1 is $?"
27 exit 0
1 [aa@aa shell]$ wow='Wow,great!'
注意这里HERE还有一个特殊的用法 :
就是在HERE前面加上-或者给HERE加上' ',加上-表明下述文字段所有TAB键将全部忽略,加上' '表明以下凡是变量定义用到了' ',将会使变量呈现所见即所得的形式,也即关闭变量替换;如果加上的是" "双引号,则会进行变量替换。
1 [aa@aa shell]$ wow='Wow,great!'
注意:这里的$wow被原样输出了。至于加上-的效果这里不细说,大家可自行测试。
这是第二行批注
这是第三行批注
其它行,类推
HERE
:代表什么都不做
原本bash只支持单行批注(用#表示),现就可用于多行注释了,此处不细说。
01 #!/bin/sh
执行脚本:
1 [aa@aa shell]$ ll
view sourceprint?
1 [aa@aa shell]$ /data/shell/here_doc.sh
view sourceprint?
1 [aa@aa shell]$ /data/shell/here_doc.sh 'htm$' 'html' *.htm
下面让我们详细说明下。
01 #!/bin/bash
7.函数
{
command1
command2
…
commandN
}
其中标题:函数名,函数体:函数内的命令集合,在编写脚本时要注意标题名应该唯一,如果不唯一,脚本执行时会产生错误。
在函数名前可以加上关键字function,但加上和省略关键字function对脚本的最终执行不产生任何影响。
函数体中的命令集合必须含有至少一条命令,即函数不允许空命令,这一点和C语言不同。
函数之间可通过参数、函数返回值交互,函数在脚本中出现的次序可以是任意的,但是必须按照脚本中的调用次序执行这些函数。
向函数传递参数
在bash Shell编程中,向函数传递的参数仍然是以位置参数的方式来传递的,而不能传递数组等其它形式变量,这与C语言或Java语言中的函数传递是不同的。
01 #!/bin/bash
在Linux Shell编程中,函数还可传递间接参数,但该方式传递方式远远没有C语言和Java语言灵活,而只能使用间接变量引用来传递参数,这种方式是一种笨拙的间接参数传递方式。
01 #!/bin/bash
函数返回值
有时需要脚本执行完成后返回特定的值来完成脚本的后继操作,这些特定的值就是函数返回值。在Linux Shell编程中,函数通过return返回其退出状态,0表示无错误,1表示有错误。在脚本中可以有选择的使用return语句,因为函数在执行完最后一条语句后将执行调用该函数的地方执行后继操作。
01 #!/bin/bash
脚本放置多个函数
可以在脚本中放置多个函数,脚本执行时按照调用函数的顺序执行这些函数.
01 #!/bin/bash
函数相互调用
在Linux Shell编程中,函数之间可以相互调用,调用时会停止当前运行的函数转去运行被调用的函数,直到调用的函数运行完,再返回当前函数继续运行。
一个函数调用多个函数
在Linux Shell编程中允许一个函数调用多个函数,在该函数调用其他函数时同样需要按照调用的顺序来执行调用的函数。
局部变量和全局变量
在Linux Shell编程中,可以通过local关键字在Shell函数中声明局部变量,局部变量将局限在函数范围内。此外,函数也可调用函数外的全局变量,如果一个局部变量和一个全局变量名字相同,则在函数中局部变量将会覆盖掉全局变量.
函数递归
Linux Shell中可以递归调用函数,即函数可以直接或间接调用其自身。在递归调用中,主调函数又是被调函数。执行递归函数将反复调用其自身,每调用一次就进入新的一层。
01 #!/bin/bash
使用局部变量进行递归一般是针对数值运行来使用的。阶乘运算是一个使用局部变量的递归调用过程,实现了n! 的运算,其可以通过下面的公式表示:
n!=1 (n=0)
n!=n*(n-1)! (n>=1)
按照该公式可实现对阶乘的运算,由于该阶乘运算中存在终止条件“0!=1”,所以可以使用函数递归来实现该运算。
01 #!/bin/bash
ok.到这里先暂告一段落,其他的后续写出。