目录
一、shell的基本组成元素
#!:出现在脚本第一行,用于定义命令解释器
#:除了第一行以外,其他以#开头的行是注释。这些行不被运行,只是给人阅读使用
系统命令:shell脚本中运行解释的系统命令
流量控制语句:判断、循环、跳转等流量控制
二、变量
1、变量的分类
本地变量:在一个用户的shell的生命周期中所有效的变量,可以使用set显示本地变量
环境变量:用于所有用户进程(经常成为子进程),登陆进程称为父进程。shell中运行的用户进程称为子进程,环境变量可以用于所有子进程。可以使用env显示环境变量
HOME 用户的家目录 PS1 第一提示符
PATH 可执行文件搜索路径 PS2 第二提示符
LOGNAME 用户登录名 PWD 当前路径
MAIL 用户的邮箱 SHELL 当前所使用的shell
位置变量:有很多特殊变量是被Shell自动赋值的,比如:
$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" ...,同上
$? 进程运行结束返回值变量$?:运行正确返回0,运行错误返回非0
$$ 进程ID变量$$:可以用来判断程序的当前状态或者对程序做相应的kill操作等等
位置参数可以用shift命令左移。比如shift 3表示原来的$4现在变成$1,原来的$5现在变成$2等等,原来的$1、$2、$3丢弃,$0不用移动。不带参数的shift相当于shift 1。例如:
#!/bin/bash
echo "The program $0 is now running"
echo "The first parameter is $1"
echo "The second parameter is $2"
echo "The parameter list is $@"
shift
echo "The first parameter is $1"
echo "The second parameter is $2"
echo "The parameter list is $@"
# 执行
./test.sh 0 1 2
The program ./test is now running
The first parameter is 0
The second parameter is 1
The parameter list is 0 1 2
The first parameter is 1
The second parameter is 2
The parameter list is 1 2
2、变量的设置
设置变量:VARNAME=VAR_VALUE
设置只读变量:readonly VARNAME=VAR_VALUE
3、变量的引用
echo ${VARNAME}
echo $VARNAME
4、变量的替换
${VARNAME:+VAR}:如果设定了VARNAME,则显示为VAR,否则为空
${VARNAME:?VAR}:如果未设定VARNAME,则显示用户定义错误信息VAR
${VARNAME:-VAR}:如果未设定VARNAME,则显示其值为VAR
${VAENAME:=VAR}:如果未设定VARNAME,则设定其值并显示为VAR
5、变量的清除
unset VARNAME
6、变量的作用域
全局变量:声明全局变量需要使用export,如果其他进程(非子进程)需要调用,则应该使用“.”或“source”调用
export VARNAME=VAR_VALUE
局部变量:函数内变量,如果要使函数内定义的变量只在函数内生效,则要使用local关键字
local kevin=kevin_foo
7、类型变量
有类型的变量:默认bash将变量设置为文本值,当使用算数方法时会自动将其转换为整数值,内置命令declare可以修改变量属性
declare参数
-a 将变量看成数组
-f 只是用函数名
-F 显示未定义的函数名
-i 将变量看成整数
-r 是变量只读
-x 标记变量未通过环境导出
整数变量:bash将$((和))包围的单词解释为算数表达式
常见的算数操作符:
+
-
*
/ 除(取整)
% 取余
<< 左移位
>> 右移位
& 位与
| 位或
~ 位非
! 位非
^ 位异或
常见的关系操作符:
< -lt
> -gt
<= -le
>= -ge
== -eq
!= -ne
&& 逻辑与
|| 逻辑或
8、数组
数组类似于保存取值的一个排列,排列中每个位置成为元素,每个元素通过数字下标访问。数组元素可以包含字符串或数字,数组下标从0开始
9、变量的叠加
三、各种符号
1、文件名替换
这些用于匹配的字符称为通配符(Wildcard),具体如下:
通配符
* 匹配0个或多个任意字符
? 匹配一个任意字符
[若干字符] 匹配方括号中任意一个字符的一次出现
2、命令代换
由'`'反引号括起来的也是一条命令,Shell先执行该命令,然后将输出结果立刻代换到当前命令行中。
3、算数代换
用于算术计算,$(())中的Shell变量取值将转换成整数,同样含义的$[]等价例如:
itcast$ VAR=45
itcast$ echo $(($VAR+3))
$(())中只能用+-*/和()运算符,并且只能做整数运算。 $[base#n],其中base表示进制,n按照base进制解释,后面再有运算数,按十进制解释。
echo $[2#10+11]
echo $[8#10+11]
echo $[10#10+11]
4、转义字符
比如创建一个文件名为“$ $”的文件可以这样:
itcast$ touch \$\ \$
5、单引号
和C语言不一样,Shell脚本中的单引号和双引号一样都是字符串的界定符,而不是字符的界定符。
单引号用于保持引号内所有字符的字面值,即使引号内的 \ 和回车也不例外,但是字符串中不能出现单引号。
itcast$ echo '$SHELL'
$SHELL
itcast$ echo 'ABC\(回车)
> DE'(再按一次回车结束命令)
ABC\
DE
6、双引号
被双引号括住的内容,将被视为单一字串。它防止通配符扩展,但允许变量扩展。
itcast$ DATE=$(date)
itcast$ echo "$DATE"
2021年 01月 07日 星期四 14:44:45 CST
itcast$ echo '$DATE'
$DATE
四、shell的基本语法
1、条件判断语句
if/then/elif/else/fi
if condition
then
statemnets
...
elif condition
then
statements
...
else
statements
...
fi
2、循环语句
for/do/done
for name in list
do
statements that can use $name
...
done
while/do/done while条件为真循环才执行
while condition
do
statemnts
...
done
until until条件为假循环才执行
until command;do
statements
...
done
3、其它流程控制
case/esac 任何pattern实际上都是可以有管道符号分割的几个模块组成,同时可以使用*号作为表达式匹配,可以使用?匹配任意单个
case expression in
pattern 1)
statements;;
pattern 2)
statements;;
...
pattern N)
statements;;
esac
continue 跳到for、while、until循环的下一步,继续执行循环,直到循环结束跳出
break 从for、while、until循环中退出,break[n]可以指定跳出几层循环
shift 参数移位
function 函数可以带参数,比如functname A B,那么函数中的S1=A,$2=B
functname()
{
shell commands
}
test [ 命令test或[可以测试一个条件是否成立,如果测试结果为真,则该命令的Exit Status为0,如果测试结果为假,则命令的Exit Status为1
[ $var -gt 3 ]
五、shell输入和输出
echo:echo显示文本行或变量,或者把字符串输入到文件。
echo [option] string
-e 解析转义字符
-n 不回车换行
管道 | :可以通过管道把一个命令的输出传递给另一个命令做输入。
cat file | more
ls -l | grep "file"
df -k | awk '{print $1}' | grep -v "devtmpfs"
# df -k 查看磁盘空间,找到第一列,去除“devtmpfs”并输出
tee:tee命令把结果输出到标准输出,另一个副本输出到相应文件。
df -k | awk '{print $1}' | grep -v "文件系统" | tee a.txt
tee -a a.txt表示追加操作
df -k | awk '{print $1}' | grep -v "文件系统" | tee -a a.txt
文件重定向
cmd > file 把标准输出重定向到新文件中
cmd >> file 追加
cmd > file 2>&1 标准出错也重定向到1所指向的file里
cmd >> file 2>&1
cmd < file1 > file2 输入输出都定向到文件里
cmd < &fd 把文件描述符fd作为标准输入
cmd > &fd 把文件描述符fd作为标准输出
cmd < &- 关闭标准输入
六、bash高级应用
1、临时文件产生和读写
我们经常需要在脚本运行过程中产生一些临时文件,创建临时文件的命令很多,但不是所有的都是用,比如vi是一个交互式命令,不适合在脚本内部使用。
可以用cat命令:
#!/bin/bash
cat /tmp/file/<<ENDF
welcome
${whoami}
ENDF
# ENDF是一个自定义的结束符,可以自由定义
2、锁文件概念
锁是一种程序与程序之间协同工作的一种机制。
比如程序可以在运行之时创建一个锁文件,当你想知道自己的脚本当前有没有运行,可以判断这个锁文件是否存在。
锁文件分为简单锁文件和复杂锁文件。
简单锁文件:
if [ if "$LOCKFILE" ]
then
echo "script is running." && exit 1
else
touch "$LOCKFILE"
fi
简单锁的问题时,如果脚本一场瑞出,而所文件没有删除,则下次执行脚本会认为自己已经运行,从而不在运行。所以需要使用复杂锁:
if [ -f "$LOCKFILE" ] //假如锁文件存在
then
pid=`cat $LOCKFILE` //查看锁文件中的PID值
[ -n "$pid" ] && ps -p $pid | grep $pid >/dev/null //比较PID是否一致
[ $? = 0 ] && echo "script is running." && exit 1 //PID一致,显示运行信息,并退出脚本
fi
echo $$ > "$LOCKFILE" //如果锁文件不存在,或者存在但PID不一致,则将新的PID写入锁文件
3、输入输出流操作
逐行读取一个文件,并进行一定的操作,我们可以称之为流操作。
#!/bin/bash
while read LINE
do
echo $LINE
sleep 1
done < /etc/hosts
4、bash shell 的调试方法
常见的方法:使用调式参数、使用read设置端点、使用echo查看变量值。
打开调试参数:
set -x bash -x test.sh
关闭调试参数:
set +x bash test.sh
脚本头目定义方式;:
#!/bin/bash -vx
其它:
set -f //禁止特殊字符用于文件扩展名
set -v //打印读入shell的输入行
set -x //执行命令前打印命令