Shell高级进阶
条件选择if语句,可实现条件性判断
if语法:if commands;then commands(如果命令为真,将执行后续命令,fi结尾;)
elif commands;then commands(如果前面if不为真,则判断elif是否为真,为真则执行后面的命令,可以写多个elif,可写可不写,条件多的情况下添加)
else commands;then commands(如果上述全都不为真,则继续判断else是否为真,为真则执行后续命令)
if true;then echo true;f1(如果true为真,则执行后续命令,结束)
条件判断;case
case 变量 in
case语法:case word in [模式 [|模式 commands]...
case "变量" in
PAT1) (判断变量是否匹配PAT1,匹配的话则执行以下命令)
分支1
;;
PAT2) (如果前面变量不匹配就执行以下命令)
分支2
;;
...
*) (如果变量前面都不匹配就匹配这个)
默认分支
;;
esac
使用的global风格语法,通配符
*: 任意长度任意字符
?: 任意单个字符
[]:指定范围内的任意单个字符
a|b: a或b
循环
将某代码段重复运行多次
重复运行多少次:
循环次数已知
循环次数未知
有进入条件和退出条件
for,while,until
for循环
for 变量名 in [word ....];do commadns; done
例子:
for num in 1 2 3 4
do
echo "num is $num"
done
上述数字内容写几个单词就循环几次
列表生成方法:
(1)直接给出列表
(2){}从起始到结束;比如:{1..10}(1-10);{1..10..2}递减2
(3)用命令生成列表
(4)使用glob,如:*.sh
(5)变量引用:$@,$*
while循环
while commands(进入循环和终止循环的条件);do commands;done(当什么时候条件满足继续循环,当条件不满足将停止循环)
select循环与菜单
select 变量 in list (将列表数据分别赋予变量并且赋予序号,适用于菜单,PS3这个变量是专用于select做提示符使用的,$REPLY系统自带的变量,存输入的字符串)
do
循环体命令
done
信号捕捉trap
trap '触发指令' 参数
当捕获到参数的操作的信号的时候将触发前面的指令
trap '' 参数
忽略信号
trap '-' 参数
恢复原信号的操作,也就是将上面的trap操作取消
trap -p
列出自定义操作
函数介绍
更加方便代码重用,也适用于模块化编程,相当于别名,别名是一条命令定义,而函数就相当于一个函数定义多条指令
定义函数
函数由两部分组成:函数名和函数体
语法一:
f_name (){
...函数体...
}
语法二:
function f_name {
...函数体...
}
语法三:
function f_name () {
...函数体...
}
f_name 执行函数
unset f_name 取消函数定义
定义的函数在哪个终端就得在哪个终端执行,别的终端无法执行
declare -f(查看定义的所有函数)
函数使用(先定义再调用)
函数一般不会在交互式环境中使用,基本都在脚本中使用
可将定义的函数单独放在一个文件中,脚本中调用函数文件的方法 source '文件名称'
/etc/init.d/function(系统专门存放函数的文件)
return 10(结束当前函数,并且$?返回值为10,并不代表结束)
local是一个特殊的关键字,只能在函数中使用;函数中如果不使用local的话,则函数中定义的变量,shell中可以使用,shell中定义的变量,函数中也可以调用,使用local的话则是只在函数中使用
子进程不能调用父进程中定义的函数,但可以使用export -f f_name将函数转换为环境函数
数组
将同一类型的数据取一个变量名字,数组的名称和数组的下标组合起来就能代表变量的唯一,从0表示第一个下标,最后一个下标的元素个数就为n-1,数字下标则成为数值索引
索引可支持自定义索引,而不止是数值索引,即为关联索引,bash4.0之后支持(bash --version)
bash的数组支持稀疏格式(索引不连续)
声明数组:
declare -a "数组名称"
declare -A "数组名称"(关联数组;自定义索引的为关联数组,先声明再调用)
数组赋值
(1)一次只赋值一个元素
"数组名称[索引]"="值"
(2)一次赋值全部元素
ARRAY_NAME=("VAL1" "VAL2" "VAL3")
(3)只赋值特定元素
ARRATY_NAME=([0]="VAL1" [3]="VAL2")稀疏格式的时候不能以这种方法补全
(4)交互式赋值
read -a
引用数组
echo ${ARRAY_NAME[INDEX]}显示某个特定的数组中的索引
引用数组所有元素
echo ${ARRAY_NAME[*]}显示所有数组索引
数组的长度(数组中元素的个数)
${#ARRAY_NAME[*]}
${#ARRAY_NAME[@]}
删除数组中指定元素
unset 数组[数字]
删除整个数组中的元素
unset 数组
数组数据处理
引用数组中的元素:
数组切片:${ARRAY[@]:offset:number}
offset:要跳过的元素个数
number:要取出的元素个数
取偏移量之后的元素
${ARRAY[@]:offset}
向数组中追加元素:
ARRAY[${#ARRAY[*]}]=value
字符串切片
${#变量名}:返回字符串变量名的长度
${变量名:offset}:跳过offset
${变量名:offset:number}:跳过offset取number个
${变量名: -offset}:取倒数三个
${变量名:offset:-number}:去掉前面offset个,也去掉后number个
${变量名: -offset:-number}:取后面offset个,取出的offset中去掉number个,在7里面用
字符串处理
基于模式取字串
${变量名#*word}:其中word可以使指定的任意字符
功能:从左往右,查找"变量名"所存储的变量值,匹配到后将匹配到的字符以及匹配到的字符前面的字符全部删除,问号代表一个 单独字符;
${变量名##*word}:同上,贪婪模式,删除的是字符串开头到最后一次由word指定的字符之间的所有内容
${变量名%word*}:从右向左,查找变量所存储的字符串中,第一次出现的word,删除从右向左发现的第一个匹配的word以及word右面的所有字符
${变量名%%wird*}:从右向左,贪婪模式,删除的是字符串开头到最后一次由word指定的字符之间的所有内要
查找替换
${变量/匹配的字符串/新替代的字符串}:查找变量所表示的字符串中,匹配的字符串替换为新替代的字符串,默认只替代第一次匹配到的
${变量//匹配的字符串/新替代的字符串}:贪婪模式,替换所有匹配到的字符串
${变量//#匹配的字符串/新替代的字符串}:替换以匹配的字符串开头的行
${变量/%匹配的字符串/新替代的字符串}:替换以匹配的字符串结尾的行
${变量/匹配的字符串}:删除匹配的字符串,非贪婪模式
${变量//匹配的字符串}:贪婪模式,删除所有匹配的字符串
${变量/#匹配的字符串}:删除以匹配的字符串开头的字符串
${变量/%匹配的字符串}:删除以匹配的字符串结尾的字符串
${变量^^}:将变量的值转换为大写
${变量,,}:将变量的值转换为小写
var=${str-"expr"};当str没有值的时候:var=expr;当str值为空的时候:var=$str;当str有值的时候:var=$str
var=${str:-expr};当str没有值的时候:var=expr;当str值为空的时候:var=expr;当str有值的时候:var=$str
........
高级变量用法-有类型变量
Shell变量一般是无类型的,但是bash shell提供了declare用于指定变量类型,bash中只支持整数
declare [选项] 变量名
-r 声明或显示只读变量
-i 声明整数
-a 将变量定义为数组
-A 将变量定义为关联数组
-f 显示已定义的函数内容
-F 显示已定义的所有的函数名
-x 声明环境变量和函数
-l 声明变量为小写字母
-u 声明变量为大写字符
eval命令
eval命令会将命令进行两次扫描,在第一次扫描的时候,查看目标是否为变量,有值的话则会置换,第二次扫描则执行
间接变量引用
如果第一个变量的值是第二个变量的名字,从第一个变量引用第二个变量的值就称为间接变量引用
variable1的值是variable2,而variable2又是变量名,variable2的值为value,间接变量引用是指通过variable1获得变量值value的行为
variable1=variable2
variable2=value
mktemp:创建临时文件,并且显示
mktemp [OPTION]... [TEMPLATE]
TEMPLATE:filenameXXX
X至少要出现三个
OPTION:
-d:创建临时目录
-p:指明临时文件所存放目录位置
安装复制文件
install命令:
install [option] 源文件 目标文件
install [option] 源 目标
install [option]
选项option:
-m MODE,默认权限755
-o OWNER:指定属主
-g GROUP:指定属组
-d 指定目录
expect介绍
主要应用于自动化交互式操作的场景,将交互式的操作改为非交互式的操作
expect语法:
expect [选项] [-c command] [[ -[f|b] ] cmdfile ] [ args ]
选项:
-c:从命令行执行expect脚本,默认expect是交互执行的
-d:可以输出调试信息
expect中相关命令
spawn:启动新的进程
send:用于向进程发送字符串
expect:从进程接收字符串
interact:允许用户交互
exp_continue 匹配多个字符串在执行动作后加此命令
expect最常用的语法(模式-动作)
单分支:expect "hi" {send "You said hi\n"}(捕获hi,而输入别的没有反应)
多分支
expect "hi" { send "You said hi\n" } \ (发现hi打印You said hi)
"hehe" { send "Hehe yourself\n" } \ (发现hehe打印Hehe yourself)
"bye" { send "Good bye\n" }(发现bye打印Good bye)
一:
#!/usr/bin/expect
spawn scp /etc/fstab 用户@对方IP地址:/app
expect {
"yes/no" { send "yes\n";exp_continue }
"password" { send "fang\n" }
}
expect eof
二:
#!/usr/bin/expect
spawn ssh 用户@对方IP地址
expect {
"yes/no" { send "yes\n";exp_continue }
"password" { send "用户密码\n" }
}
expect eof
interact(执行完上述命令不退出执行交互式命令)
三:
#!/usr/bin/expect
set ip "IP地址"(定义名为ip的变量,值为后方ip地址)
set user "用户名" (定义名为user的变量,值为root)
set password "密码"
set timeout 10
spawn ssh $user@$ip
expect {
"yes/no" { send "yes\n";exp_continue }
"password" { send "$password\n" }
}
interact
四
#!/usr/bin/expect
set ip [lindex $argv 0](定义名为ip的变量,值为第一个参数)
set user [lindex $argv 1] (定义名为user的变量,值为第二个参数)
set password [lindex $argv 2] (定义名为password的变量,值为第三个参数)
spawn ssh $user@$ip
expect {
"yes/no" { send "yes\n";exp_continue }
"password" { send "$password\n" }
}
interact
五:Bash中调用expect
#!/usr/bin/expect
#!/bin/bash
ip=$1
user=$2
password=$3
expect <
set timeout 10
spawn ssh $user@$ip
expect {
"yes/no" { send "yes\n";exp_continue }
"password" { send "$password\n" }
}
expect "]#" { send "useradd hehe\n" }
expect "]#" { send "echo magedu |passwd --stdin hehe\n" }
expect "]#" { send "exit\n" }
expect eof
EOF