本文梳理linux的shell脚本知识,linux基础部分的前提知识点击这里linux核心知识梳理
一、脚本基础
1、简介
Linux Shell脚本有很多
Bourne Shell(sh) 命令文件 /usr/bin/sh或/bin/sh
Bourne Again shell(bash)命令文件 /bin/bash
C Shell(csh)命令文件 /usr/bin/csh
TENEX C Shell(tcsh)
Korn shell(ksh)命令文件 /usr/bin/ksh
Shell for Root(/sbin/sh)
…
Bash 是目前最常用的 Shell,除非特别指明,下文的 Shell 和 Bash 当作同义词使用,可以互换。
2、echo打印
声明为bin类型的bash脚本:固定写法
注释:以#开头
echo:打印
#!/bin/bash
# 这是注释
echo "123"
3、声明变量注意
声明变量的”=“前后不能有空格,否则脚本报错
注意:赋值时 “=” 两边都不能加空格符;比较时 “=” 两边都必须加空格符。
#!/bin/bash
# 字符串
text="I love china!"
echo $text
# 数字
NDK=10
echo $NDK
# 拼接
echo "$text haha"
# 转义输出
echo "\$NDK"
打印
I love china!
10
I love china! haha
$NDK
4、系统日期、用户名
#!/bin/bash
date
who
输出时间和用户名
2022年 7月11日 星期一 09时11分25秒 CST
zhanglei console Jun 28 19:54 zhanglei ttys000 Jul 11 08:52
二、shell各种括号的用法 () (())、[]、[[]]、{}
1、() 运算符
1.1、命令替换 $()
#!/bin/bash
date
# 命令替换就是将shell命令的输出赋给变量
test=$(date)
echo $test
# 除了使用$() 进行命令替换以外,还可以用 `` 符号
test2=`date`
echo $test2
1.2、进程列表 (;;)
() 表示在当前 shell 中将多个命令作为一个整体执行,示例:
# 它的一般形式为: ( 命令;命令;命令… )
rm ~/Desktop/1.txt || (cd ~/Desktop/;ls -a;echo "fail")
每个命令后面加分号就是命令列表,但是同样的命令列表括号的加入使命令列表变成了进程列表。下面示例中$BASH_SUBSHELL 输出为0则表示为主线程。
#!/bin/bash
# /Users/zhanglei/Desktop
# 1
(pwd ;echo $BASH_SUBSHELL )
# /Users/zhanglei/Desktop
# 0
pwd ;echo $BASH_SUBSHELL
1.3、数组变量(a b c d )
在shell 中也是支持定义数组的,数组的赋值是通过()括起来的,数组元素之间通过空格分隔,并且数组的下标是从零开始的。其中和其他编译语言一样要访问数组元素需要通过数组名+[下标]的方式访问。[*] 比较特别,它可以列出数组的所有元素。并且变量名指代的是数组变量的第一个元素也就是[0]。
#!/bin/bash
test=(a b c d)
echo ${test[*]} # a b c d
echo ${test[0]} # a
echo $test # a
2、(()) 运算符
注意:
- expr的乘法需要转义
- 这两者都只能用于整数的计算,对于浮点数计算会直接报错
2.1、(())加减乘除
用于计算整数的加减乘除
#!/bin/bash
a=10
b=20
c2=$(($a + $b))
echo "加:$c2"
echo "减:$(($b - $a))"
echo "乘:$(($b * $a))"
echo "除:$(($b / $a))"
加:30
减:10
乘:200
乘:2
2.2、expr加减乘除
expr命令,是一个手工命令行计数器,用于在Linux下求表达式变量的值,一般用于整数值,也可用于字符串。
#!/bin/bash
a=10
b=20
c=$(expr $b + $a)
echo "加:$c"
echo "减:$(expr $b - $a)"
echo "乘:$(expr $b \* $a)"
echo "除:$(expr $b / $a)"
加:30
减:10
乘:200
乘:2
3、[] 运算符
3.1、通配符[]
- 查找1或3的文件
中括号表示一个字符位置并给出多个可能的选择
➜ 未命名文件夹 ls
123 223 323 tests.c
➜ 未命名文件夹 ls [13]*
123 323
- 查找字母范围[1–3]的文件
-表示指定范围
➜ 未命名文件夹 ls
123 223 323 tests.c
➜ 未命名文件夹 ls [1-3]*
123 223 323
3.2、数学运算$[]
只能用于整数的加、乘
#!/bin/bash
a=10
b=20
c3=$[$a + $b]
echo "加:$c3"
echo "乘:$[$a * $b]"
加:30
乘:200
4、[[]]运算符
模式匹配比较 [[]] ,更多参考[5.1、字符串判断](# 1、字符串判断)
if [[ str1 ]] # 当字符串 str1 为非空时为真
5、{}运算符
5.1、变量范围限定${}
#!/bin/bash
a=123456
echo $abc #
echo ${a}bc #123456bc
5.2、命令分组 { ;;}
注意 “{” 后面需要有空格,“}” 前可以不需要空格 但是最后一条命令需要结束后也需要加“;” 。可以看到echo $BASH_SUBSHELL 输出的为 0,说明命令分组 { ;;} 并没有创建子shell 执行命令。
#!/bin/bash
{ ls ; ls ;echo $BASH_SUBSHELL; }
# 123 223 323 tests.c
# 0
二、计算
1、浮点数
bc:浮点数计算
|: 管道,一个命令的输出作为另外一个命令的输入
scale:自带的内建变量,设定小数位数
#!/bin/bash
a=10
b=20
e=$(echo "scale=4; $a / 3" | bc)
echo "浮点数计算:$e"
浮点数计算:3.3333
2、内联输入重定向
bc:浮点数计算
scale:自带的内建变量,设定小数位数
格式相对固定:
开头:$(bc << EOF,
结尾:EOF)
示例中:将 bc 的计算结果赋值给 Shell 变量
#!/bin/bash
a=10
b=20
f=$(bc << EOF
scale=4
a1=$a * $b
a1/3
EOF
)
echo "内联输入重定向:$f"
内联输入重定向:66.6666
3、&&和||
shell支持逻辑运算符编写命令语句
command1 && command2 //逻辑与:如果这个命令执行成功&&那么执行这个命令
command1 || command2 //逻辑或:如果这个命令执行失败了||那么就执行这个命令
4、异步执行
4.1、&异步执行
在执行命令后加&操作符,表示将命令放在子shell中异步执行。可以达到多线程效果。如下
sleep 10 #等待10秒,再继续下一操作
sleep 10 & #当前shell不等待,后台子shell等待
4.2、wait命令
等待作业号或者进程号制定的进程退出
#!/bin/bash
sleep 10 &
sleep 5&
wait #等待10秒后,退出
四、条件语句
1、if
- If里面必须要then,else里面可以不用then
- fi结尾
- grep:文本搜索工具命令
下面示例:去读是linux下否有自定义的jack用户,有则打印jack的主目录,无则提示。关于怎么创建用户参考linux核心知识梳理
#!/bin/bash
testuser=jack
if grep $testuser /etc/passwd
then
echo "ok"
ls -a /home/$testuser/
elif ls -d /home/$testuser
then
echo "用户不存在,主目录仍然存在"
else
echo "$testuser not exist"
fi
jack:x:1002:1002::/home/jack:/bin/sh
ok
. .. .bash_logout .bashrc .profile
passwd:当前所有用户信息,linux下截图如下
![image-20220127202810611](https://img-blog.csdnimg.cn/8c0916bd50ca4c82a7e01973a470f54e.png)
2、test
test命令,如果条件成立,test命令状态为0退出,if条件成立
下面示例中:判断var变量是否有值(0也是有值),这里为字符串abc,因此if成立
#!/bin/bash
var=abc
if test $var
then
echo "test条件成立"
else
echo "test条件不成立"
fi
test条件成立
3、多个条件
3.1、操作符[ ]
如果if要判断多个条件,我们&&将多个[ ]连接起来
-d:检查目录是否存在
-w:检查是否存在,并且可写
下面示例:在指定目录下生成了test5文件
#!/bin/bash
#多个条件 []
mydir=/Users/zhanglei/Desktop
#任意数学赋值或者比较表达式
#if (( a++ > 90 ))
if [ -d $HOME ] && [ -w $mydir ]
then
cd $mydir
touch test5
else
echo "no"
fi
3.2、操作符 (( ))
下面示例输出:yes
#!/bin/bash
#多个条件 []
#任意数学赋值或者比较表达式
a=95
if (( (a++ > 90) && (a++ < 100) ))
then
echo "yes"
else
echo "no"
fi
4、case语句
case命令
case 变量 in
pattern1) 命令;;
pattern2) 命令;;
*) 默认命令;;
esac
- 每个case用)包起来,也就是:jack)
- 每个case末尾用双分号:;;
- default用esac
#!/bin/bash
testuser=jack
case $testuser in
jack)
echo "hi,rose with jack";;
jason)
echo "hello,jason";;
*)
echo "defaults";;
esac
输出
hi,rose with jack
五、判断语句
1、字符串判断
if [[ str1 = str2 ]] # 当字符串 str1 和 str2 有相同内容、长度时为真
if [[ str1 != str2 ]] # 当字符串 str1 和 str2 不等时为真
if [[ -n "str1" ]] # 当字符串 str1 的长度大于 0(非空)时为真
if [[ -z "str1" ]] # 当字符串 str1 的长度为 0(空)时为真
if [[ str1 ]] # 当字符串 str1 为非空时为真
示例
结果:相等
#!/bin/bash
str1="asdf"
str2="asdf"
if [[ str1 = str2 ]]; then
echo "相等"
else
echo "不相等"
fi
注意:
- 赋值时 “=” 两边都不能加空格符;比较时 “=” 两边都必须加空格符。
- 字符串比较这里=前后空格
== 和=
- ==可用于判断变量是否相等,= 除了可用于判断变量是否相等外,还可以表示赋值。
- = 与 == 在 [ ] 中表示判断(字符串比较)时是等价的
- 在 (( )) 中 = 表示赋值, == 表示判断(整数比较),它们不等价
2、数字的判断
int1 -eq int2 # 两数相等为真
int1 -ne int2 # 两数不等为真
int1 -gt int2 # int1大于int2为真
int1 -ge int2 # int1大于等于int2为真
int1 -lt int2 # int1小于int2为真
int1 -le int2 # int1小于等于int2为真
下面示例输出:10 greater than 5
if[ ]:test命令简单形式
注意:if[ ]要打前后空格
#!/bin/bash
int1=10
int2=5
if [ $int1 -gt $int2 ]
then
echo "$int1 greater than $int2"
else
echo "$int1 smaller than $int2"
fi
3、文件的判断
# 高频
-d file # 文件为目录为真
-e file # 检查file是否存在
-f file # 文件为正规文件为真(检查是否存在,并且是一个文件)
# 非高频
-c file # 文件为字符特殊文件为真
-b file # 文件为块特殊文件为真
-s file # 文件大小非0时为真
-t file # 当文件描述符(默认为1)指定的设备为终端时为真
# rwx读、写、执行
-r file # 用户可读为真
-w file # 用户可写为真
-x file # 用户可执行为真
示例:-d检查目录是否存在
#!/bin/bash
mydir=/Users/zhanglei/Desktop
#-d检查目录是否存在
if [ -d $mydir ]
then
echo "$mydir exist"
cd $mydir
ls
else
echo "mydir not exist"
fi
exist
01.sh U启动增强版.lnk min-apps-develop test_cli
六、循环语句
1、for循环
分隔符IFS:”IFS=-“就是以-为分隔符
#!/bin/bash
list="windows--linux--macos"
#IFS字段分隔符
#IFS=$--
IFS=-
for item in $list
do
echo $item
done
windows
linux
macos
2、while循环
-gt:大于
-eq:等于
下面示例:a的值为5,a>0时每次循环减1,当a=5退出循环
#!/bin/bash
a=10
while [ $a -gt 0 ]
do
echo "num:$a"
#赋值不用使用$符号
a=$[ $a - 1 ]
if [ $a -eq 5 ]
then
echo "break"
break
fi
done
num:10
num:9
num:8
num:7
num:6
break
七、脚本文件入参
1、第一个参数、第二个参数
$0:表示文件路径
$1:表示第一个参数
$2:表示第二个参数,以此类推
#!/bin/bash
echo $0
echo $1
echo $2
使用两种不同方式调用脚本输出如下
➜ Desktop sh test.sh 123 456
test.sh
123
456
➜ Desktop ./test.sh 123 456
./test.sh
123
456
2、获取文件名与参数总数
#!/bin/bash
filename=$(basename $0)
echo $filename
echo "参数的总数:$#"
使用两种不同方式调用脚本输出如下
➜ Desktop sh test.sh 123 456
test.sh
参数的总数:2
➜ Desktop ./test.sh 123 456
test.sh
参数的总数:2
3、for循环遍历参数
#!/bin/bash
#使用$@遍历所有参数
for param in "$@"
do
echo "param:$param"
done
➜ Desktop ./test.sh 123 456 789
param:123
param:456
param:789
八、输出重定向
1、ls命令的重定向
输出到一个文件
#!/bin/bash
ls -la > text3.txt
将文件列表输出到text3.txt文件中
total 432
drwx------+ 27 zhanglei staff 864 7 11 09:00 .
drwxr-x---+ 88 zhanglei staff 2816 7 11 09:00 ..
2、所有的输出重定向
上面仅针对一条命令进行重定向,那么如何对后续所有输出重定向?
exec num输出重定向,num取值
0:STDIN 标准输入(光标等待用户输入的)
1:STDOUT 标准输出
2:STDERR 标准错误
#!/bin/bash
exec 1>test7.txt
echo "abc"
echo "efg"
ls -a
打印如下 (可以用来写日志)
abc
efg
test7.txt
test.sh
九、函数
1、函数入参与返回值
示例:调用myfun函数传入10、90两个参数,相加后通过echo返回,得到100赋值给value
注意:函数括号不能紧贴函数写,错误写法”myfun{“,这里要么换行要么空格
#!/bin/bash
function myfun
{
echo $[ $1 + $2 ]
}
value=$(myfun 10 90)
echo "value:$value"
打印如下
➜ Desktop ./test.sh
value:asdf 100
1.1、返回值的方式
- 方法一:return
- 方法二: echo
1.2、return和echo使用场景区别:
- 使用return返回值:
使用return返回值,只能返回1-255的整数
函数使用return返回值,通常只是用来供其他地方调用获取状态,因此通常仅返回0或1;0表示成功,1表示失败
- 使用echo返回值:
使用echo可以返回任何字符串结果
通常用于返回数据,比如一个字符串值或者列表值
2、引入其他脚本文件
如果是调用其它脚本,直接bash 脚本全路径即可
bash ./replace/replaceResources.sh
如果是引入其他脚本变量函数,则需要source引入。
比如这里定义加法函数add.sh如下
#!/bin/bash
function add()
{
echo $[ $1 + $2 ]
}
2.1、source引入
新建脚本source引入add.sh,并调用add函数
#!/bin/bash
#引入
source ./add.sh
echo "add:$(add 10 30)"
#打印:add:40
2.2、.source快捷别名
注意第一个点是快捷别名,第二个点是路径,不能写连一块儿
#!/bin/bash
#.source快捷别名
. ./add.sh
echo "add:$(add 10 30)"
#打印:add:40