编写 shell 脚本
Hello word
- 创建并进入编写一个 xx.sh脚本文件
vi first.sh
#! /bin/bash
echo "Hello Word!"
- 运行 .sh脚本
sh first.sh
或
./first.sh
加上 -x 可以查看脚本的运行记录
sh -x first.sh
[root@shell ~]# sh -x first.sh
+ echo 'Hello Word!'
Hello Word!
基础语法
分号,换行都表示单条命令的结束。同一行内写多条命令必须用;分割。
空格。某些结构的语法要求必须有空格,如 $[ $1 -lt 10 ]中,‘[’ 后要有空格,']'前也要空格; 如定义函数 sum() { 后必有空格或换行。如单行内定义多个变量要用空格分割。
‘’ 表示字符串原样。``表示输出其中命令的结果。如echo `seq 1 5`会输出 1 2 3 4 5。
运行和调试
如果某一行语法错误,下面不关联的脚本仍然会继续执行。
使用sh 或 .都能执行shell脚本文件。
调试:
- -x
跟踪执行过程,将每条执行命令和结果一并输出。可以检查语法错误,尤其对于单行文本中有多条命令,-x 会将根据语法规则做详细拆分,逐次输出命令和结果。 - -n
读一编脚本但不执行,可以用来事先检查语法错误。 - -v
将每行命令文本和对应的结果一并输出。
在shell中使用变量
- 在shell中定义变量
a=1
echo $a
对变量做数学运算,需要使用[]括起来,并在[]前使用$
a=1
b=2
echo "sum=$[$a+$b]"
- 预设变量
a=$1
b=$2
echo "sum=$[$a+$b]"
执行命令同时传入的参数,用$1、$2…对应参数顺序就可以。$0特指当前shell脚本文件名。
[root@shell ~]# sh first.sh 100 200
sum=300
- 交互变量,shell运行过程中传入变量
read -p "请输入第一个值:" x
read -p "请输入第二个值:" y
echo "求和等于:$[$x+$y]"
执行脚本:
[root@shell ~]# sh first.sh
请输入第一个值:100
请输入第二个值:200
求和等于:300
if选择结构
if 不带 else
格式:
if 判断语句
then
命令语句
fi
示例:
if (($1 < 5))
then
echo $1这个数小于5
fi
单行内写完整个if结构要使用分号:
if [ $y -gt 100 ];then echo $y大于100哈;fi
if else
格式:
if 判断语句
then
命令语句
else
命令语句
fi
示例:
if (($1 < 5)); then
echo 这个数小于5
else
echo 这个数太大了
fi
if elif
格式:
if 判断语句; then
命令语句
elif 判断语句; then
命令语句
else
命令语句
fi
示例:
if (($1 < 5)); then
echo 这个数小于5
elif (($1 == 5)); then
echo 这个数刚好
else
echo $1你太大了
fi
-lt、-gt、-le、-ge、-eq、-ne
等值的判断语句可以写在(())内,也可以写在[]内,使用[]时<>=符号要用以下符号代替。
-lt 小于
-gt 大于
-le 小于或等于
-ge 大于或等于
-eq 等于
-ne 不等于
if [ $1 -lt 5 ]; then
echo 这个数小于5
elif [ $1 -eq 5 ]; then
echo 这个数刚好
else
echo 这个数太大了
fi
&& 和 ||
与和或。在判断语句中使用 && 和 || 对多个条件的判断,和java类似。
if [ $1 -lt 5 ] || [ $1 -gt 10 ]; then
echo 这个数小于5,或大于10
fi
文档相关的判断
在if 判断语句中,对文档的判断,常用的有以下关键字
-e 判断文件或目录是否存在
-d 判断是不是目录以及是否存在
-f 判断是不是文件以及是否存在
-r 判断是否有读权限
-w 判断是否有写权限
-x 判断是否有执行权限
-x 判断字符串为空返回true
-s 判断文件大小不为0返回true
判断文件存在,具体格式:
if [ -e filename ]; then
命令语句
fi
if [ -e /home/ ]; then
echo 'ok'
fi
case选择结构
具体格式如下
case 变量 in
value1)
命令语句
;;
value2)
命令语句
;;
*)
命令语句
;;
esac
示例:
a=$[$1%2]
case $a in
0)
echo "The number is even."
;;
1)
echo "The numbei is odd."
;;
*)
echo "Tt's not a number."
;;
esac
for循环
格式:
for 变量名 in 循环条件; do
命令语句
done
循环条件可以是一组字符串或数字(空格分割),也可以是一条命令的执行结果。
示例:
for i in 1 2 3 a b c; do
echo $i;
done
# seq 1 5 表示从1到5的一个序列
for i in `seq 1 5`; do
echo $i;
done
for file in `ls ~`; do
echo $file;
done
while循环
格式:
while 条件语句; do
命令语句
done
示例:
a=$1
while [ $a -ge 1 ]; do
echo $a
a=$[$a-1]
done
如果用冒号代替循环条件,可以死循环
while :; do
echo '呀哈哈,我被发现了'
done
循环中断 break、continue、exit
break 结束整个循环体。
continue 结束本次循环,进入下一次循环。
exit 退出整个脚本。
for i in `seq 1 5`
do
if [ $i == 3 ]; then
break
fi
echo $i
done
# 输出 1 2
for i in `seq 1 5`
do
if [ $i == 3 ]; then
continue
fi
echo $i
done
# 输出 1 2 4 5
数组
- 定义数组
a=(1 2 3 4 5)
或者
a=(`seq 1 5`)
- 获取数组所有元素
echo ${a[@]}
或者
echo ${a[*]}
- 获取数组长度
echo ${#a[@]}
- 获取指定索引的元素
echo ${a[1]}
- 修改指定索引的元素
a[1]=100
# 1 100 3 4 5
- 直接替换指定位置元素
# 将第3个元素设置为100. 注意,3不是索引
a=(${a[@]/3/100})
# 1 100 100 4 5
# 如果索引下标不存在,则添加一个元素
a[5]=6
# 1 100 3 4 5 6
- 删除指定索引的元素
unset a[5]
# 1 100 3 4 5
- 删除整个数组
unset a
- 指定位置和长度截取
# 从索引第0个元素开始,截取长度3个
echo ${a[@]:0:3}
# 1 2 3
# 从倒数第3个元素开始,截取长度2个
echo ${a[@]:0-3:2}
# 3 4
函数定义和使用
定义函数必须写在调用函数之前,而且是在最前,不能出现在中间。
示例:
# 定义sum()函数
function sum()
{
sum=$[$1+$2]
echo $sum
}
# 调用
sum $1 $2
在shell中使用日期date
#! /bin/bash
date
运行后输出:
2023年04月11日 星期二 15:11:38 CST
如果要将date执行结果赋值给变量,需要写在``中,否则表示date这个字符串
d=`date`
echo $d
- 指定格式的日期
%Y 表示四位数字年份
%y 表示两位数字年份
%m 表示月份
%d 表示日期
%H 表示小时
%M 表示分钟
%S 表示秒
%w 表示星期
示例:
date +%Y-%m-%d
# 2023-04-12
示例:
date +'%Y-%m-%d %H:%M:%S'
# 2023-04-12 17:49:43
注意区分大小写,在java中输出这个样式是使用 yyyy-MM-dd HH:mm:ss
- 对日期加减偏移
date -d '-1 day' # 当前日期的前一天
date -d '-1 hour' # 当前时间的前一小时
date -d '-1 min' # 当前日期的前一分钟
偏移后的日期仍然可以指定格式输出
date -d '-1 day' +'%Y-%m-%d %H:%M:%S'
同样,赋值给变量也需要写在``里
d1=`date -d '+1 hour' +'%Y-%m-%d %H:%M:%S'`
echo $d1
bin/bash 和 /bin/sh
以/bin/bash声明的脚本,中间即使发生错误,依然会继续向下运行。
/bin/sh是早期版本,脚本中间发生错误会终止脚本的运行,不再运行下面的代码。
#!/bin/bash --posix,脚本执行效果跟#!/bin/sh是一样的。
#!/bin/bash --posix #开启便携模式,遇到错误时,停止继续运行
新版本的Linux内核中,老的sh已经被后来者bash整合了。