“夕阳无限好,只是近黄昏。”——李商隐《乐游原》
终于到第四趴了,这也将是这个系列的最后一个部分了。我先把结束语写在前面吧,Shell是一门博大精深的脚本语言,实际上因为Shell可以直接调用很多现成的或者定制的命令,比如awk,比如top,甚至java 命令行,这就在事实上给了shell可扩展的无限可能性。所以到目前为止带大家所看到的只是shell编程冰山的一角,希望大家在日常使用中慢慢积累。有机会的话我们再谈一谈OOTB的linux命令集。find, sed, grep, 等等,又将是一个很大的话题。
04
—
Shell函数
函数可以让我们将一个复杂功能划分成若干模块,让程序结构更加清晰,代码重复利用率更高。Shell 函数必须先定义后使用。
[function] function_name () { list of commands [ return value ]}
function 关键字为可选。可以用显式return语句提供返回值;如果不加,会将最后一条命令运行结果作为返回值。
Shell 函数返回值只能是整数,一般用来表示函数执行成功与否,0表示成功,其他值表示失败。如果 return 其他数据,比如一个字符串,往往会得到错误提示:“numeric argument required”。
如果一定要让函数返回字符串,权宜之计是先定义一个变量,用来存放函数的计算结果,脚本在需要的时候访问这个变量来获得函数返回值。这更像是oracle 存储过程中的 out参数。
函数的调用不需要加括号。
来看个例子:
#!/bin/bash
funWithReturn(){
echo"The function is to get the sum of two numbers..."
echo-n"Input first number: "
readaNum
echo-n"Input another number: "
readanotherNum
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: 25Input another number: 50The two numbers are 25 and 50 !The sum of two numbers is 75 !
像删除变量一样,删除函数也可以使用 unset 命令,不过要加上 .f 选项,如下所示:
$unset.f function_name
和执行脚本类似,调用函数时可以向其传递参数。在函数体内部,通过 $n 的形式来获取参数的值,例如,$1表示第一个参数,$2表示第二个参数... 另外,$#, $@, $*的作用也和前文诉述的作用一致。
#!/bin/bash
funWithParam(){
echo"The value of the second parameter is $2 !"
echo"The amount of the parameters is $# !"# 参数个数
echo"The string of the parameters is $* !"# 传递给函数的所有参数
}
funWithParam123
输出如下:
The value of the second parameter is 2 !The amount of the parameters is 3!The string of the parameters is 1 2 3!"
注意,$10 不能获取第十个参数,获取第十个参数需要$。当n>=10时,需要使用$来获取参数。
Shell输入输出重定向
命令的输出不仅可以是显示器,还可以很容易的转移向到文件,这被称为输出重定向。语法为
$command>file
输出重定向会覆盖文件内容,如果不希望文件内容被覆盖,可以使用 >> 追加到文件末尾,例如:
$ echo line 2 >> file
和输出重定向一样,Unix 命令也可以从文件获取输入,语法为:
$command
这样,本来需要从键盘获取输入的命令会转移到文件读取内容。l例如,
$ wc -l
一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件:
标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。
标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。
标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。
如果希望 stderr 重定向到 file,可以这样写:
$command2>file
2 表示标准错误文件(stderr)。
如果希望将 stdout 和 stderr 合并后重定向到 file,可以这样写:
$command>file2>&1
或
$command>>file2>&1
如果希望对 stdin 和 stdout 分别重定向,可以这样写:
$commandfile2
Here Document
Document 是 Shell 中的一种特殊的重定向方式,它的基本的形式如下:
command
document content
delimiter
它的作用是将两个 delimiter 之间的内容作为输入传递给 command。
注意:
结尾的delimiter 一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和 tab 缩进。
开始的delimiter前后的空格会被忽略掉。
下面的例子,通过 wc -l 命令计算 document 的行数:
$wc -l
下面的脚本通过 vi 编辑器将 document 保存到 test.txt 文件:
#!/bin/sh
filename=test.txt
vi$filename
This file was created automatically from
a shell script
^[
ZZ
EndOfCommands
运行脚本:
$ sh test.shVim: Warning: Input is not from a terminal$
打开 test.txt,可以看到下面的内容:
$ cat test.txtThis file was created automatically froma shell script$
/dev/null 文件
/dev/null 是一个特殊的文件,写入到它的内容都会被丢弃;如果尝试从该文件读取内容,那么什么也读不到。如果希望屏蔽 stdout 和 stderr,可以这样写:
$command>/dev/null2>&1
Shell文件包含
Shell 也可以包含外部脚本,将外部脚本的内容合并到当前脚本。Shell 中包含脚本可以使用:
.filename
或
sourcefilename
注意,点号(.)和文件名中间有一空格。
例如,创建两个脚本,一个是被调用脚本 subscript.sh,内容如下:
name="glen"
一个是主文件 main.sh,内容如下:
#!/bin/bash
../subscript.sh
echo$name
执行脚本:
$chomd +x main.sh./main.shglen$
注意,被包含脚本不需要有执行权限。
Shell调试
shell调试有三种方式
命令行方式
sh -x shell.script
脚本文件首行指定
#!/bin/bash -x
使用set
set -x
-v 显示所有行,详细模式
-n 检查语法,不执行命令
-x shell 跟踪模式,显示所有命令和参数
领取专属 10元无门槛券
私享最新 技术干货