# ShellScript
# Flag
Shell
脚本(shell script
),是一种为Shell
编写的脚本程序。Shell
脚本文件的名称可以任意,但为了避免被误以为是普通文件,建议将.sh
后缀加上,以表示是一个脚本文件。
- https://github.com/topics/bash (opens new window)
- https://github.com/Ph0enixKM/Amber (opens new window)
- 静态分析shell语法规范 https://github.com/koalaman/shellcheck (opens new window)
- https://github.com/ComplianceAsCode/content (opens new window)
- 格式化 https://github.com/mvdan/sh (opens new window)
- rm替代方案 https://github.com/qqAys/trash.sh (opens new window)
- Shell 教程 (opens new window)
- Linux Shell脚本学习指南 (opens new window)
- Shell命令脚本初步认识,Shell脚本入门 (opens new window)
- Shell中if的使用详解_&&与||的使用详解 (opens new window)
- shell-if判断 (opens new window)
- https://github.com/guodongxiaren/Bash (opens new window)
- https://github.com/oldratlee/useful-scripts (opens new window)
- https://github.com/chen-shang/baseshell (opens new window)
在shell脚本中,通常将
EOF
与<<
结合使用,表示后续的输入作为子命令或子Shell的输入,直到遇到EOF
为止,再返回到主Shell。EOF
只是一个分界符,当然也可以用abcde
替换。当shell遇到<<
时,它知道下一个词是一个分界符。在该分界符以后的内容都被当作输入, 直到shell又看到该分界符(位于单独的一行)。此分界符可以是所定义的任何字符串,其实,不一定要用EOF
, 只要是“内容段”中没有出现的字符串,都可以用来替代EOF
,完全可以换成abcde之类的字符串,只是一个起始和结束的标志罢了。
# 自动交互
# 指令有参数
重定向
shell用重定向作为标准输入的用法是:
cmd<<delimiter
shell会将分界符delimiter之后直到下一个同样的分界符之前的内容作为输入
实现ftp自动登录并运行ls指令的用法如下:其中admin为用户名,password为密码
ftp -i -n 192.168.21.46 <<EOF
user admin password
ls
EOF
管道
# sudo的-S参数
echo 'zjk123' | sudo -S cp file1 /etc/hosts
# passwd的-stdin参数
echo 'password' | passwd -stdin username
# 指令无参数
Expect
是由Don Libes
基于Tcl
(Tool Command Language
)的脚本语言,所以你至少要学习一下TCL
它的语法。
- https://www.tcl-lang.org/man (opens new window)
- Tcl教程 (opens new window)
- tclsh expect手册 (opens new window)
- shell编程之expect用法 (opens new window)
- linux expect 自动交互脚本用法 (opens new window)
- expect 脚本使用 (opens new window)
- Expect学习笔记 (opens new window)
启用选项
选项 | 说明 |
---|---|
-c | 执行脚本前先执行的命令,可多次使用。 |
-d | debug模式,可以在运行时输出一些诊断信息,与在脚本开始处使用exp_internal 1相似。 |
-D | 启用交换调式器,可设一整数参数。 |
-f | 从文件读取命令,仅用于使用#!时。如果文件名为"-",则从stdin读取(使用"./-"从文件名为-的文件读取)。 |
-i | 交互式输入命令,使用"exit"或"EOF"退出输入状态。 |
-- | 标示选项结束(如果你需要传递与expect选项相似的参数给脚本时),可放到#!行:#!/usr/bin/expect --。 |
-v | 显示expect版本信息 |
命令
命令 | 说明 |
---|---|
$argc | 参数个数 |
$argv | 接收的所有参数数组 |
$NAME | 使用变量 |
close | 关闭当前进程的连接,-i选项关闭指定句柄的过程 |
debug | 控制调试器 |
disconnect | 断开进程连接(进程仍在后台运行) |
exit | 退出expect |
exp_pid | 获取当前spawn的进程号,-i选项指定spawn进程:setpid [exp_pid –i $spawn_id] |
exp_send | 将参数输出到程序中 |
exp_continue | 当问题不存在时继续回答下边的问题 |
exp_internal | 调试模式,1(打开)、0(关闭)、-f file(将调试内容写入文件),放在spawn后面 |
expect eof | 问题回答完毕等待expect进程结束,expect -timeout -1 eof |
expect -re | 表示匹配正则表达式 |
expect | 从进程接收字符串,expect与{之间没有空格或者TAB间隔,会报invalid command name "expect{" |
expr | 计算 |
interact | 执行完成后保持交互状态,否则退出 |
lindex | 获取参数 |
puts | 向用户终端发送提示信息 |
send_user | 把参数输出到标准输出中 |
send_error | 把参数输出到标准错误输出中 |
send_log | 把内容输出到log记录文件中 |
send | 用于向进程发送字符串 |
set NAME value | 设置变量 |
set timeout -1 | 超时时间,-1为永不超时 |
spawn | expect中的监控程序,其运行会监控命令提出的交互式问题,启动新的进程 |
wait | 等待系统主动返回eof,也就是结束信号后才关闭,wait -nowait |
log_user | 指定输出的位置,默认值是1,表示所有输出都放在标准输出中,为0就表示不需要任何输出 |
log_file | 将输出记录到一个文件中 |
send
命令有几个可用的参数
-i
指定spawn_id
,这个参数用来向不同spawn_id
的进程发送命令,是进行多程序控制的关键参数。
-s
代表slowly
,也就是控制发送的速度,这个参数使用的时候要与expect
中的变量send_slow
相关联
特殊字符
字符 | 说明 |
---|---|
\r | 表示回车 |
\n | 表示换行 |
\t | 表示制表符 |
\ | 需转义 \\\ |
} | 需转义 \} |
[ | 需转义 \[ |
$ | 需转义 \\\$ |
` | 需转义 \` |
" | 需转义 \\\" |
- 方式一
push_url=https://github.com/bajins/bajins.github.io.git
push_username=admin
push_password=admin
# 检索expect是否安装
is_expect=`whereis expect | awk '{print $2}'`
# 如果没有安装
if [ ! -n "$is_expect" ]; then
yum -y install expect > /dev/null 2>&1
fi
expect -c "
# 超时时间-1为永不超时
set timeout -1
# spawn将开启一个新的进程,或者使用:ssh $user@$host {your_command}
# 只有先进入expect环境后才可执行spawn
spawn git push -f ${push_url} master
# 判断运行上述命令的输出结果中是否有指定的字符串(不区分大小写)。
# 若有则立即返回,否则就等待一段时间后返回,等待时长就是开头设置的timeout。
# 同时向上面的进程发送字符串, 并且自动敲Enter健(\r)
expect {
\"*Username*\" {send \"${push_username}\r\"; exp_continue}
\"*Password*\" {send \"${push_password}\r\";}
}
# 问题回答完毕等待expect进程结束
expect eof
"
- 方式二
push_url=https://github.com/bajins/bajins.github.io.git
push_username=admin
push_password=admin
# 检索expect是否安装
is_expect=`whereis expect | awk '{print $2}'`
# 如果没有安装
if [ ! -n "$is_expect" ]; then
yum -y install expect > /dev/null 2>&1
fi
expect <<-EOF
set timeout -1
spawn git push -f ${push_url} master
#expect "*Username*" {send "${push_username}\r"; exp_continue}
#expect "*Password*" {send "${push_password}\r"}
expect {
\"*Username*\" {send \"${push_username}\r\"; exp_continue}
\"*Password*\" {send \"${push_password}\r\";}
}
interact
# 问题回答完毕等待`expect`进程结束
expect eof
# 由于用的-EOF,这里的EOF可以有空格,tab键
EOF
- 方式三
#!/usr/bin/expect
set push_url "https://github.com/bajins/bajins.github.io.git"
set push_username "admin"
set push_password "admin"
# 超时时间-1为永不超时
set timeout -1
# spawn将开启一个新的进程,或者使用:ssh $user@$host {your_command}
# 只有先进入expect环境后才可执行spawn
spawn git push -f ${push_url} master
# 判断运行上述命令的输出结果中是否有指定的字符串(不区分大小写)。
# 若有则立即返回,否则就等待一段时间后返回,等待时长就是开头设置的timeout。
expect "*Username*"
# 向上面的进程发送字符串, 并且自动敲Enter健(\r)
# -- 后面的"之间有一个空格
send -- "$push_username\n"
expect "*Password*"
# -- 后面的"之间有一个空格
send -- "$push_password\n"
# 允许用户交互
interact
# 问题回答完毕等待expect进程结束
expect eof
- 获取日期
expect -c "
set date [ clock format [ clock seconds ] -format "%Y%m%d" ]
set secon [ clock seconds ]
set yestoday_secon 0
#set i [expr {$i + 1}] #expect里的加减法
set yestoday_secon [expr {$secon - 86400} ]
set yestoday [ clock format [ expr {$yestoday_secon} ] -format "%Y%m%d" ]
puts "\n date = $date"
puts "\n secon = $secon"
puts "\n yestoday_secon = $yestoday_secon"
puts "\n yestoday = $yestoday"
# 问题回答完毕等待expect进程结束
expect eof
"
# 清理内存
# 获取到的内存配置信息若为0的话,则表示开启了缓存机制
cat /proc/sys/vm/drop_caches
# drop_caches是让系统清理内存页的缓存,从而得到更多的可用内存
# 释放网页缓存(To free pagecache)
sync; echo 1 > /proc/sys/vm/drop_caches
# 释放目录项和索引(To free dentries and inodes)
sync; echo 2 > /proc/sys/vm/drop_caches
# 释放网页缓存,目录项和索引(To free pagecache, dentries and inodes)
sync; echo 3 > /proc/sys/vm/drop_caches
# 清理/var/cache/yum的headers
yum clean headers
# 清理/var/cache/yum下的软件包
yum clean packages
# 清理软件源
yum clean metadata
# 清理日志
# 清除定时任务记录
sed -i '1,50d' /var/log/cron
# 清除ftp记录
sed -i '1,50d' /var/log/xferlog
# 清除数据库日志
sed -i '1,50' /var/log/mariadb/mariadb.log
# 清除sshd信息
sed -i '1,50d' /var/log/secure
sed -i '1,50d' /var/log/firewalld
sed -i '1,50d' /var/log/httpd/access_log
sed -i '1,50d' /var/log/httpd/ssl_access_log
sed -i '1,50d' /var/log/httpd/ssl_error_log
sed -i '1,50d' /var/log/httpd/ssl_request_log
# 清除系统开机发生的错误
sed -i '1,50d' /var/log/messages
sed -i '1,50d' /var/log/tuned/tuned.log
sed -i '1,50d' /var/log/hawkey.log
sed -i '1,50d' /var/log/yum.log
sed -i '1,50d' /var/log/dnf.log
sed -i '1,50d' /var/log/dnf.rpm.log
sed -i '1,50d' /var/log/ntp.log
sed -i '1,50d' /var/log/audit/audit.log
# 清除历史执行命令
history -cw && rm -rf ~/.bash_history
# 清除系统登录成功的记录
echo > /var/log/wtmp
# 清除系统登录失败的记录
echo > /var/log/btmp
# 清除最近登录信息
echo > /var/log/lastlog
rm -fr /var/log/*
# Linux之间传输文件
#!/bin/bash
# 远程IP
des_ip=192.168.1.1
# 远程端口
des_port=22
# 远程用户
des_user=root
# 远程密码
des_pass=123456
# 远程文件或文件夹路径
des_path=/www/wwwroot/file
# 本地文件或文件夹路径
local_path=/www/wwwroot/file
# 检索expect是否安装
is_expect=`whereis expect | awk '{print $2}'`
# 如果没有安装
if [ ! -n "$is_expect" ]; then
yum -y install expect > /dev/null 2>&1
fi
expect -c "
# 设置拷贝的时间,超时时间-1为永不超时
set timeout -1
# 本地路径在前,远程在后,是从本地上传到远端
# spawn scp -P ${des_port} -p -r ${local_path} ${des_user}@${des_ip}:${des_path}
# 远程在前,本地路径在后,的是从远端下载到本地
spawn scp -P ${des_port} -p -r ${des_user}@${des_ip}:${des_path} ${local_path}
expect {
\"*yes/no*\" {send \"yes\r\"; exp_continue}
\"*password*\" {send \"${des_pass}\r\";}
}
# 问题回答完毕等待expect进程结束
expect eof
"
exit