目录
一、什么是Shell脚本
二、变量与运算
三、逻辑判断
四、循环
五、函数
六、中断与继续
在前面学习了Linux的基本指令,而shell脚本其实就是是这些命令的集合。
那么为什么需要shell脚本呢?
因为可以用来实现一些复杂的操作,如下:
(1) 进入/tmp/目录;
(2) 列出当前目录中所有的文件名;
(3) 把所有当前的文件复制到/root/目录下;
(4) 删除当前目录下所有的文件。
对于每一个操作,熟悉Linux指令的都知道并不难,但是要完成这些操作就需要四次回车。而通过创建shell脚本文件就可以一次性执行上述所有操作。
接下来将通过实际案例进行教学实现第一个shell脚本
1.cd /usr/local/sbin/ //这里是建议脚本存放目录
2.vim first.sh //建议使用 vim编辑器,输入下面内容(注意:需要root权限)
shell脚本通常都以.sh为后缀名
#! /bin/bash
#This is my first shell script.
#Writen by author 2023-11-21.
date
echo "Hello world!"
注意:
第1行要以#! /bin/bash开头,表示该文件使用的是bash语法。不设置也可以执行,但是不符合规范
#表示注释,后面跟一些该脚本的相关注释内容,以及作者、创建日期或者版本等。不要省略,养成习惯。
运行:有两种方式运行bash文件,一种是sh + 文件名 或者 bash + 文件名
变量的定义:
定义变量的格式:
变量名=变量的值
在脚本中引用变量时需要加上符号$
变量的简单计算案例
#! /bin/bash
# For get the sum of two numbers.
# author 2023-11-21.
a=1
b=2
sum=$((a+b))
echo "$a+$b=$sum"
注意:变量的计算需要使用双括号括起来(( )),并且在前面加上$符号
注意:使用shell脚本语言,变量赋值时候不能有空格!
练习1: 写一个脚本,输入A与B计算,输出A+B的值。
#!/bin/bash
read -p "please input x:" x
read -p "please input y:" y
sum=$((x + y))
echo "the sum is $sum"
练习 2:输出参数与文件本身
#! /bin/bash
echo "$0 $1 $2"
注意:$0是文件本身名称的意思
if判断格式
if((判断条件)); then
符合对应的条件执行该代码
elif((判断条件));then[可省略]
符合对应的条件执行该代码
else[可省略]
符合对应的条件执行该代码
fi
案例:通过输入分数,判断是否及格
#! /bin/bash
read -p "please input your score:" score
if(($score<60));then
echo "you didn't pass the exam"
else
echo "good!"
fi
通过逻辑符号实现判断分数的高低
&&
:表示逻辑与(AND)。在Shell脚本中,command1 && command2
的意思是,如果command1
执行成功(返回退出状态码为0),则执行command2
。||
:表示逻辑或(OR)。在Shell脚本中,command1 || command2
的意思是,如果command1
执行失败(返回退出状态码非0),则执行command2
。练习案例:通过输入分数,判断是高分,及格分,低分。三种情况
#!/bin/bash
read -p "please input your score:" score
if (($score < 60)); then
echo "your score is low"
elif (($score >= 60 && $score < 85)); then
echo "your score is mid"
elif (($score >= 85 && $score <= 100)); then
echo "nice! your score is high"
else
echo "your score is invalid"
fi
通过比较运算符判断
在Shell中,常用的比较运算符有:
-eq
:等于(equal to),例如if [ $a -eq 5 ]
。-ne
:不等于(not equal to),例如if [ $a -ne 5 ]
。-lt
:小于(less than),例如if [ $a -lt 5 ]
。-le
:小于或等于(less than or equal to),例如if [ $a -le 5 ]
。-gt
:大于(greater than),例如if [ $a -gt 5 ]
。-ge
:大于或等于(greater than or equal to),例如if [ $a -ge 5 ]
格式[ $变量 -比较符 ];then
通过比较符简化上述案例:
#!/bin/bash
read -p "please input your score:" score
if [ $score -lt 60 ]; then
echo "your score is low"
elif [ $score -ge 60 -a $score -lt 85 ]; then
echo "your score is mid"
elif [ $score -le 100 -a $score -ge 85 ]; then
echo "nice! your score is high"
else
echo "your score is invalid"
fi
注意: 在Shell中,方括号
[ ]
是用于条件测试的一种方法,但是它需要在每个条件表达式周围添加空格,并且对于多个条件的连接需要使用逻辑运算符-a
。
练习案例:请你根据比较运算符判断下面shell脚本运行的结果
1.a=10; if [ $a -lt 5 ]; then echo ok; fi
2.a=10; if [ $a -gt 5 ]; then echo ok; fi
3.a=10; if [ $a -ge 10 ]; then echo ok; fi
4.a=10; if [ $a -eq 10 ]; then echo ok; fi
5.a=10; if [ $a -ne 10 ]; then echo ok; fi
6.a=10; if [ $a -lt 1 ] || [ $a -gt 5 ]; then echo ok; fi
7.a=10; if [ $a -gt 1 ] || [ $a -lt 10 ]; then echo ok; fi
特殊判断
if [ -d /home/ ]; then echo ok; fi //-d:判断是不是目录以及是否存在。
if [ -f /home/ ]; then echo ok; fi //-f:判断是不是普通文件以及是否存在。
if [ -x /root/test.txt ]; then echo ok; fi
//-r:判断是否有读权限。
//-w:判断是否有写权限。
//-x:判断是否可执行。
通过case判断
case格式:
case $变量 in
对应变量) 条件
;;
esac
案例:通过输入一个数,判断是奇数还是偶数。
#! /bin/bash
read -p "please input a number:" n
a=$(($n%2))
case $a in
1) echo "this is odd"
;;
0) echo "this is even"
;;
*) echo "your input is invali"
;;
esac
for循环格式:
for 变量 in 集合;
do
符合的条件
done
案例:循环输出1至5
#! /bin/bash
for i in 1 a s c x;
do
echo $i
done
#! /bin/bash
for file in $(ls);
do
echo $file
done
通过$(指令),设置需要遍历的指令结果。
while循环格式:
while ((条件));
do
符合条件指令
done
案例:循环输出递减。
#! /bin/bash
a=5
while [ $a -ge 1 ];
do
echo $a
a=$((a-1))
done
什么是shell的函数
shell脚本中的函数就是先把一段代码整理到一个小单元中,并给这个小单元命名,当用到这段代码时直接调用这个小单元的名字即可。
案例:通过设置相加函数实现两个参数相加。
#! /bin/bash
sum(){
sum=$(($1+$2))
echo $sum
}
sum $1 $2
练习:创建一个函数,输出"Hello World"
#! /bin/bash
say_Hello(){
echo "Hello World"
}
#use function
say_Hello
中断break
案例:在循环输出1-10的时候,遇到5时候停下。
#! /bin/bash
for i in $(seq 1 10);
do
if [ $i -eq 5 ]; then
break
fi
echo $i
done
继续continue
案例:在循环输出1-10,遇到5时候不输出。
#! /bin/bash
for i in $(seq 1 10);
do
if [ $i -eq 5 ]; then
continue
fi
echo $i
done
退出程序exit
#!/bin/bash
for i in $(seq 1 5)
do
echo $i
if [ $i == 3 ]
then
exit
fi
echo $i
done
echo aaaaaaa
到这里基本的语法就学完了,下面将进行shell脚本实践
练习1:目录/tmp/log需要将老文件(比如三天以前的),挪到另外一个目录下 /tmp/logbak下。挪完之后,还需要做软链接,需要日志.
#!/bin/bash
# 定义目录和时间变量
log_dir="/tmp/log"
bak_dir="/tmp/logbak"
current_date=$(date +%s)
time_limit=$((3 * 24 * 60 * 60)) # 3 天的秒数
# 遍历 /tmp/log 目录下所有文件和子目录
find "$log_dir" -mindepth 1 -mtime +3 -type f | while read file; do
# 构建备份文件路径
bak_file="$bak_dir/$(basename "$file").$current_date.bak"
# 备份文件
mv "$file" "$bak_file"
# 创建软链接
ln -sf "$bak_file" "$file"
# 输出备份信息
echo "备份 $file 到 $bak_file,并创建软链接。"
done
练习2:写一个脚本,遍历当前txt目录下的txt文件,将这些txt文件做一个备份,备份的文件名增加一个年月日的后缀。
#!/bin/bash
# 获取当前年月日
current_date=$(date +"%Y%m%d")
# 遍历当前目录下的所有txt文件
for file in ./txt/*.txt; do
if [ -f "$file" ]; then
# 构建备份文件名
backup_file="${file%.txt}_${current_date}.txt"
# 复制文件到备份文件
sudo cp "$file" "$backup_file"
# 输出备份信息
echo "备份 $file 到 $backup_file"
fi
done
练习3:将 /var/log/ 目录中的文件移动到 /tmp/log/ 中,并将其中的某些文件在 3 天后备份到 /tmp/logbak/ 目录中。
#!/bin/bash
#auth:mm,date
#功能
Diskmov()
{
cd /tmp/log
for dir in `ls`
do
for dir2 in `find $dir -maxdepth 1 -type d -mtime +3`
do
rsync -aR $dir2/ /tmp/logbak/
if [ $? -eq 0 ]
then
rm -rf $dir2
echo "/var/log/$dir2 移动成功"
ln -s /tmp/logbak/$dir2 /tmp/log/$dir2 && echo "/tmp/log/$dir2成功创建软链接"
echo
else
echo "/tmp/log/$dir 未移动成功"
fi
done
done
}
diskmov &> /tmp/move_old_data_`date +%F`.log