Shell脚本
Shell 脚本
#!/bin/bash # #!脚本声明
# file # 脚本说明
ls # 功能
pwd
reboot
逻辑判断
[ $USER = root ] && echo "you are admin" || echo "you are user"
# [ ] 逻辑判断,前后均有空格
# && 为 与 运算
# || 为 或 运算
[ `free -m | grep Mem: | awk '{print $4}'` -lt 1024 && echo "buzu" || echo "chongzu"
# 判断空闲内存是否充足
文件测试所用的参数
运算符 | 作用 |
---|---|
-d | 测试文件是否为目录类型 |
-e | 测试文件是否存在 |
-f | 判断是否为一般文件 |
-r | 测试当前用户是否有权限读取 |
-w | 测试当前用户是否有权限写入 |
-x | 测试当前用户是否有权限执行 |
可用的整数比较运算符
操作符 | 作用 |
---|---|
-eq | 是否等于 |
-ne | 是否不等于 |
-gt | 是否大于 |
-lt | 是否小于 |
-le | 是否等于或小于 |
-ge | 是否大于或等于 |
常见的字符串比较运算符
操作符 | 作用 |
---|---|
= | 比较字符串内容是否相同 |
!= | 比较字符串内容是否不同 |
-z | 判断字符串内容是否为空 |
ping
获取ip地址
ping -c 1 linuxcool.com | grep from | cut -d " " -f 4
# -c 几次
# -i 间隔多少秒
vim ping.sh
#!/bin/bash
ping -c 3 -i 0.2 -W 3 $1 >> /dev/null
if [ $? -eq 0 ] ; then
echo "$1 is On-line"
else
echo "$1 is Off-line"
fi
bash ping.sh 163.com
判断成绩
vim test.sh
#!/bin/bash
read -p "Please input your grade:" GRADE
if [ $GRADE -ge 85 ] && [ $GRADE -le 100 ]; then
echo "$GRADE is Great!"
elif [ $GRADE -ge 70 ] && [ $GRADE -lt 85 ]; then
echo "$GRADE is Pass."
else
echo "$GRADE is Fail."
fi
bash test.sh
猜大小
#!/bin/sh
PRICE=$( expr $RANDOM % 1000 )
TIMES=0
while true
do
read -p "Guess a INT number:" INT
let TIMES++
if [ $INT -eq $PRICE ]; then
echo "You are right:$INT"
echo "Guess $TIMES times"
exit 0
elif [ $INT -gt $PRICE ]; then
echo "High"
else
echo "Low"
fi
done
Case
#!/bin/bash
read -p "Enter:" KEY
case $KEY in
[a-z]|[A-Z])
echo "Zimu"
;;
[0-9])
echo "Number"
;;
*)
echo "Error"
esac
一次性任务
at 20:30
systemctl restart httpd
#按Ctrl+D结束编写任务
at -l #查看任务列表
atrim 任务序号 #删除任务
长期任务
crontab -l # 查看任务列表
crontab -e #创建任务
# 分 时 日 月 星期 命令
25 3 * * 1,3,5 /usr/bin/tar -czvf backup.tar.gz /home/wwwroot
# 每周1、3、5,3:25,备份
0 */2 * * 1-5 /usr/bin/rm -rf /tmp/*
# 周一到周五,每隔两个小时,清空/tmp
kvm-arm64
#!/bin/bash
ISOURL=$1
rm -rf /home/sandy/arm64.qcow2
qemu-img create -f qcow2 /home/sandy/arm64.qcow2 20G
virsh undefine arm64 --nvram
install_from_iso_vga_UOS() {
virt-install -n arm64 --memory 2048 --arch aarch64 --vcpus 2 \
--disk /home/sandy/arm64.qcow2,device=disk,bus=virtio \
--os-type=generic \
--boot uefi \
--video vga \
--noautoconsole \
--noreboot \
--cdrom $ISOURL
}
install_from_iso_vga_UOS
写入多行文本到文件
cat >/etc/product-info <<EOF
## cat >>为追加
UOS device Enterprise V20 $(uname -m) $(date +%Y%m%d)
EOF
脚本运行保存为日志
#!/bin/bash
logfile=/var/log/logfile.log
exec >$logfile 2>&1
重定向脚本输出到日志文件并同时显示
logfile=log.log
exec > >(tee $logfile) 2>&1
选择执行
#!/bin/bash
echo ""
echo " 1: ssh 访问 自动构建服务器 "
echo " 2: ssh 访问 UOS ISO存储服务器 "
echo " 3: 浏览器打开 UOS ISO存储服务器 "
echo " 4: 上传UOS ISO镜像到存储服务器"
echo " 5: 打开 虚拟机管理器virt-manager"
echo " 6: ssh 访问 my vps"
echo ""
read -p "Please input the choice:" idx
##定义函数
sync_upload_iso(){
echo "input the iso url: "
read ISOURL
rsync -avz --progress $ISOURL -e ssh root@ip:/data/iso/uos/device/snapshots/
if [[ $ISOURL =~ "iso" ]]; then
# sudo apt install rsync -y
rsync -avz --progress $ISOURL -e ssh root@ip:/data/iso/uos/device/snapshots/
fi
}
#if [[ -z "$idx"]];then
# echo "no choice,exit"
if [[ '1' = "$idx" ]];then
eval "ssh root@ip -t 'cd /data/soft/isobuilder/; bash --login'"
elif [[ '2' = "$idx" ]];then
eval "ssh root@ip -t 'cd /data/iso/uos/; bash --login'"
elif [[ '3' = "$idx" ]];then
eval "xdg-open 'http://ip'"
elif [[ '4' = "$idx" ]];then
eval "sync_upload_iso"
elif [[ '5' = "$idx" ]];then
eval "virt-manager"
elif [[ '6' = "$idx" ]];then
eval "ssh root@ip -p 22"
else
echo "no choice,exit!"
fi
echo ""
info and error
#!/bin/bash
RED_COL="\033[41;1m"
RESET_COL="\033[0m"
function info() {
echo "INFO: $1"
}
function error() {
echo -e "${RED_COL}ERR:${RESET_COL} $1" >&2
}
function halt() {
error "$1"
exit 1
}
info "This message goes to STDOUT"
error "This message goes to STDERR"
halt "This message goes to STDERR, and script will halt"
info "This won't be executed"
变量替换
msg="I like scripting."
new_msg=${msg/scripting/Bash}
echo $new_msg
变量配置方式 | 说明 |
---|---|
${变量#关键词} ${变量##关键词} | 若变量内容从头开始的数据符合『关键词』,则将符合的最短数据删除 若变量内容从头开始的数据符合『关键词』,则将符合的最长数据删除 |
${变量%关键词} ${变量 %% 关键词} | 若变量内容从尾向前的数据符合『关键词』,则将符合的最短数据删除 若变量内容从尾向前的数据符合『关键词』,则将符合的最长数据删除 |
${变量/旧字符串/新字符串} ${变量//旧字符串/新字符串} | 若变量内容符合『旧字符串』则『第一个旧字符串会被新字符串取代』 若变量内容符合『旧字符串』则『全部的旧字符串会被新字符串取代』 |
$ image="library/nginx:1.19"
# 比如要获取镜像的 tag 常用的是 echo 然后 awk/cut 的方式
$ echo ${image} | awk -F ':' '{print $2}' 方式
# 可以直接使用 bash 内置的变量替换功能,截取特定字符串
$ image_name=${image%%:*}
$ image_tag=${image##*:}
$ image_repo=${image%%/*}
脚本中统计函数耗时
reset_global_timer() {
export SEC0=$(date --utc +%s)
}
reset_function_timer(){
export SEC1=$(date --utc +%s)
}
running_time()
{
SEC2=$(date --utc +%s); DIFFSEC=$((${SEC2} - ${SEC1})); printf "\nSection Time: $(date +%H:%M:%S -ud @${DIFFSEC})\n"
SEC2=$(date --utc +%s); DIFFSEC=$((${SEC2} - ${SEC0})); printf "Elapsed Time: $(date +%H:%M:%S -ud @${DIFFSEC})\n\n"
}
reset_global_timer
reset_function_timer
running_time
正确传递数组到函数中
function update() {
declare -a apps_version=("${!1}")
echo "${apps_version[@]}"
}
APPS_VERSION=("aaa" "bbb" "ccc")
update APPS_VERSION[@]
要特别注意的是,使用不当就造成只将数组的第一个数组到函数中
上面是正确的使用方法
bash中检测函数foo是否存在
fn_exists() {
# appended double quote is an ugly trick to make sure we do get a string -- if $1 is not a known command, type does not output anything
[ `type -t $1`"" == 'function' ]
}
if ! fn_exists $FN; then
echo "Hey, $FN does not exist ! Duh."
exit 2
fi
或者
fn_exists() { declare -F "$1" > /dev/null; }
fn_exists foo && echo yes || echo no
trap 脚本错误及退出
trap '>&2 echo Command failed: $(tail -n+$LINENO $(readlink -f $0) | head -n1)' ERR
trap 'rc=$?; echo $rc SIGINT; exit $rc' INT
trap 'rc=$?; echo $rc EXIT; exit $rc' EXIT
严格脚本语法
#bash strict mode
set -euo pipefail
#debug mode
set -x