一、什么是shell程序
以文件形式存放批量的Linux命令集合,该文件能够被Shell解释执行,这种文件就是Shell脚本程序
通常由一段Linux命令、Shell命令、控制语句以及注释语句构成Shell 脚本的编写
Shell 脚本是纯文本文件,可以使用任何文本编辑器编写
Shell 脚本通常是以 .sh 作为后缀名
第一行:指定用哪个程序来编译和执行脚本。#!/bin/bash
注释行:使用(#)符号
二、shell编程的主要内容
变量
本地变量、环境变量、位置参量
输入输出
read/echo或printf
条件测试
整数测试、逻辑测试、字符串测试
控制语句
条件/循环/分支/
函数
常用Shell程序内置指令
declare/export/eval/trap等
三、变量
(一)变量概述
(二)变量常见操作
(三)环境变量和只读变量
(四)位置参量(命令行参数)
位置参量是一组特殊的内置变量,通常被 shell 脚本用来从命令行接受参数,或被函数用来保存传递给它的参数。
执行 shell 脚本时,用户可以通过命令行向脚本传递信息,跟在脚本名后面的用空格隔开的每个字符串都称为位置参量。
在脚本中使用这些参数时,需通过位置参量来引用。例如: $1 表示第一个参数,$2 表示第二个参数,以此类推。 $9 以后需要用花
括号把数字括起来,如第 10 个位置参量以 ${10} 的方式来访问。
#例1:shell_test.sh
echo “the count of parameters:$#”
echo “first param=$1”
echo “second param=$2”
echo “params’ string=$*”
shell_test.sh This is Peter
shell_test.sh This is "Peter Piper" //如果位置参量中含有空格,则需要使用双引号
(五)数组
四、输入输出
(一)输入--read命令
read var |
从标准输入读取一行并赋值给变量var |
read |
标准输入读取一行并赋值给内置变量REPLY |
read -a arr |
读入一组词,依次赋值给数组arr |
read -p "please input 5 digits:" -t 10 -a arr3 // -p 提示符 -t 超时
stty -echo // 输入不回显
stty echo // 输入回显
echo $num 或 echo ${num} //输出一行文本
echo -n “Hello World” // -n 去掉换行符
echo -e “\t” “Hello World” // -e 支持转义
(三)echo输出颜色与光标定位:
\33[30m -- \33[37m 设置前景色(字体颜色)
\33[40m -- \33[47m 设置背景色
\33[y;xH设置光标位置
echo –e “\033[31mthis is a test”
echo -e "\033[10;5H\033[31;46mthis is a test“
echo -e "\033[0m" // 取消全部设置
五、算术扩展
(一)单引号、双引号、反引号区别
单引号 忽略所有特殊字符
双引号 忽略大部分特殊字符($,`等字符除外) 参考这里 或者尝试 X=*; echo $X; echo ‘$X‘; echo "$X"; 的区别
反引号 命令替换(将一个命令的标准输出插入到命令的任何位置
$() 同上
命令替换可以嵌套
如果使用反引号,则内部的反引号必须用反斜杠来转义。
echo `basename \`pwd\``
echo $(basename $(pwd))
算术运算符:
+、-、*、/(四则运算) |
**、% (幂运算 和 模运算,取余数) |
<<、>> (按位左移 和 按位右移) |
&、^、| (按位与 、按位异或 和 按位或) |
=、+=、-=
、*=、/=、%= |
<、>、<=、>=、==、!= (比较操作符) |
&&、|| (逻辑与 和 逻辑或) |
算术扩展:
$[] n=5; echo $[$n+1]
$(()) n=5; echo $(($n+1))
(()) ((n+=1)); echo $n
expr
expr 4 + 5 注意+号两边要有空格
r=`expr 4 + 5`
r=`expr 4 \* 5`
let // 内置命令 type let
let n=n+1
let “n = n + 1”
let “n=n+abc” // abc 当做0
六、条件测试
任何一种测试中,都要有退出状态(返回值),退出状态为 0 表示命令成功或表达式为真,非0 则表示命令失败或表达式为假。
状态变量 $? 中保存命令退出状态的值
grep study /etc/passwd; echo$?
grep hello /etc/passwd;echo$?
表达式测试包括字符串测试、整数测试和文件测试。
通常用 test 命令来测试表达式的值
x=5; y=10
test $x -gt $y
echo $?
x=5; y=10
[ $x -gt $y ]
echo $?
2.x 版本以上的 Bash 中可以用双方括号来测试表达式的值,此时可以使用通配符进行模式匹配。
name=Tom
[[ $name = [Tt]?? ]]
echo $?
(二)字符串测试(方括号只能使用!= ==) //字符串测试最好加上" "
[ -z$str] |
如果字符串 str 长度为0,返回真 |
[ -n$str] |
如果字符串 str 长度不为0,返回真 |
[ $str1== $str2] |
两字符串相等 |
[ $str1!=$str2] |
两字符串不等 |
name=Tom; [ -z $name ]; echo $?
name2=Andy; [ $name == $name2 ] ; echo $?
(三)整数测试 //操作符两边必须留空格!
[ int1-eqint2] |
int1等于int2 |
[ int1-neint2] |
int1不等于int2 |
[ int1-gtint2] |
int1大于int2 |
[ int1-geint2] |
int1大于或等于int2 |
[ int1-ltint2] |
int1小于int2 |
[ int1-leint2] |
int1小于或等于int2 |
x=1; [ $x -eq 1 ]; echo $?
整数测试也可以使用 let 命令或双圆括号:
相应的操作符为:== 、!= 、> 、>= 、< 、<=
x=1; let "$x == 1"; echo $?
x=1; (($x+1>= 2 )); echo $?
let 和 双圆括号中可以使用算术表达式,而方括号不能
let 和 双圆括号中,操作符两边可以不留空格
(四)逻辑测试
[expr1-aexpr2] |
逻辑与,都为真时,结果为真 |
[expr1-oexpr2] |
逻辑或,有一个为真时,结果为真 |
[!expr] |
逻辑非 |
x=1; name=Tom;
[ $x -eq 1 –a –n $name ]; echo $?
[ ( $x -eq 1 ) –a ( –n $name ) ]; echo $? //error, 不能随便添加括号
可以使用模式的逻辑测试:
[[pattern1&&pattern2]] |
逻辑与 |
[[pattern1||pattern2]] |
逻辑或 |
[[!pattern]] |
逻辑非 |
(五)检查空值
[ "$name" = "" ] [ ! "$name" ] [ "X${name}" = "X" ]
(六)文件测试
文件测试:文件是否存在,文件属性,访问权限等。更多文件测试符参见 man test
-ffname |
fname 存在且是普通文件时,返回真 ( 即返回0 ) |
-L fname |
fname 存在且是链接文件时,返回真 |
-d fname |
fname 存在且是一个目录时,返回真 |
-e fname |
fname(文件或目录)存在时,返回真 |
-s fname |
fname 存在且大小大于0 时,返回真 |
-r fname |
fname(文件或目录)存在且可读时,返回真 |
-w fname |
fname(文件或目录)存在且可写时,返回真 |
-x fname |
fname(文件或目录)存在且可执行时,返回真 |
(七)括号总结
${...} |
获取变量值 |
$(...) |
命令替换 |
$[...] |
让无类型的变量参与算术运算 |
$((...)) |
同上 |
((…)) |
算术运算 |
[ ... ] |
条件测试,等价于test命令 |
[[ ... ]] |
条件测试,支持模式匹配与通配符 |
七、条件与分支语句
(一)if条件语句
if expr1 #如果expr1为真(返回值为0)
then #那么
commands1 #执行语句块commands1
elif expr2 #若expr1不真,而expr2为真
then #那么
commands2 #执行语句块commands2
... ... #可以有多个elif语句
else # else最多只能有一个
commands4 #执行语句块commands4
fi #if语句必须以单词fi终止
几点说明:
elif 可以有任意多个(0 个或多个); else 最多只能有一个(0 个或 1 个); if 语句必须以 fi 表示结束
expr 通常为条件测试表达式;也可以是多个命令,以最后一个命令的退出状态为条件值。
if 语句可以嵌套使用。
(二)case 选择语句
case expr in # expr为表达式,关键词in不要忘!
pattern1) # 若expr与pattern1匹配,注意括号
commands1 # 执行语句块commands1
;; # 跳出case结构
pattern2) # 若expr与pattern2匹配
commands2 #执行语句块commands2
;; # 跳出case结构
...... # 可以有任意多个模式匹配
*) # 若expr与上面的模式都不匹配
commands # 执行语句块commands
;; # 跳出case结构
esac # case语句必须以esac终止
几点说明:
表达式 expr 按顺序匹配每个模式,一旦有一个模式匹配成功,则执行该模式后面的所有命令,然后退出 case。
所给的匹配模式 pattern 中可以含有通配符和“ | ”。
每个命令块的最后必须有一个双分号,可以独占一行,或放在最后一个命令的后面。
八、循环语句
(一)for 循环
for variable in list
# 每一次循环,依次把列表list中的一个值赋给循环变量
do #循环开始的标志
commands #循环变量每取一次值,循环体就执行一遍
done #循环结束的标志
几点说明:
列表 list 可以是命令替换、变量名替换、字符串和文件名列表 ( 可包含通配符 )可以省略 in list ,此时使用“$@”
for ((exp1;exp2;exp3) //类似于C语言的for 循环
do
done
(二)while 和until循环
while expr #执行expr
do #若expr的退出状态为0,进入循环,否则退出while
commands #循环体
done #循环结束标志,返回循环顶部
until expr #执行expr
do #若expr的退出状态非0,进入循环,否则退出until
commands #循环体
done #循环结束标志,返回循环顶部
(三)break和continue、exit和sleep
break [n]
用于强行退出当前循环。continue [n]
用于忽略本次循环的剩余部分,回到循环的顶部,继续下一次循环。
如果是嵌套循环,continue 命令后面也可跟一数字 n,表示回到第 n 重循环的顶部。
exit n
exit 命令用于退出脚本或当前进程。n 是一个从 0 到 255 的整数,0 表示成功退出,非零表示遇到某种失败而非正常退出。该整数被保存在状态变量 $? 中。sleep n 暂停 n 秒钟
(四)select循环和菜单
select variable in list
do #循环开始的标志
commands #循环变量每取一次值,循环体就执行一遍
done #循环结束的标志
select 循环主要用于创建菜单,按数字顺序排列的菜单项将显示在标准错误上,并显示 PS3 提示符,等待用户输入 select 是个无限循环,因此要记住用 break 命令退出循环,或用 exit 命令终止脚本。也可以按 ctrl+c 退出循环。
select 经常和 case 联合使用
与 for 循环类似,可以省略 in list ,此时使用位置参量
九、函数
一个函数就是一个子程序,用于完成特定的任务,当有重复代码,或者一个任务只需要很少的修改就被重复几次执行时, 这时你应考虑使用函数。
function function_name {
commands
}
或
function_name() {
commands
}
只需输入函数名即可调用该函数 函数必须在调用之前定义
如果要调用其他文件的函数,可以在开头 . 文件名 //类似文件包含,也可以使用source
#!/bin/bash
fun2()
{
echo "This is fun2."
echo "Now exitingfun2."
}
fun2 #调用函数fun2
#! /bin/bash
func1()
{
echo "theparameter‘s count:$#"
echo "the firstparameter:$1"
echo "the secondparameter:$2"
}
func1 a b
(一)字符串操作:
m 的取值从0 到${#var}-1
注:pattern,old中可以使用通配符。
${#var} |
返回字符串变量 var的长度 |
${var:m} |
返回${var}中从第m+1个字符到最后的部分 |
${var:m:len} |
返回${var}中从第m+1个字符开始,长度为len的部分 |
${var#pattern} |
删除${var}中开头部分与pattern匹配的最小部分 |
${var##pattern} |
删除${var}中开头部分与pattern匹配的最大部分 |
${var%pattern} |
删除${var}中结尾部分与pattern匹配的最小部分 |
${var%%pattern} |
删除${var}中结尾部分与pattern匹配的最大部分 |
${var/old/new} |
用new替换${var}中第一次出现的old |
${var//old/new} |
用new替换${var}中所有的old(全局替换) |
(二)随机数和 expr 命令
echo $RANDOM // 生成随机数的特殊变量
expr 5 % 3
expr 5 \* 3 #乘法符号必须被转义
注意:目前比较少使用,可用$[ ... ]替换
一般用于函数或者脚本程序参数处理,特别是参数多于10以上的时候
将所有参数变量向下移动一个位置,$2变成$1,$3变成$2,依次递进,但$0保持不变
例如:
while [ "$1" != "" ]
do
echo $1
shift
done
(四)eval 命令
eval arg1 [arg2] ... [argN]
listpage="ls -l | more"
eval $listpage
(五)trap命令
trap command signal
command
一般情况下是Linux命令
’ ’表示发生陷阱时为空指令,不做任何动作
’-’表示发生陷阱时采用缺省指令
signal
HUP(1)
挂起;一般因终端掉线或用户退出而引发
INT(2)
中断;一般因按下”Ctrl+C”组合键引发
QUIT(3)
退出;一般因按下”Ctrl+\”组合键引发
ABRT(6)
异常中止;一般因某些严重的执行错误而引发
ALRM(14)
闹钟;一般是超时时钟到来而引发
TREM(15)
中止;一般由系统在关机的时候发出
#!/bin/bash
#安装2、3号信号
#处理代码为"rm-ftmp$$;exit0"
trap "rm -ftmp$$;exit 0" 2 3
#生成文件,文件名为tmp+当前进程号
touch tmp$$
#睡眠60秒,以便向当前进程发送信号
sleep 60
(六)declare 命令
declare或typeset内建命令(它们是完全相同的)可以用来限定变量的属性.这是在某些编程语言中使用的定义类型不严格的方式。命令declare是bash版本2之后才有的。命令typeset也可以在ksh脚本中运行。
1 declare -r var1
|
(declare -r var1与readonly var1作用相同)
这大致和C的const限定词相同.一个试图改变只读变量值的操作将会引起错误信息而失败.
declare -i number
# 脚本余下的部分会把"number"当作整数看待.
|
declare -a indices
|
变量indices会被当作数组.
declare -f
|
在脚本中没有带任何参数的declare -f 会列出所有在此脚本前面已定义的函数出来。
declare -f function_name
|
而declare -f function_name则只会列出指定的函数.
declare -x var3
|
这样将声明一个变量作为脚本的环境变量而被导出。
declare -x var3=373
|
declare命令允许在声明变量类型的时候同时给变量赋值。
(七)shell内置命令总结
|
|
echo |
输出一行文本到标准输出设备 |
read |
从标准输入设备读入数据 |
printf |
格式化输出 |
declare |
定义或创建变量或数组 |
let |
让未定义的变量参与算术运算 |
expr |
执行表达式 |
shift |
把所有参数变量向下移动一个位置 |
eval |
执行命令 |
trap |
用来定义接收OS信号后而采取的动作 |
exit |
退出SHELL程序 |
sleep |
睡眠 |
test |
条件测试 |
参考:
《鸟哥的Linux私房菜基础篇》
《高级bash shell编程指南》
原文:http://blog.csdn.net/jnu_simba/article/details/19474327