Linux04 Shell编程一
认识Shell脚本
概念
- Shell脚本是包含一系列命令的文本文件。
- Shell读取此文件并执行命令。
- 翻译命令环境的位置:
/bin/bash
(Bash解释器的位置) |/bin/sh
(Shell解释器的位置)。
应用场景
- 重复性操作。
- 批量事务处理。
- 自动化运维。
- 定时任务执行。
示例
- 在多台服务器上定期备份文件(1+4)。
- 编写脚本扫描某个目录中的文件并进行特定操作(2)。
- 编写脚本来自动监测服务器性能、清理临时文件、更新软件包、管理用户账户等(3)。
如何实现个性化安装?
- 先构建一个安装的脚本
install.sh
。 install.sh
指定的虚拟机名称(如果没有指定虚拟机则对全部虚拟机执行)。
vim
安装
yum -y install vim-enhanced.x86_64
将缩进设置为4位
vim /etc/vimrc
:set tabstop=4
:set softtabstop=4
:set shiftwidth=4
编写脚本
#!/bin/bash # #!用于告诉系统脚本需要什么解释器来执行
echo "Hello world"
运行Shell脚本
同步与异步的区别
- 异步指程序的执行不按照严格的顺序,通常用于多任务处理。此处适用于在后台运行的长时间任务。
- 同步指程序的执行需按照严格的顺序,此处适用于影响当前环境的配置任务。
异步执行
/bin/sh test.sh
/bin/bash test.sh
./test.sh # 在test.sh先在第一行写!/bin/bash + chmod u+x test.sh
- 当频繁执行一个脚本时,授予其执行权限并用./执行。
同步执行
source test.sh # 在当前bash环境下执行,不需要授权
变量
定义变量
varA=Hello
|"Hello"
- 判断值是否需要使用
""
括起来:- 简单值或数字时不需要:
varA=Hello varB=42
- 值包含空格或特殊字符,变量替换时需要:
varA="Hello World"
varA="$varB"
- 简单值或数字时不需要:
- 不需要声明变量,等号前后不能有空格,变量用完之后需要撤销变量。
- 变量的命名按照驼峰原则。
撤销变量
unset varA
将命令结果分配给变量
varA=`ls -l`
变量拼接
echo "info : $a"
${}
$
表示提取。{}
用来锁定变量名边界,若边界无需锁定可缺省。${MYTEST}
直接使用环境变量。
作用域
- 全局变量:当前的整个Shell会话中有效。
- 局部变量:只能在函数内部使用。
- 环境变量:可以在其它Shell中使用。如系统级:
$PATH
,用户级:$JAVA_HOME
。
类别
- 系统变量
- 自定义变量
输出Java的环境变量
echo $PATH | awk '{split($0,a,":"); for(i in a){if(match(a[i],"jdk")) print(a[i])}}'
位置变量$n
$0
用于获取当前脚本文件名称。$1~$9
获取第1输入参数到第9输入参数。${10}
获取第10输入参数。
预定义变量
$#
命令行参数或位置参数的数量。如./test.sh arg1 arg2 arg3 => test.sh内 echo $# => 3
。$?
最近一次执行的命令或shell脚本的返回值(0表示没有错误,其他任何值表明有错误 不写默认为0)。$*|$@
表示所有的位置参数。- `$$` 变量是shell脚本里面的进程ID。 ```bash # var_test.sh # 参数数量 argCount=$# # 所有变量 allArgs=$* # 当前脚本执行时进程号 proNo=$$
序(编)号参数
if [ "$1" ];then
echo -e "INFO : ${argCount}\t$proNo"
echo "ARGS : $allArgs"
exit 0
else
exit 1
fi
### read读取控制台输入
```bash
read [选项][参数]
-p 后面跟提示信息,即在输入前打印提示信息
-t 后面跟秒数,定义输入字符的等待时间
read -t 30 -p "Please enter your name in 30 seconds:" NAME
echo $NAME
表示用户在30秒内需要输入名字,名字会存储在NAME变量中,并会将他们的名字打印。
Shell算术表达式和算术运算符
表达式
let c=a+b
c=$[a+b]
c=$((a+b))
特殊:c=$[(1+3)/(2+3)]
✔ let c = (1+3)/(2+3)
❌
②
和③
都不存在以上的let错误。
如果a='5'
, b=2
, let c=a+b
之后c
的结果为7。
如果c="$a+$b"
,实现了字符串拼接。
运算符
+ - * / % = == !=
+= -=( let ++a|((++a))|((a=a+1)) )
Shell条件表达式
[ 条件表达式 ]
如[ $a == 5 ]
三个以上逻辑表达式会报警告。- 条件成立时,返回true,否则返回false。
=~
通常用于正则匹配,[]
不可用,[[]]
可用。- 示例:判断压缩包的后缀名
if [[ !"$pack" =~ ^.*jdk.*(tar\.gz|tgz)$ ]]; then
Shell关系运算符
关系运算符只支持数字,返回true或false。
-eq
equal to-ne
not equal to-gt
greater than-lt
less than-le
less than or equal to-gt
greater than-ge
greater than or equal to
示例:[ -1 -eq 1 ] => false
Shell逻辑运算符
&&
||
用于[]
外或[[ ]]
内-a
-o
用于[]
内- 示例:
[1 -eq 2 -a 2 -gt 1]
[[1 -eq 2 && 2 -lt 3]]
或者[1 -eq 2] && [2 -lt 3]
Shell字符串运算符
==
!=
-n
: 不为空时为真-z
: 为空时为真
Shell文件操作符
-d
判断是否为目录-e
判断目录或文件是否存在-f
判断是否为文件-r
-w
-x
判断读写执行权限是否存在
Shell三元运算符语法
- 逻辑表达式
&& echo yes || echo no
=> 返回true则输出yes,返回false则输出no
流程控制 - if判断
if [ command ];then
# 符合该条件执行的语句
elif [ command ];then
# 符合该条件执行的语句
else
# 符合该条件执行的语句
fi
流程控制 - case
case多分支条件判断
- 模式匹配
[A-Z]
一个大写字母[a-z]
一个小写字母[0-9]
一个数字?
一个任意字符*
一个任意字符串
- 注意:大小写分开识别,必须大写在前,小写在后,否则统一识别为小写。
case $1 in
"1")
echo "你输入的数字是1"
;;
"2")
echo "你输入的数字是2"
;;
*)
echo "你输入的数字是其他"
;;
esac
循环语句 - for循环
for 变量 in 值1 值2 值3 ... | 字符串 | {
1..100(..2)} # (步长为2)从1到100
do
...
done
示例:
for arg in "$@"
do
echo "arg : $arg"
done
STRING = "Hello world henry"
for var in $STRING
do
echo "var:$var"
done
for((初始值;循环控制条件;变量变化))
do
...
done
示例:
for((i=1;i<=10;i++))
do
echo $[$i*3+1]
done
循环语句 - while循环
while [ 条件表达式 ]
do
...
done
continue
break
同Java
示例:
i=1
sum=0
while [ $i -le 10 ]
do
sum=`$[sum+i]`
((++i))
done
echo "sum=$sum,i=$i"
补充
seq
用于生成从一个数到另一个数之间的所有整数。- 示例:
seq 1 5
或seq 5
生成数字1到5。
数据类型
字符串
henry
不支持有空格的情况varA=henry
''
只输出原文,不输出变量varA='henry pola'
""
输出原文和变量varB="steven $varA"
- ````输出命令执行的结果
布尔
[ true ] && echo yes || echo no
该命令用于判断条件表达式结果为真or假- 逻辑短路:
&&
只有在前一个值为真值的时候,才会执行后一个命令;||
只有在前一个值返回假值的时候,才会执行后一个命令。
练习
打印九九乘法表
for循环
for i in { 1..9} do for j in `seq $i` do echo -en "$[j]*$[i]=$[i*j]\t" done echo done
while循环
i=1 while [ $i -le 9 ] do j=1 while [ $j -le $i ] do echo -n -e "$i*$j=$[i*j]\t" let j++ done let i++ echo " " done
后台运行Shell脚本
- 对守护进程而言,只需在后面加上
&
就能使其在后台自动运行。但对于非守护进程而言,则需要加上nohup
命令使其能够在后台运行。 让程序后台运行
nohup /root/test.sh &
让程序后台运行,并存储运行输出到指定文件
nohup COMMAND | SHELL_SCRIPT > out.file 2>&1 &
Shell exit命令
exit
用来退出当前Shell进程,并返回一个退出状态。exit
命令可以接受一个整数值作为参数,代表退出状态;如果不指定,默认状态值是 0exit
退出状态只能是一个介于 0~255 之间的整数(可以通过指定状态区分不同类型的错误),其中只有 0 表示成功,其它值都表示失败echo $?
输出退出状态
Shell RANDOM变量
- shell有一个环境变量
RANDOM
,范围是0--32767 产生0-25范围的数:
$[RANDOM%26]产生1-68范围的数:
$[RANDOM%68+1]
编写shell 脚本
- 要求统计
/var/log
目录下有多少个文件,并显示这些文件名
Shell数组
- 数组中可存放多个值,初始化时不需要定义数组大小
- 数组元素的下标由0开始
Shell 数组用括号来表示,元素用"空格"符号分割开来
ARRAY_NAME=(VALUE1 ... VALUEN)获取数组元素
${MY_ARRAY[0]}获取数组中所有数组元素
${MY_ARRAY[@]}
Shell函数
- 函数定义
①function fun()
②fun()
小括号不带任何参数
函数调用
FUNC_NAME ARG1 ARG2...
- Shell并不指明定义与调用的顺序。
- 返回值:为0-255之间的证书,可以显式加
return
返回,缺省默认为0,等同于exit
- 返回值扩展:通过
var=\
func args...`将函数内所有输出内容存到变量
var` - 一个function最多只能有一个
return
- 例:设计一个计算所有参数总和的函数
function getsum(){ local sum=0 for n in $@ do ((sum+=n)) done return $sum } getsum 10 20 55 15 #调用函数并传递参数 echo $?
TMOUT
超时设定
TMOUT=5
# 设置用户输入的超时限制为5秒read -p "请输入数值:" num
# 显示提示并等待用户输入- 如果用户输入成功,显示输入的数值
if [ $? -eq 0 ];then echo "你输入的数值为: $num" else echo "输入超时:5秒" fi
ping
发送网络请求 -c [数量]
表示发送对应数量的请求-W [时间长度]
表示指定了等待主机响应的最长时间- 例:
ping -c 1 -W 1 &>/dev/null