`

Shell编程学习摘录十三--shell函数

阅读更多
shell允许将一组命令集或语句形成一个可用块,这些块称为shell 函数.

函数由两部分组成:
函数标题
函数体

标题是函数名.函数体是函数内的命令集合.标题名应该唯一;如果不是,将会混淆结果,因为脚本在查看调用脚本前将首先搜索函数调用响应的shell.

格式:
函数名 ()
{
命令1
...
}
或者
函数名() {
命令1
...
}

两种方式都可行.如果愿意,可在函数名前加上关键字function,这取决于使用者需求.

function 函数名 ()
{ ...
}

19.1 在脚本中定义函数
以下是一个简单函数
hello ()
{
echo "Hello there today's date is `date`"
}

19.2 在脚本中使用函数
$ vi func1.sh
#!/bin/bash
hello ()
{
echo "hello there today's date is `date`"
}
hello
运行脚本:
$ sh func1.sh
Hello there today's date is Tue Sep 11 11:41:21 CST 2007

19.3 向函数传递参数
函数里调用参数(变量)的转换以下划线开始,后加变量名,如: _FILENAME或_filename.

19.4 从调用函数中返回
当函数完成处理或希望函数基于某一测试语句返回时,可做两种处理:
1)让函数正常执行到函数末尾,然后返回脚本种调用函数的控制部分.
2)使用return返回脚本种函数调用的下一条语句,可以带返回值.0为无错误,1为有错误.
这是可选的,于最后状态命令报表例子极其类似,格式为:
return  从函数种返回,用最后状态命令决定返回值
Return 0  无错误返回
Return 1 有错误返回

19.6 在shell中使用函数
当你收集一些经常使用的函数时,可以将之放入函数文件中并将文件载入shell.
一旦文件载入shell,就可以在命令行或脚本中调用函数.可以使用set命令查看所有定义的函数.输出列表包括已经载入shell的所有函数.

19.7 创建函数文件

下面创建包容函数的函数文件并将之载入shell,进行测试,再做改动,之后再重新载入.
函数文件名为functions.main,内容如下:
$ vi functions.main
#!/bin/bash
#functions.main
#findit:this is front end for the basic find command
findit() {
if [ $# -lt 1 ]; then
echo "usage:findit file"
return 1
fi
find / -name $1 -print

19.8 定位文件
定位文件格式为:
./pathname/filename
现在文件已经创建好了,要将之载入shell,键入:
. /functions.main 或.  functions.main(应该是后者正确)
点-空格-斜线-文件名,或点-空格-文件名

19.9 检查载入函数
使用set命令确保函数已载入,set命令将在shell中显示所有的载入函数.

19.10 执行shell 函数
要执行函数,简单地键入函数名即可.

19.10.1 删除shell 函数
$ unset function_name

19.10.2 编辑shell函数
编辑函数functions.main,加入for循环以便脚本可以从命令行中读取多个参数.改动后函数脚本如下:
$ vi functions.main
#!/bin/bash
findit()
{
#findit
if [ $# -lt 1 ];then
echo "usage:findit file"
return 1
fi
for loop
do
find / -name $loop -print
done
}
执行改动过的findit函数,输入参数:
$ findit passwd

1.却提示错误:
-bash: findit: command not found ?
通常Shell程序将在子Shell中执行,该程序对变量的改变只在子Shell中有效而在当前Shell中无效。"."命令可以使Shell程序在当前Shell中执行。用户可以在当前Shell中定义函数和对变量赋值。
A: 输入 . functions1.main , 然后执行 findit passwd后正常

2.return 1 是什么意思?
A: 通常,函数中的最后一个命令执行后,就退出被调用函数。也可利用return命令立即退出函数,其语法格式是:
return [ n ]
其中,n值是退出函数时的退出值(退出状态),即$?的值,当n值缺省时,则退出值是最后一个命令执行后的退出值.


19.10.3 函数举例
既然已经学习了函数的基本用法,现在就用它来做一些工作.函数可以节省大量的编程时间,因为它时可重用的.

1.变量输入
以下脚本询问名,然后是姓:
$ vi func2.sh
# func2
echo -n "What is your first name:"
read F_NAME
echo -n "What is you surname:"
read S_NAME
要求输入字符必须只包含字母,以下是取得只有小写或大写字符的测试函数.
char_name()
{
# char_name
# to call: char_name string
# assign the argument across to new variable
_LETTERS_ONLY=$1
# use awk to test for characters only!
_LETTES_ONLY=`echo $1|awk '{if($0~/[^a-z A-Z]/) print "1"}'`
if [ "$_LETTERS_ONLY" != "" ]
then
# oops errors
return 1
else
# contains only chrs
return 0
fi
}

2.echo 问题
使用echo时,提示应放在语句末尾,以等待从 read命令中接受进一步输入。
linux 和bsd为此使用echo 命令-n 选项.
在echo 语句开头linux使用-e选项反馈控制字符.其他系统使用反斜线保证shell获知控制字符的存在。

3.读单个字符
在菜单进行选择时,最麻烦的工作是必须在选择后键入回车键,或显示"press any key to continue".可以使用dd命令解决不键入回车符以发送击键序列的问题。
dd命令常用于对磁带或一般的磁带解压任务中出现的数据问题提出质疑或转换,但也可用于创建定长文件.下面创建长度为1M的文件myfile.
dd if=/dev/zero of=myfile count=512 bs=2048
注:
dev/null 是linux的拉圾箱,任何重定向到该设备的文件都将被丢弃
/dev/zero 是添零设备,提供无限个零
cp /dev/null tmp 将使tmp文件为空
cp /dev/zero tmp 若不加限制将迅速填满整个文件系统
dd命令可以翻译键盘输入,可被用来接受多个字符,这里如果只要一个字符,dd命令需要删除换行自负,这与用户点击回车键相对应.dd只送回车前一个字符.在输入前必须使用stty命令将终端设置成未加工模式,并在dd执行前保存设置,在dd完成后恢复终端设置。
函数如下:
read_a_char()
#read_a_char
{
#save the settings
SAVEDSTTY=`stty -g`
# set terminal raw please
stty cbreak
#read and output only one character
dd if=/dev/tty bs=1 count=1 2>/dev/null
# restore terminal and restore stty
stty -cbreak
stty $SAVEDSTTY
}
要调用函数,返回键入字符,可以使用命令替换操作,例子如下:
echo -n "Hit any key to continue"
character=`read_a_char`
echo "In case you are wondering you perssed $character"

4.测试目录存在
拷贝文件时,测试目录是否存在时常见的工作之一.以下函数测试传递给函数的文件名是否是一个目录.因为此函数返回时带有成功或失败取值,可用if语句测试结果.
is_it_a_directory()
{
#is_it_a_directory
$to call:is_it_a_directory directory_name
if [ $# -lt 1 ]
; then
echo "is_it_a_directory: I need an argument"
return 1
fi
# is it a directory ?
_DIRECTORY_NAME=$1
if [ ! -d $_DIRECTORY_NAME ]
; then
# no it is not
return 1
else
# yes it is
return 0
fi
}
要调用函数并测试结果,可使用:
echo -n "enter destination directory:"
read DIREC
if is_it_a_directory $direc;
then:
else
echo "$DIREC does not exitst,create it now? [y..n]"
#commands go here to either create the directory or exit
...
...
fi

5. 提示Y或N
许多脚本在继续处理前会发出提示.大约可以提示以下动作:
创建一个目录
是否删除文件
是否后台运行
确认保存记录
等等

6.从登陆ID号中抽取信息
当所在系统很庞大,要和一登陆用户通信时,如果忘了用户的全名,是很讨厌的事情.比如有时你看到用户锁住了一个进程,但是他们的用户ID对你来说没有意义,因此必须用grep passwd文件以取得用户全名,然后从中抽取可用信息,向其发信号,让其他用户开锁.

7.列出文本文件行号
在vi编辑器中,可以列出行号来进行调试,但是如果打印几个带有行号的文件,必须使用nl命令。

8.字符串大写
有时需要在文件中将字符串转为大写,例如在文件系统中只用大写字符创建目录或在有效的文本域中将输入转换为大写数据。
可以用tr命令。

9.is_upper
虽然函数str_to_upper做字符串转换,但有时在进一步处理前只需知道字符串是否为大写,is_upper实现此功能.在脚本中使用if语句决定传递的字符串是否为大写。

10.字符串小写
现在实现此功能,因为已经给出了str_to_upper,最好相应给出str_to_lower.函数工作方式与前面一样。

11.字符串长度
在脚本中确认域输入有效是最常见的任务之一.确认有效包括许多方式,如输入是否为数字或字符;域的格式长度是否为确定形式或值.
假定脚本要求用户交互输入数据到名称域,你会想控制此域包含字符数目,比如人名最多为20个字符.有可能用户输入超过50个字符,以下函数实施控制功能.需要向函数传递两个参数,实际字符串和字符串最大长度.

12.chop
chop函数删除字符串前面字符。可以指定从第一个字符起删去的字符数.假定有字符串

13.months
产生报表或创建屏幕显示时,为方便起见有时要快速显示完整月份。函数months,接受月份数字或月份缩写作为参数,返回完整月份.


19.10.4 将函数集中在一起
测试函数时,首先将其作为代码测试,当结果满意时,再将其转换为函数,这样做可节省大量时间。


19.11 函数调用
本章最后讲述使用函数的两种不同方法:从原文件中调用函数和使用脚本中的函数.


19.11.1 在脚本中调用函数
要在脚本中调用函数,首先创建函数,并确保它位于调用之前.


19.11.2 从函数文件中调用函数
将函数放入函数文件,比如functions.sh里,sh即shell脚本。
函数文件在脚本中以下述命令格式定位:
.\
使用这种方法不会创建另一个shell,所有函数均在当前shell下执行。


19.12 定位文件不只用于函数
定位文件不只针对于函数,也包含组成配置文件的全局变量。
假定有两个悲愤文件备份同一系统的不同部分。最好让他们共享一个配置文件。为此需要在一个文件里创建用户变量,然后将一个备份脚本删除后,可以载入这些变量以获知用户在备份开始前是否要改变其缺省值.有时候也要悲愤到不同的媒体中
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics