一、Shell函数:Shell函数返回值、删除函数、在终端调用函数
函数可以让我们将一个复杂功能划分成若干模块,让程序结构更加清晰,代码重复利用率更高。像其他编程语言一样,Shell也支持函数。Shell函数必须先定义后使用。
Shell函数的定义格式如下:
function_name () { list of commands [ return value ] }
如果你愿意,也可以在函数名前加上关键字function:
function function_name () { list of commands [ return value ] }
函数返回值,可以显式增加return语句;如果不加,会将最后一条命令运行结果作为返回值。
#一定要有返回值的意思
Shell函数返回值只能是整数,一般用来表示函数执行成功与否,0表示成功,其他值表示失败。如果return其他数据,比如一个字符串,往往会得到错误提示:“numericargumentrequired”。
如果一定要让函数返回字符串,那么可以先定义一个变量,用来接收函数的计算结果,脚本在需要的时候访问这个变量来获得函数返回值。
先来看一个例子:
-
#!/bin/bash
-
# Define your function here
-
Hello () {
-
echo "Url is http://see.xidian.edu.cn/cpp/shell/"
-
}
-
# Invoke your function
-
Hello
运行结果:
$./test.sh Hello World $
调用函数只需要给出函数名,不需要加括号。
再来看一个带有return语句的函数:
-
#!/bin/bash
-
funWithReturn(){
-
echo "The function is to get the sum of two numbers..."
-
echo -n "Input first number: " # echo 附带自动换行
-
read aNum
-
echo -n "Input another number: "
-
read anotherNum
-
echo "The two numbers are $aNum and $anotherNum !"
-
return $(($aNum+$anotherNum))
-
}
-
funWithReturn
-
# Capture value returnd by last command
-
ret=$? # $?--上个命令的退出状态或者函数的返回值
-
echo "The sum of two numbers is $ret !"
运行结果:
The function is to get the sum of two numbers... Input first number: 25 Input another number: 50 The two numbers are 25 and 50 ! The sum of two numbers is 75 !
函数返回值在调用该函数后通过$?来获得。
再来看一个函数嵌套的例子:#在一个函数里面调用另一个函数
-
#!/bin/bash
-
# Calling one function from another
-
number_one () {
-
echo "Url_1 is http://see.xidian.edu.cn/cpp/shell/"
-
number_two
-
}
-
number_two () {
-
echo "Url_2 is http://see.xidian.edu.cn/cpp/u/xitong/"
-
}
-
number_one
运行结果
Url_1 is http://see.xidian.edu.cn/cpp/shell/ Url_2 is http://see.xidian.edu.cn/cpp/u/xitong/
像删除变量一样,删除函数也可以使用unset命令,不过要加上.f选项,如下所示:
-
$unset .f function_name
如果你希望直接从终端调用函数,可以将函数定义在主目录下的.profile文件,这样每次登录后,在命令提示符后面输入函数名字就可以立即调用。#没有成功
二、Shell函数参数
在Shell中,调用函数时可以向其传递参数。在函数体内部,通过$n的形式来获取参数的值,例如,$1表示第一个参数,$2表示第二个参数...#$0表示的依然是脚本名
带参数的函数示例:
-
#!/bin/bash
-
funWithParam(){
-
echo "The value of the first parameter is $1 !"
-
echo "The value of the second parameter is $2 !"
-
echo "The value of the tenth parameter is $10 !"
-
echo "The value of the tenth parameter is ${10} !"
-
echo "The value of the eleventh parameter is ${11} !"
-
echo "The amount of the parameters is $# !" # 参数个数
-
echo "The string of the parameters is $* !" # 传递给函数的所有参数
-
}
-
funWithParam 1 2 3 4 5 6 7 8 9 34 73
运行脚本:
The value of the first parameter is 1 ! The value of the second parameter is 2 ! The value of the tenth parameter is 10 ! The value of the tenth parameter is 34 ! The value of the eleventh parameter is 73 ! The amount of the parameters is 11 ! The string of the parameters is 1 2 3 4 5 6 7 8 9 34 73 !"
注意,$10不能获取第十个参数,获取第十个参数需要${10}。当n>=10时,需要使用${n}来获取参数。
另外,还有几个特殊变量用来处理参数,前面已经提到:
特殊变量 | 说明 |
---|---|
$# | 传递给函数的参数个数。 |
$* | 显示所有传递给函数的参数。 |
$@ | 与$*相同,但是略有区别 |
$? | 函数的返回值。 |
三、Shell输入输出重定向:ShellHere Document,/dev/null文件
Unix命令默认从标准输入设备(stdin)获取输入,将结果输出到标准输出设备(stdout)显示。一般情况下,标准输入设备就是键盘,标准输出设备就是终端,即显示器。
输出重定向
命令的输出不仅可以是显示器,还可以很容易的转移向到文件,这被称为输出重定向。
#将命令执行后的结果以字符串的形式输出到文件中
命令输出重定向的语法为:
$ command > file
这样,输出到显示器的内容就可以被重定向到文件。
例如,下面的命令在显示器上不会看到任何输出:
$ who > users
打开users文件,可以看到下面的内容:
$ cat users oko tty01 Sep 12 07:30 ai tty15 Sep 12 13:32 ruth tty21 Sep 12 10:10 pat tty24 Sep 12 13:07 steve tty25 Sep 12 13:03 $
只有一个>,输出重定向会覆盖文件内容,(文件的偏移量是在开头处)请看下面的例子:
$ echo line 1 > users $ cat users line 1 $
如果不希望文件内容被覆盖,可以使用>>追加到文件末尾,例如:
$ echo line 2 >> users $ cat users line 1 line 2 $
输入重定向
和输出重定向一样,Unix命令也可以从文件获取输入,被称为输入重定向,语法为:
command < file
这样,本来需要从键盘获取输入的命令会转移到文件读取内容。
注意:输出重定向是大于号(>),输入重定向是小于号(<)。
例如,计算users文件中的行数,可以使用下面的命令:
$ wc -l users 2 users $
也可以将输入重定向到users文件:
$ wc -l < users 2 $
注意:上面两个例子的结果不同:第一个例子,会输出文件名;第二个不会,因为它仅仅知道从标准输入读取内容。
重定向深入讲解
一般情况下,每个Unix/Linux命令运行时都会打开三个文件:
-
标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。
-
标准输出文件(stdout):stdout的文件描述符为1,Unix程序默认向stdout输出数据。
-
标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。
默认情况下,command> file 将stdout重定向到file,command< file 将stdin重定向到file。
如果希望stderr重定向到file,可以这样写:
$command 2 > file
如果希望stderr追加到file文件末尾,可以这样写:
$command 2 >> file
2表示标准错误文件(stderr)。
如果希望将stdout和stderr合并后重定向到file,可以这样写:
$command > file 2>&1
或
$command >> file 2>&1
如果希望对stdin和stdout都重定向,可以这样写:
$command < file1 >file2
command 命令将stdin重定向到file1,将stdout重定向到file2。
全部可用的重定向命令列表
命令 | 说明 |
---|---|
command> file | 将输出重定向到 file。 |
command< file | 将输入重定向到 file。 |
command>> file | 将输出以追加的方式重定向到file。 |
n> file | 将文件描述符为 n的文件重定向到 file。 |
n>> file | 将文件描述符为 n的文件以追加的方式重定向到file。 |
n>& m | 将输出文件 m和 n合并。 |
n<& m | 将输入文件 m和 n合并。 |
<<tag | 将开始标记 tag和结束标记 tag之间的内容作为输入。 |
HereDocument
HereDocument 目前没有统一的翻译,这里暂译为”嵌入文档“。HereDocument 是Shell中的一种特殊的重定向方式,它的基本的形式如下:
command << delimiter documentdelimiter
它的作用是将两个delimiter之间的内容(document)作为输入传递给command。
#delimiter是分隔符的意思,是不是很喜欢用EOF作分隔符?_?,不是delimiter随便命名的0.0
注意:
-
结尾的delimiter一定要顶格写(意思就是说在一行的最前面),前面不能有任何字符,后面也不能有任何字符,包括空格和tab缩进。
-
开始的delimiter前后的空格会被忽略掉。
下面的例子,通过wc-l 命令计算document的行数:
$wc -l << EOF This is a simple lookup program for good (and bad) restaurants in Cape Town. EOF 3 $
也可以将 HereDocument 用在脚本中,例如:
-
#!/bin/bash
-
cat << EOF
-
This is a simple lookup program
-
for good (and bad) restaurants
-
in Cape Town.
-
EOF
运行结果:
This is a simple lookup program for good (and bad) restaurants in Cape Town.
下面的脚本通过vi编辑器将document保存到test.txt文件:
-
#!/bin/sh
-
filename=test.txt
-
vi $filename <<EndOfCommands
-
i
-
This file was created automatically from
-
a shell script
-
^[
-
ZZ
-
EndOfCommands
运行脚本:
$ sh test.sh Vim: Warning: Input is not from a terminal #terminal--终端 $
#执行完该脚本后,只有在当前目录下生成test.txt.swp的文件,这是vi非正常退出时产生的,至于为什么会非正常退出?不知道。不过可以用vi-r test.txt将.swp恢复成txt
打开test.txt,可以看到下面的内容:
$ cat test.txt This file was created automatically from a shell script $
/dev/null文件
如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null:
$ command > /dev/null
/dev/null是一个特殊的文件,写入到它的内容都会被丢弃;如果尝试从该文件读取内容,那么什么也读不到。但是 /dev/null文件非常有用,将命令的输出重定向到它,会起到”禁止输出“的效果。
如果希望屏蔽stdout和stderr,可以这样写:
$ command > /dev/null 2>&1
四、Shell文件包含
像其他语言一样,Shell也可以包含外部脚本,将外部脚本的内容合并到当前脚本。
Shell中包含脚本可以使用:
. filename
或
source filename
两种方式的效果相同,简单起见,一般使用点号(.),但是注意点号(.)和文件名中间有一空格。
例如,创建两个脚本,一个是被调用脚本subscript.sh,内容如下:
url="http://see.xidian.edu.cn/cpp/view/2738.html"
一个是主文件main.sh,内容如下:
-
#!/bin/bash
-
. ./subscript.sh
-
echo $url
执行脚本:
$chomd +x main.sh ./main.sh http://see.xidian.edu.cn/cpp/view/2738.html $
注意:被包含脚本不需要有执行权限。#有读权限就可以了