Shell脚本(英语:Shell script),又称Shell命令稿、程序化脚本,是一种电脑程序与文本文件,内容由一连串的shell命令组成,经由Unix Shell直译其内容后运作。被当成是一种脚本语言来设计,其运作方式与直译语言相当,由Unix shell扮演命令行解释器的角色,在读取shell脚本之后,依序运行其中的shell命令,之后输出结果。利用shell脚本可以进行系统管理,文件操作等。
在创建shell脚本时,必须在第一行指定要使用的shell,其格式为:
#!/bin/bash
(#):用作注释行,第一行是个列外,#后面的惊叹号会告诉shell用哪个shell来运行脚本,这里是可以使用bash
shell脚本的后缀一般是 sh结尾,写在shell里面的命令是按照行,从上往下执行的。
1)要加上执行权限。
chmod +x test.sh
用点号(.)执行,如 ./test.sh
或者:sh test.sh
假如使用sh命令执行脚本文件,可以没有+x 和 第一行解释器#!/bin/bash
假如不是使用sh命令,那么需要+x 且 第一行需要添加解释器#!/bin/bash
2)三种常见的调试
在命令行提供参数
[root@vm01 test]# sh -x test.sh #是debug模式
在脚本开头提供参数
#! /bin/sh -x
在脚本中用set命令启用或禁用参数
#! /bin/sh
if [ -z "$1" ]; then
set -x
echo "ERROR: Insufficient Args."
exit 1
set +x
fi
set -x和set +x分别表示启用和禁用-x参数,这样可以只对脚本中的某一段进行跟踪调试。
echo命令后面可以加上字符串,输入到控制台,可以用单引号或双引号划定文本字符串。
echo "hello\n\n"
echo -e "hello\n\n"
echo "hello"
echo -n "hello"
1)定义变量:变量名不加美元符号($)
your_name=“11hao”
注意,变量名和等号之间不能有空格
DATE=`date` #这种是动态变量
除了显式地直接赋值,还可以用语句给变量赋值,如:
for file in `ls /etc` #后面的 ls /etc引用的符号不是单引号,是数字1前面那个键。是用来动态获取命令执行后的结果的。
2)使用变量
your_name=“qinjx”
#两种方式均可
echo $your_name
echo ${your_name} #加花括号是为了帮助解释器识别变量的边界
如:echo ${your_name} what
3)给变量传递参数
$1,$2,$3等,在shell代表传递的参数顺序
[root@vm01 test]# sh test.sh 11 hao
以“#”开头的行就是注释,会被解释器忽略。
sh里没有多行注释,只能每一行加一个#号
字符串是shell编程中最常用最有用的数据类型
字符串可以用单引号,也可以用双引号,也可以不用引号
单引号字符串的限制:
·单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的
·单引号字串中不能出现单引号(对单引号使用转义符后也不行)
1)字符串操作
拼接字符串
your_name=“11hao”
greeting=“hello, “$your_name” !”
greeting_1=“hello, ${your_name} !”
echo $greeting $greeting_1
获取字符串长度
string=“abcd”
echo ${#string} #输出:4
提取子字符串
string=“alibaba is a great company”
echo ${string:1:4} #输出:liba
用反斜杠可以转移shell里面的一些特殊的符号,比如说要正确打印$符号,那么在前面加一个反斜杠即可。
按照格式输出:
today=$(date +%y%m%d)
或者
today=`date +%y%m%d`
可以通过 | 把一个命令的输出传递给另一个命令做输入。
提示:awk里面的$1,表示输出第一列
df -k | awk ‘{print $1}’ | grep -v “文件系统”
tee命令把结果输出到标准输出,且生成一个副本到相应文件。
tee -a a.txt表示追加操作。
awk ‘{print $1}’ 表示打印第一列
df -k | awk '{print $1}' | grep -v "文件系统" | tee a.txt
df -k | awk '{print $1}' | grep -v "文件系统" | tee -a a.txt
">",">>":第一个表示覆盖,第二个表示追加
> file.txt 把标准输出重定向到新文件中
>> file.txt 追加
在LINUX中,周期执行的任务一般由cron这个守护进程来处理[ps -ef|grep cron]。cron读取一个或多个配置文件,这些配置文件中包含了命令行及其调用时间。cron的配置文件称为“crontab”,是“cron table”的简写。
文件路径:/etc/crontab
进程:crond进程
命令:
crontab -e 进入文件内
crontab -l 查看调度的作业
事例:
每小时的第3和第15分钟执行
3,15 * * * * command
在上午8点到11点的第3和第15分钟执行
3,15 8-11 * * * command
每隔两天的上午8点到11点的第3和第15分钟执行
3,15 8-11 */2 * * command
每个星期一的上午8点到11点的第3和第15分钟执行
3,15 8-11 * * 1 command
每晚的21:30重启smb
30 21 * * * /etc/init.d/smb restart
在命令后面加上& 实现后台运行。
例如:sh test.sh &
使用&命令后,作业被提交到后台运行,当前控制台没有被占用,但是一但把当前控制台关掉(退出帐户时),作业就会停止运行。nohup命令可以在你退出帐户之后继续运行相应的进程。
格式:
nohup command &
2>&1解析
command >out.file 2>&1 &
2>&1 是将标准出错重定向到标准输出,这里的标准输出已经重定向到了out.file文件,即将标准出错也输出到out.file文件中。最后一个&, 是让该命令在后台执行。
一般在shell脚本末尾加上这个,表示成功结束
exit 0
条件测试类型:
整数测试
字符测试
文件测试
1、条件测试的表达式:
[ expression ] 括号两端必须要有空格
[[ expression ]] 括号两端必须要有空格
test expression
组合测试条件:
-a: and
-o: or
!: 非
2、整数比较:
-eq 测试两个整数是否相等
-ne 测试两个整数是否不等
-gt 测试一个数是否大于另一个数
-lt 测试一个数是否小于另一个数
-ge 大于或等于
-le 小于或等于
逻辑与:&&
第一个条件为假 第二个条件不用在判断,最终结果已经有
第一个条件为真,第二个条件必须得判断
逻辑或:||
3、字符串比较
== 等于 两边要有空格
!= 不等
> 大于
< 小于
四、文件测试
-z string 测试指定字符是否为空,空着真,非空为假
-n string 测试指定字符串是否为不空,空为假 非空为真
-e FILE 测试文件是否存在
-f file 测试文件是否为普通文件
-d file 测试指定路径是否为目录
-r file 测试文件对当前用户是否可读
-w file 测试文件对当前用户是否可写
-x file 测试文件对当前用户是都可执行
-z 是否为空 为空则为真
-a 是否不空
在Shell中用if、then、elif、else、fi这几条命令实现分支控制
案例一:
#!/bin/bash
if [ -f /bin/bash ]
then
echo "/bin/bash is a file"
else
echo "/bin/bash is NOT a file"
fi
if :; then echo "always true"; fi
案例二:
#!/bin/bash
echo "Is it morning? Please answer yes or no."
read YES_OR_NO
if [ "$YES_OR_NO" = "yes" ]; then
echo "Good morning!"
elif [ "$YES_OR_NO" = "no" ]; then
echo "Good afternoon!"
else
echo "Sorry, $YES_OR_NO not recognized. Enter yes or no."
exit 1
fi
exit 0
read命令的作用是等待用户输入一行字符串,将该字符串存到一个Shell变量中
#!/bin/bash
echo "Is it morning? Please answer yes or no."
read YES_OR_NO
case "$YES_OR_NO" in
yes|y|Yes|YES)
echo "Good Morning!";;
[nN]*)
echo "Good Afternoon!";;
*)
echo "Sorry, $YES_OR_NO not recognized. Enter yes or no."
exit 1;;
esac
exit 0
#!/bin/bash
s="ruoze,jepson,xingxing,dashu,xiaoshiqi,xiaohai"
OLD_IFS="$IFS"
IFS=","
arr=($s)
IFS="OLD_IFS"
for x in ${arr[*]}
do
echo $x
done
#! /bin/sh
echo "Enter password:"
read TRY
while [ "$TRY" != "secret" ]; do
echo "Sorry, try again"
read TRY
done
break跳出,continue跳过。 continue跳过本次循环,但不会跳出循环
#! /bin/sh
echo "Enter password:"
COUNTER=0
read TRY
while [ "$TRY" != "secret" ]; do
COUNTER=$(($COUNTER+1))
if [ $COUNTER -eq 5 ]
then
echo "Sorry, permission denied"
break
else
echo "Sorry, try again"
read TRY
fi
done
echo "identity varified"
$0 相当于C语言main函数的argv[0]
$1、$2… 这些称为位置参数(Positional Parameter),相当于C语言main函数的argv[1]、argv[2]…
$# 相当于C语言main函数的argc - 1,注意这里的#后面不表示注释
$@ 表示参数列表”$1” “$2” …,例如可以用在for循环中的in后面。
$* 表示参数列表”$1” “$2” …,同上
$? 上一条命令的Exit Status
$$ 当前进程号
#!/bin/bash
echo "File Name: $0"
echo "First Parameter : $1"
echo "First Parameter : $2"
echo "Quoted Values: $@"
echo "Quoted Values: $*"
echo "Total Number of Parameters : $#"
$* 和 $@ 的区别
$* 和 $@ 都表示传递给函数或脚本的所有参数,不被双引号(" ")包含时,
都以"$1" "$2" … "$n" 的形式输出所有参数。
但是当它们被双引号(" ")包含时,"$*" 会将所有的参数作为一个整体,以"$1 $2 … $n"的形式输出所有参数;
"$@" 会将各个参数分开,以"$1" "$2" … "$n" 的形式输出所有参数。
1、函数的定义格式:
[ function ] funname [()]
{
action;
[return int;]
}
说明:
1)、可以带function fun() 定义,也可以直接fun() 定义,不带任何参数。
2)、参数返回,可以显示加:return 返回,如果不加,将以最后一条命令运行结果,作为返回值。 return后跟数值n(0-255)
2、函数调用
案例一:
#!/bin/bash
demoFun(){
echo "这是我的第一个 shell 函数!"
}
echo "-----函数开始执行-----"
demoFun # 函数写在单独的一行
echo "-----函数执行完毕-----"
#!/bin/bash
funWithReturn(){
echo "这个函数会对输入的两个数字进行相加运算..."
echo "输入第一个数字: "
read aNum
echo "输入第二个数字: "
read anotherNum
echo "两个数字分别为 $aNum 和 $anotherNum !"
return $(($aNum+$anotherNum))
}
funWithReturn
echo "输入的两个数字之和为 $? !"