目录
一、免交互
1.Here Document 多行重定向
1.1定义
使用I/O重定向的方式将命令列表提供给交互式程序
Here Document是标准输入的一种替代品,可以帮助脚本开发人员不必使用临时文件来构建输入信息,而是直接就地生产处一个文件并用作命令的标准输入,Here Document可以与非交互式程序和命令一起使用。
1.2语法格式
命令 << 标记
内容
标记
注意事项:
- 标记可以使用任意的合法字符(通用的字符是EOF[End of file])
- 结尾的标记一定要顶格写,前面不能有任何字符(包括空格)
- 结尾的标记后面也不能有任何字符(包括空格)
- 开头标记前后空格会被省略掉
1.3tee命令
1.4cat与tee
cat与tee相差不大
1.5Here Document 变量设定
Here Document也支持使用变量,如果标记之间有变量被使用,会先替换成变量值。如果想要将一些内容写入文件,除了常规的方法外,也可以使用Here Document。如果写入的内容中包含变量,在写入文件时要先将变量替换成实际值,再结合cat命令完成写入。
[root@localhost opt]#vim eof.sh
#!/bin/bash
var="today i will study well"
myvar=$(cat <<EOF
TOday is Therday
$var
this is a good day
EOF
)
echo $myvar
[root@localhost opt]#bash eof.sh
TOday is Therday today i will study well this is a good day
[root@localhost opt]#vim eof.sh
#!/bin/bash
var="today I will study"
myvar=$(cat <<EOF
Today is Friday
$var
this is good day
EOF
)
echo "$myvar"
[root@localhost opt]#bash eof.sh
Today is Friday
today I will study
this is good day
2.Expect
2.1定义
建立在TCL(Tool Command Language)语言基础上的一个工具,常被用于进行自动化控制和测试,解决Shell脚本中交互的相关问题
- 建立在tcl之上的一个工具(需要安装,例yum install expect)
- 用于进行自动化控制和测试
- 解决Shell脚本中交互相关的问题
[root@localhost ~]#yum install expect -y
已加载插件:fastestmirror, langpacks
base | 3.6 kB 00:00
epel/x86_64/metalink | 7.5 kB 00:00
epel | 4.7 kB 00:00
extras | 2.9 kB 00:00
updates | 2.9 kB 00:00
(1/2): epel/x86_64/updateinfo | 1.0 MB 00:01
(2/2): epel/x86_64/primary_db | 7.0 MB 00:01
Loading mirror speeds from cached hostfile
* base: mirrors.ustc.edu.cn
* epel: mirrors.tuna.tsinghua.edu.cn
* extras: mirrors.ustc.edu.cn
* updates: mirrors.ustc.edu.cn
软件包 expect-5.45-14.el7_1.x86_64 已安装并且是最新版本
无须任何处理
[root@localhost ~]#rpm -q expect
expect-5.45-14.el7_1.x86_64
[root@localhost ~]#which expect
/usr/bin/expect
2.2格式
expect [选项] [ -c cmds ] [[ -[f|b] ] cmdfile ] [ args ]
2.3命令详解
1.脚本解释器
- expect脚本中首先引入文件,表明使用的是哪一种shell(#! /usr/bin/expect)
2.spawn
- 启动新的进程(监控、捕捉)
- spawn后面通常跟一个Linux执行命令,表示开启一个会话、进程,并跟踪后续交互信息(spawn passwd root)
3.expect
- 从进程接收字符串
- 判断上次输出结果中是否包含指定的字符串,如果有则立即返回,否则就等待超时时间返回;只能捕捉有spawn启动的进程输出;
- 用于接收命令执行后的输出,然后和期望的字符串匹配
4.send
- 向进程发送字符串,用于模拟用户的输入;该命令不能自动回车换行,一般要加\r(\n)
5.结束符(expect eof)
- 表示交互结束,等待执行结束,退回到原用户,与spawn对应(切换到root用户,expect脚本默认的等待时间是10s,当执行完命令之后,默认停留时间10s后,自动切回原用户)
6.interact
- 允许用户交互expect eof
- 执行完成后保持交互状态,把控制权交给控制台,会停留在目标终端而不是退回到原终端,这时候就可以手工操作了,interact后命令不再起作用,比如interact后添加exit,并不会退出root用户;而如果没有interact则登录完成后会退出,而不是留在远程终端上。
expect eof 与 interact 只能二选一
7.set
- expect默认的超时时间是10秒,通过set命令可以设置会话超时时间,若不限制超时时间,则应设置为-1(set time out 30)
8.exp_continue
- 匹配多个字符串在执行动作后加此命令
- 表示允许expect继续向下执行指令;
- exp_continue附加于某个expect判断选项之后,可以是该项被匹配后还能继续匹配expect判断语句内的其他项。exp_continue类似于控制语句的continue语句,表示允许expect继续向下执行命令
expect { "(yes/no)" {send "yes\n";exp_continue;}
"*password" {set timeout 300;send "abc123\n"}
}
注意:使用exp_continue时,如果跟踪像passwd这样输入密码后就结束进程的命令,expect{}外不要加上expect eof,因为spawn进程结束后会默认向expect发送eof,会导致后面的expect eof执行报错
9.send_user
表示回显命令 与echo相同
10.接收参数(位置变量)
expect脚本可以接收从bash命令行传递参数,使用[lindex $argv n]获得。其中从0开始,分别表示第一个,第二个,第三个......参数
set hostname [lindex $argv 0] 相当于hostname=$1
set password [lindex $argv 1] 相当于passswd=$2
2.4示例
2.4.1交互式
2.4.2远程拷贝文件
2.4.3远程登录
交互式登录
免交互式登录
2.4.4免交互远程批量创建用户
[root@localhost ~]#vim cxk
#!/bin/bash
net=192.168.241
password=123
iplist="
22
23
"
for i in $iplist
do
ip=$net.$i
/usr/bin/expect <<EOF
spawn ssh root@$ip
expect {
"(yes/no)"
{send "yes\r";exp_continue}
"*password"
{send "$password\r"}
}
expect "*]#" { send "useradd test\n" }
expect "*]#" { send "echo 123 |passwd --stdin test\r" }
expect "*]#" { send "exit\r" }
expect eof
EOF
done
[root@localhost ~]#bash cxk
spawn ssh root@192.168.241.22
root@192.168.241.22's password:
Last failed login: Wed Jan 31 03:48:51 EST 2024 from 192.168.241.11 on ssh:notty
There was 1 failed login attempt since the last successful login.
Last login: Wed Jan 31 03:41:56 2024 from 192.168.241.11
[root@node2 ~]#useradd test
useradd:警告:此主目录已经存在。
不从 skel 目录里向其中复制任何文件。
正在创建信箱文件: 文件已存在
[root@node2 ~]#echo 123 |passwd --stdin test
更改用户 test 的密码 。
passwd:所有的身份验证令牌已经成功更新。
[root@node2 ~]#exit
登出
Connection to 192.168.241.22 closed.
spawn ssh root@192.168.241.23
root@192.168.241.23's password:
Last failed login: Thu Feb 1 00:48:57 CST 2024 from 192.168.241.11 on ssh:notty
There was 1 failed login attempt since the last successful login.
Last login: Thu Feb 1 00:48:28 2024 from 192.168.241.1
[root@node3 ~]#useradd test
[root@node3 ~]#echo 123 |passwd --stdin test
更改用户 test 的密码 。
passwd:所有的身份验证令牌已经成功更新。
[root@node3 ~]#exit
登出
Connection to 192.168.241.23 closed.
[root@node2 ~]#id test
uid=1001(test) gid=1001(test) groups=1001(test)
[root@node3 ~]#id test
uid=1001(test) gid=1001(test) 组=1001(test)
二、字符串处理
1.字符串切片
1.1基于偏移量取字符
1.1.1取字符长度
- ${#var} 返回字符串变量var的字符的长度,一个汉字算一个字符
1.1.2跳过指定位置取指定位置数值
1.1.3跳过左边字符
- ${var:offset} 返回字符串变量var中第offset个字符后(不包括第offset个字符)的字符开始,到最后的部分,offset的取值在0到${#var}-1 之间
- ${var:offset:number}返回字符串变量var中从第offset个字符后(不包括第offset个字符)的字符开始,长度为number的部分
1.1.4取字符串右边的字符
- ${var:-length}取字符串的最右侧几个字符,取字符串的最右侧几个字符;
- 注意:冒号后必须有一空白字符
1.1.5掐头去尾
- ${var:offset:-length}从最左侧跳过offset字符,一直向右取到距离最右侧length个字符之前的内容,即掐头去尾
1.1.6取倒数的范围
- ${var:-length:-offset}先从最右侧向左取到length个字符开始,再向右取到距离最右侧offset个字符之间的内容;
- 注意:-length前空格,并且length必须大于offset
[root@localhost ~]#echo ${str}
abcdefghijklmnopqrstuvwxyz
[root@localhost ~]#echo ${str: -4:-3}
#从倒数第4个开始取 取1个
w
[root@localhost ~]#echo ${str: -4:-2}
#从倒数第4个开始取 取2个
wx
[root@localhost ~]#echo ${str: -5:-2}
#从倒数第5个开始取 取3个
vwx
[root@localhost ~]#echo ${str: -5:-3}
#从倒数第5个开始取 取2个
vw
[root@localhost ~]#echo ${str: -6:-3}
#从倒数第6个开始取 取3个
uvw
1.2基于模式取字符串
1.2.1删左留右
- ${var#*word}其中word可以是指定的任意字符,自左向右,查找var变量所存储的字符串中,第一次出现的word,删除字符串开头至第一次出现word字符串(含)之间的所有字符,即懒惰模式
- ${var#*word}其中word可以是指定的任意字符,自左向右,查找var变量所存储的字符串中,最后一个word为界,删除字符串开头的字符向右至最后一次出现word字符串(含)之间的所有字符,即贪婪模式
1.2.2删右留左
- ${var%word*}其中word可以是指定的任意字符,自右向左,查找var变量所存储的字符串中,第一次出现的word,删除字符串最后一个字符向左至第一次出现word字符串(含)之间的所有字符,即为懒惰模式,以从右向左的第一个word为界删右留左
- ${var%word*}其中word可以是指定的任意字符,自右向左,查找var变量所存储的字符串中,第一次出现的word,删除字符串最后一个字符向左至最后一次出现word字符串(含)之间的所有字符,即为懒惰模式,以从右向左的第一个word为界删右留左
2.查找替换删除
2.1查找替换
- ${var/pattern/substr} ${变量/搜索的字符串/修改的字符串}
- #查找var所表示的字符串中,第一次被pattern所匹配到的字符串,以substr替换之
- 懒惰模式
- ${var//pattern/substr}
- 查找var所表示的字符串中,所有能被pattern所匹配到的字符串,以substr替换之
- 贪婪模式
- ${var/#pattern/substr}
- 查找var所表示的字符串中,行首被pattern所匹配到的字符串,以substr替换之(在此处“#”代表开头)
- ${var/%pattern/substr}
- 查找var所表示的字符串中,行尾被pattern所匹配到的字符串,以substr替换之(在此处“%"代表结尾)
2.2查找并删除
- ${var/pattern}
- 删除var表示的字符串中第一次被pattern匹配到的字符串
- 懒惰模式
- ${var//pattern}
- 删除var表示的字符串中所有被pattern匹配到的字符串
- 贪婪模式
- ${var/#pattern}
- 删除var表示的字符串中所有以pattern为行首所匹配到的字符串
- ${var/%pattern}
- 删除var所表示的字符串中所有以pattern为行尾所匹配到的字符串
2.3示例扩展
getent命令会读取文件/etc/hosts中的内容
2.3.1懒惰模式
2.3.2贪婪模式
2.3.3开头更换
2.3.4结尾更换
3.大小写转换
3.1转换大写
- ${var^^}
- 把var中的所有小写字母转换为大写
3.2转换小写
- ${var,,}
- 把var中的所有大写字母转换为小写
三、高级变量
1.高级变量赋值
变量配置方式 | str没有配置 | str为空字符串 | str已配置为费控字符串 |
---|---|---|---|
var=${str-expr} | var=expr | var= | var=$str |
var=${str:-expr} | var=expr | var=expr | var=$str |
var=${str+expr} | var= | var=expr | var=expr |
var=${str:+expr} | var= | var= | var=expr |
var=${str=expr} | str=expr var=expr | str不变 var= | str不变 var=$str |
var=${str:=expr} | str=expr var=expr | str=expr var=expr | str不变 var=$str |
var=${str?expr} | expr 输出至 stderr | var= | var=$str |
var=${str:?expr} | expr 输出至 stderr | expr 输出至 stderr | var=$str |
[root@localhost ~]#unset str
#str没有配置
[root@localhost ~]#var=${str-lucky}
#定义var的变量为str-lucky
[root@localhost ~]#echo $var
#输出var的值为lucky
lucky
[root@localhost ~]#unset str;var=${str-lucky};echo $var
lucky
[root@localhost ~]#str=" ";var=${str-lucky};echo $var
#str变量为空
#var输出变量为空
[root@localhost ~]#str=1;var=${str-lucky};echo $var
#str变量定义为1
#var输出变量为非空字符串 输出str的变量
1
[root@localhost ~]#str=1;var=${str:-lucky};echo $var
#str变量定义为1
#var输出变量为非空字符串 输出str的变量
1
[root@localhost ~]#str=1;var=${str+lucky};echo $var
#str变量定义为1 "+"输出var的定义变量lucky
lucky
[root@localhost ~]#str=1;var=${str:+lucky};echo $var
#str变量定义为1 ":+"输出var的定义变量lucky
lucky
[root@localhost ~]#str=1;var=${str=lucky};echo $var
#str变量定义为1 "="输出str的定义变量1
1
[root@localhost ~]#str=1;var=${str:=lucky};echo $var
#str变量定义为1 ":="输出str的定义变量1
1
[root@localhost ~]#str=1;var=${str?lucky};echo $var
#str变量定义为1 "?"输出str的定义变量1
1
[root@localhost ~]#str=1;var=${str:?lucky};echo $var
1
#str变量定义为1 ":?"输出str的定义变量1
2.变量的间接引用——eval命令引用
eval将首先扫描命令行进行所有的置换,然后再执行该命令。该命令适用于一次扫描无法实现其功能的变量,该命令可以对变量进行两次扫描
四、其他脚本工具
1.创建临时文件mktemp
mktemp命令用于创建并显示临时文件,可以避免冲突
1.1格式
mktemp [option]... [template]
template:filenamexxx,x至少要出现是哪个
1.2选项
选项 | 含义 |
---|---|
-d | 创建临时目录 |
-p DIR或--tmpdir=DIR | 指明临时文件所存放目录位置 |
1.3示例
1.3.1直接使用代表创建临时文件
1.3.2创建随机文件
1.3.3创建随机目录
1.4扩展——垃圾箱
[root@localhost ~]#vim ljx.sh
#!/bin/bash
DIR=`mktemp -d /tmp/trash-$(date +%F_%H-%M-%S)XXXXXX`
mv $* $DIR
echo $* is move to $DIR
function rm () { local trash=`mktemp -d /tmp/trashXXXX`;mv $*
$trash; }
[root@localhost ~]#alias rm=ljx.sh
[root@localhost ~]#cd /opt
[root@localhost opt]#ls
passwd rh test
[root@localhost opt]#rm passwd
bash: ljx.sh: 未找到命令...
[root@localhost opt]#chmod +x ~/ljx.sh
[root@localhost opt]#rm passwd
bash: ljx.sh: 未找到命令...
[root@localhost opt]#cd
[root@localhost ~]#rm /opt/passwd
bash: ljx.sh: 未找到命令...
[root@localhost ~]#alias
alias cp='cp -i'
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias grep='grep --color=auto'
alias l.='ls -d .* --color=auto'
alias ll='ls -l --color=auto'
alias ls='ls --color=auto'
alias mv='mv -i'
alias rm='ljx.sh'
alias scan='echo "- - -" > /sys/class/scsi_host/host0/scan;echo "- - -" > /sys/class/scsi_host/host1/scan;echo "- - -" > /sys/class/scsi_host/host2/scan'
alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'
[root@localhost ~]#alias rm="~/ljx.sh"
[root@localhost ~]#rm /opt/passwd
/opt/passwd is move to /tmp/trash-2024-01-31_19-57-46h6jTVD
[root@localhost ~]#cd /tmp
[root@localhost tmp]#ls
systemd-private-a4556f18442a41648b3f9b5caa837012-chronyd.service-rGR5Ls
systemd-private-a4556f18442a41648b3f9b5caa837012-colord.service-h9U9Wb
systemd-private-a4556f18442a41648b3f9b5caa837012-cups.service-IeH202
systemd-private-a4556f18442a41648b3f9b5caa837012-rtkit-daemon.service-AjhOUA
systemd-private-a4556f18442a41648b3f9b5caa837012-vgauthd.service-anvCIk
systemd-private-a4556f18442a41648b3f9b5caa837012-vmtoolsd.service-9SsjJc
testdirBrl
trash-2024-01-31_19-57-46h6jTVD
定义别名一定要加绝对路径!!!
2.安装复制文件install
install功能相当于cp,chmod,chown,chgrp,mkdir等相关工具的集合(也就是说install可以替代他们执行他们的命令)
2.1格式
- install [OPTION]...[-T] SOURCE DEST 单文件
- install [OPTION]... SOURCE... DIRECTORY
- install [OPTION]...-t DIRECTORY SOURCE...
- install [OPTION]...-d DIRECTORY ...
2.2选项
选项 | 含义 |
---|---|
-m | MODE 默认755 |
-o | OWNER |
-g | GROUP |
-d | DIRNAME 目录 |
[root@localhost opt]#install /etc/passwd -m 700 -o cxk -g cxk .
[root@localhost opt]#ls
passwd rh test
[root@localhost opt]#cat passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
polkitd:x:999:998:User for polkitd:/:/sbin/nologin
abrt:x:173:173::/etc/abrt:/sbin/nologin
libstoragemgmt:x:998:996:daemon account for libstoragemgmt:/var/run/lsm:/sbin/nologin
rpc:x:32:32:Rpcbind Daemon:/var/lib/rpcbind:/sbin/nologin
colord:x:997:995:User for colord:/var/lib/colord:/sbin/nologin
saslauth:x:996:76:Saslauthd user:/run/saslauthd:/sbin/nologin
rtkit:x:172:172:RealtimeKit:/proc:/sbin/nologin
pulse:x:171:171:PulseAudio System Daemon:/var/run/pulse:/sbin/nologin
chrony:x:995:991::/var/lib/chrony:/sbin/nologin
rpcuser:x:29:29:RPC Service User:/var/lib/nfs:/sbin/nologin
nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin
ntp:x:38:38::/etc/ntp:/sbin/nologin
tss:x:59:59:Account used by the trousers package to sandbox the tcsd daemon:/dev/null:/sbin/nologin
usbmuxd:x:113:113:usbmuxd user:/:/sbin/nologin
geoclue:x:994:989:User for geoclue:/var/lib/geoclue:/sbin/nologin
qemu:x:107:107:qemu user:/:/sbin/nologin
radvd:x:75:75:radvd user:/:/sbin/nologin
setroubleshoot:x:993:988::/var/lib/setroubleshoot:/sbin/nologin
sssd:x:992:987:User for sssd:/:/sbin/nologin
gdm:x:42:42::/var/lib/gdm:/sbin/nologin
gnome-initial-setup:x:991:986::/run/gnome-initial-setup/:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
avahi:x:70:70:Avahi mDNS/DNS-SD Stack:/var/run/avahi-daemon:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
tcpdump:x:72:72::/:/sbin/nologin
ghd:x:1000:1000:ghd:/home/ghd:/bin/bash
cxk:x:1001:1001::/home/cxk:/bin/bash
[root@localhost opt]#ll passwd
-rwx------ 1 cxk cxk 2138 1月 31 20:11 passwd
[root@localhost opt]#install -d wyb -m 666
[root@localhost opt]#ls
passwd rh test wyb
[root@localhost opt]#ll wyb
总用量 0
[root@localhost opt]#ll
总用量 4
-rw------- 1 cxk cxk 2138 1月 31 20:11 passwd
drwxr-xr-x. 2 root root 6 12月 24 11:43 rh
-rw-r--r-- 1 root root 0 1月 31 19:55 test
drw-rw-rw- 2 root root 6 1月 31 20:14 wyb
3.扩展——生成随机六位数密码
[root@localhost opt]#cat /dev/random|tr -dc "[0-9a-zA-Z]"|tr -d "[ ]"|head -c6
SPdRQl
[root@localhost opt]#cat /dev/random|tr -dc "[0-9a-zA-Z]"|tr -d "[ ]"|h6ad -c6
zCy0ev
[root@localhost opt]#cat /dev/random|tr -dc "[0-9a-zA-Z]"|tr -d "[ ]"|h6ad -c6
f38QpE
[root@localhost opt]#cat /dev/random|tr -dc "[0-9a-zA-Z]"|tr -d "[ ]"|h6ad -c6
8yjVM3
[root@localhost opt]#cat /dev/random|tr -dc "[0-9a-zA-Z]"|tr -d "[ ]"|h6ad -c6
4GwN38
[root@localhost opt]#cat /dev/random|tr -dc "[0-9a-zA-Z]"|tr -d "[ ]"|h6ad -c6
a4ERRf
[root@localhost opt]#cat /dev/random|tr -dc "[0-9a-zA-Z]"|tr -d "[ ]"|h6ad -c6
eD3Mym
[root@localhost opt]#cat /dev/random|tr -dc "[0-9a-zA-Z]"|tr -d "[ ]"|h6ad -c6
3yJQdp
[root@localhost opt]#cat /dev/random|tr -dc "[0-9a-zA-Z]"|tr -d "[ ]"|h6ad -c6
OavoBw