1. shell的概述
shell 是一种脚本语言
脚本:本质是一个文件,文件里面存放的是特定格式的命令,系统可以使用脚本解析器翻译或解析指令并执行(它不需要编译)
shell 既是应用程序 又是一种脚本语言(应用程序解析脚本语言)
shell 命令解析器:
系统提供shell命令解析器:sh ash bash
查看自己linux系统的默认解析:echo $SHELL
shell脚本是一种脚本语言,我们只需使用任意文本编辑器,按照语法编写相应程序,增加可执行权限,即可在安装shell命令解释器的环境下执行
2. 脚本的调用形式
- 打开终端时系统自动调用:
/etc/profile
或~/.bashrc
/etc/profile
此文件为系统的每个用户设置环境信息,当用户第一次登录时,该文件被执行,系统的公共环境变量在这里设置
开机自启动的程序,一般也在这里设置
~/.bashrc
用户自己的家目录中的.bashrc
登录时会自动调用,打开任意终端时也会自动调用
这个文件一般设置与个人用户有关的环境变量,如交叉编译器的路径等等
用户手动调用:用户实现的脚本
3. shell语法初识
3.1 定义开头:#!/bin/bash
#!
用来声明脚本由什么shell解释,否则使用默认shell
ls /bin | grep sh
echo $SHELL
3.2 单个"#"号代表注释当前行
- 第一步:编写脚本文件
#!/bin/bash
#注释
echo "hello world!"
- 第二步:加上可执行权限
chmod +777 01_dzf.sh
- 第三步:运行
./01_dzf.sh
- 三种执行方式
./xxx.sh
:先按照文件中"#!" 指定的解析器解析
如果"#!" 指定的解析器不存在才会使用系统默认的解析器
bash xxx.sh
:指明先用bash解析器解析
如果bash不存在才会使用默认解析器
.xxx.sh
:直接使用默认解析器解析(不会执行第一行"#!" 指定的解析器)但是第一行还是要写的
三种执行情况:
打开终端就会有一个解析器,我们称为当前解析器
我们指定解析器的时候(使用 ./xxx.sh
或 bash xxx.sh
)时会创建一个子shell解析 脚本
注意:Windows下写脚本在Linux下执行注意将Windows文件转换成unix文件
方法一:dos2unix
如果没有该插件 需要安装
sudo apt-get install dos2unix
dos2unix 02_dzf.sh
转换成功就可以执行运行
方法二:需要用vim打开脚本,在最后一行模式下执行:set ff=unix
后执行:wq
4. 变量
- 定义变量
变量名=变量值
如:num=10
-
引用变量
$变量名
-
清除变量值
unset 变量名
-
从键盘获取值
read
在一行上显示和添加提示 需要加上-p
- 只读变量
readonly
#!/bin/bash
#定义变量
num=100
#打印 引用变量
echo "打印定义变量num:$num"
#清除变量值
unset num
echo "打印清除后的定义变量:$num"
#从键盘获取值
echo "请输入num的值"
read num
echo "num=$num"
read -p "请输入Num的值:" Num
echo "Num=$Num"
#读取多个值
read -p "读取多个值data1 data2:" data1 data2
echo "data1=$data1"
echo "data2=$data2"
#只读变量
readonly onlyNum=10
echo "onlyNum=$onlyNum"
onlyNum=11
echo "onlyNum=$onlyNum"
- 查看环境变量
env
-
导出环境变量 作用:(让其他shell脚本识别该变量,设为全局变量)
-
source命令用法:
source FileName
作用:在当前bash环境下读取并执行FileName中的命令。
注:该命令通常用命令“.”来替代。
如:source .bash_rc 与 . .bash_rc 是等效的。
注意:source命令与shell scripts的区别是,
source在当前bash环境下执行命令,而scripts是启动一个子shell来执行命令。这样如果把设置环境变量(或alias等等)的命令写进scripts中,就只会影响子shell,无法改变当前的BASH,所以通过文件(命令列)设置环境变量时,要用source 命令。
#!/bin/bash
#设置环境变量
export DATA=250
用source
命令使文件生效
使用 env可以查看到环境变量中已经有 DATA
可以在终端直接中读取:
echo $DATA
在其他sh脚本读取
#!/bin/bash
echo "环境变量中的DATA=$DATA"
注意事项:
-
变量名只能包含英文字母下划线,不能以数字开头
-
等号两边不能有空格符,若变量中本身就包含了空格,则整个字符串都要用双引号、或单引号括起来
-
双引号和单引号的区别
双引号:可以解析变量的值
单引号:不能解析变量的值
#!/bin/bash
num=200
#$num当成变量的值处理
echo "num=$num"
#$num当成字符串处理
echo 'num=$num'
如果想在PATH变量中 追加一个路径写法如下:(重要!!!!)
export PATH=$PATH:/需要添加的路径
5. 预设变量
5.1 shell 直接提供无需定义的变量
名称 | 解释 |
---|---|
$# | 传给shell脚本参数的数量 |
$* | 传给shell脚本参数的内容 |
$1、$2...$9 | 运行脚本时传递给其的参数,用空格隔开 |
$? | 命令执行后返回的状态 |
"$?" | 用于检查上一个命令执行是否正确(在Linux中,命令退出状态为0表示该命令正确执行,任何非0值表示命令出错) |
$0 | 当前执行的进程名 |
$$ | 当前进程的进程号 |
"$$" | 变量最常见的用途是用作临时文件的名字以保证临时文件不会重复 |
#!/bin/bash
echo "参数的个数=$#"
echo "参数的内容=$*"
echo "第一个参数:$1"
echo "第二个参数:$2"
echo "第三个参数:$3"
readonly data=10
data=250
echo "data=250的结果:$?"
echo "进程名:$0"
echo "进程号:$$"
5.2 脚本标量的特殊用法
名称 | 解释 |
---|---|
""(双引号) | 包含的变量会被解释 |
''(单引号) | 包含的变量会当作字符串解释 |
``(数字键1左面的反引号) | 反引号的内容作为系统命令,并执行其内容,可以替换输出为一个变量 |
\(转义字符) | 同c语言 \n \t \r \a 等 echo 命令需要加-e 转义 |
(命令序列)(小括号) | 由子shell来完成,不影响当前shell中的变量 |
{命令序列}(大括号) | 在当前shell中执行,会影响当前变量 |
#!/bin/bash
#打印当前系统时间
echo "today is `date`"
#查看当前文件夹文件
ls
#加-e转义 才起换行作用
echo "##\n##"
echo -e "##\n##"
#()由子shell完成
echo "()由子shell完成"
data=10
echo "定义data = $data"
( #子shell完成 不会影响当前shell得值
data=100
echo "()里面data = $data"
)
echo "当前data=$data"
#{}由当前的shell执行
echo "{}由当前shell完成"
data=10
echo "定义data = $data"
{ #子shell完成 不会影响当前shell得值
data=100
echo "{}里面data = $data"
}
echo "当前data=$data"
6. 变量的扩展
6.1 判断变量是否存在
#!/bin/bash
# ${num:-val} 如果num存在,整个表达式的值为num,否则为val
echo ${num:-100} #100
num=200
echo ${num:-100} #200
#!/bin/bash
#${num:=val} 如果num存在,整个表达式的值为num,否则为val,同时将num的值赋值为val
echo ${num:=100} #100
echo "num=$num" #100
6.2 字符串的操作
#!/bin/bash
str="hehe:haha:xixi:lala"
#测量字符串的长度${#str}
echo "str的长度为:${#str}"
#从下标3的位置提取${str:3}
echo "从下标3的位置提取:${str:3}"
#从下标3的位置提取长度为6字节${str:3:6}
echo "从下标3的位置提取长度为6字节:${str:3:6}"
#${str/old/new} 用new替换str中出现的第一个old
echo "单个字符串替换:${str/:/#}"
#${str//lod/new} 用new替换str中所有的lod
echo "字符串替换:${str//:/#}"
7. 条件测试
- test命令
用于测试字符串、文件状态和数字
test命令有两种格式:test condition
或[condition]
使用方括号时,要注意在条件两边加上空格
7.1 文件测试
名称 | 解释 |
---|---|
-e | 如果文件存在则为真 |
-d | 如果文件存在且为目录则为真 |
-f | 如果文件存在且为普通文件则为真 |
-r | 如果文件存在且可读则为真 |
-w | 如果文件存在且可写则为真 |
-x | 如果文件存在且可执行则为真 |
-L | 符号链接 |
-c | 如果文件存在且为字符型特殊文件则为真 |
-b | 如果文件存在且为块特殊文件则为真 |
-s | 如果文件存在且至少有一个字符则为真(文件非空) |
#!/bin/bash
read -p "请输入一个文件名:" fileName
#第一种命令格式
test -e $fileName
echo "第一种命令格式结果:$?"
#第二种命令格式
[ -e $fileName ]
echo "第二种命令格式结果:$?"
7.2 字符串测试
语法
test str_operator "str"
test "str2" str_operator "str2"
[ str_operator "str" ]
[ "str1" str_operator "str2" ]
str_operator | 解释 |
---|---|
= | 两个字符串相等 |
!= | 两个字符串不相等 |
-z | 空串 |
-n | 非空串 |
#!/bin/bash
test -z $yn
echo "yn是否为空:$?"
read -p "please input y/n:" yn
[ -z $yn ]
echo "输入的是否为空:$?"
[ $yn = "y" ]
echo "输入的是否为y:$?"
read -p "请输入第一个字符串:" str1
read -p "请输入第二个字符串:" str2
# test $str1 = $str2
[ $str1 = $str2 ]
echo "两次输入是否相同:$?"
7.3 数值测试
test num1 num_operator num2
[ num1 num_operator num2 ]
num_operator | 解释 |
---|---|
-eq | 数值相等 |
-ne | 数值不相等 |
-gt | 数1大于数2 |
-ge | 数1大于等于数2 |
-le | 数1小于等于数2 |
-lt | 数1小于数2 |
#!/bin/bash
read -p "请输入第一个数值:" data1
read -p "请输入第二个数值:" data2
test $data1 -eq $data2
echo "相等:$?"
test $data1 -ge $data2
echo "大于等于:$?"
[ $data1 -lt $data2 ]
echo "小于:$?"
7.4 符合语句测试
- &&
command1 && command2
command1执行成功shell才执行command2
- ||
command1 || command2
command1执行失败shell才执行command2
#!/bin/bash
#根目录下有home文件且是个目录则打印true
test -e /home && test -d /home && echo "true"
#2小于3且5大于3则打印equal
test 2 -lt 3 && test 5 -gt 3 && echo "equal"
#aaa与aaa不相同则打印not equal 相同则打印equal
test "aaa" = "aaa" || echo "not equal" && echo "equal"
- 多重条件判定
名称 | 解释 |
---|---|
-a | (and)test -r file -a -x file file同时具有r与x权限时才为true |
-o | (or)test -r file -o -x file file具有r或x权限时就为true |
! | test ! -x file file不具有x权限时为true |
8. 控制语句
8.1 if
- 语法
#格式一
if [条件一]; then
执行第一段程序
else
执行第二段程序
fi
#格式二
if [条件一]; then
执行第一段程序
elif [条件二]; then
执行第二段程序
else
执行第三段程序
fi
- 案例1
#!/bin/bash
read -p "输入y继续:" yn
if [ $yn = "y" ]; then
echo "继续执行"
else
echo "停止执行"
fi
- 案例2
#!/bin/bash
read -p "请输入文件夹的名字:" dirName
#判断文件夹是否存在
if [ -d $dirName ]; then
echo "$dirName文件夹存在,进入文件夹"
cd $dirName
echo "创建test.c文件"
touch test.c
else #不存在
echo "$dirName文件夹不存在,创建文件夹"
mkdir $dirName
echo "进入$dirName文件夹"
cd $dirName
echo "创建test.c文件"
touch test.c
fi
判断当前路径下有没有文件夹 有就进入创建文件 没有 就创建文件夹 再进入创建文件
- 案例3
#!/bin/bash
read -p "请输入文件夹的名字:" dirName
#判断文件夹是否存在
if [ -d $dirName ]; then
echo "$dirName 文件夹存在,进入文件夹"
cd $dirName
if [ -e test.c ]; then
echo "test.c文件已存在,安装失败"
else
echo "创建test.c文件"
touch test.c
if [ $? -eq 0 ]; then
echo "安装成功"
else
echo "安装失败"
fi
fi
else #不存在
echo "$dirName文件夹不存在,创建文件夹"
mkdir $dirName
echo "进入$dirName文件夹"
cd $dirName
if [ -e test.c ]; then
echo "test.c文件已存在,安装失败"
else
echo "创建test.c文件"
touch test.c
if [ $? -eq 0 ]; then
echo "安装成功"
else
echo "安装失败"
fi
fi
fi
8.2 case
- 语法
case $变量名称 in
"第一个变量内容")
程序段一
;; #break
"第二个变量内容")
程序段一
;;
*) #default
其他程序段
exit 1
esac
- 案例
#!/bin/bash
read -p "请输入yes/no:" choice
case $choice in
yes | y* |Y*)
echo "输入了yes"
;; #break
no | n* | N*)
echo "输入了no"
;;
*) #default
echo "输入了其他"
exit 1 #或;;
esac
8.3 for
- 语法
#形式一
for (( 初始值; 限制值; 执行步阶 ))
do
程序段
done
初始值:变量在循环中的起始值
限制值:当变量值在这个限制范围内时,就能继续进行循环
执行步阶:每一次循环时,变量的变化量
#形式二
for var in con1 con2 con3 ...
do
程序段
done
第一次循环时,$var 的内容为con1
第二次循环时,$var 的内容为con2
第三次循环时,$var 的内容为con3
....
declare
是bash的一个内建命令,可以用来声明shell变量、设置变量的属性。declare
也可以写作typeset
。
declare -i s
代表强制把s变量当做int型参数运算。
- 案例1
#!/bin/bash
#使用declare定义int类型
declare -i sum=0
declare -i i=0
for (( i=0; i<=100; i++ ))
do
sum=$sum+$i;
done
echo "sum=$sum"
- 案例2
#!/bin/bash
#使用declare定义int类型
declare -i sum=0
declare -i i=0
for i in 1 2 3 4 5 6 7 8 9 10
do
sum=$sum+$i;
done
echo "sum=$sum"
- 案例3:扫描当前文件
#!/bin/bash
for fileName in `ls`
do
if [ -d $fileName ]; then
echo "$fileName是文件夹"
elif [ -f $fileName ]; then
echo "$fileName是普通文件"
fi
done
8.4 while
- 语法
while [ condition ]
do
程序段
done
当 condition 成立的时候进入 while 循环,直到condition不成立时才退出循环。
- 案例
#!/bin/bash
declare -i i
declare -i s
while [ "$i" != "101" ]
do
s+=i;
i=i+1;
done
echo "The count is $s"
8.5 until
- 语法
until [ condition ]
do
程序段
done
这种方式与while恰恰相反,当condition成立的时候退出循环,否则继续循环。
- 案例
#!/bin/bash
declare -i i
declare -i s
until [ "$i" = "101" ]
do
s+=i;
i=i+1;
done
echo "The count is $s"
8.6 break continue
- break
break 命令允许跳出循环。
break 通常在进行一些处理后退出循环或case语句
- continue
continue 命令类似于break命令
只有一点重要差别,它不会跳出循环,只是跳过这个循环步
9. 函数
- 语法
定义函数的两种格式:
#格式一:
函数名 () {
命令 ...
}
#格式二:
function 函数名 () {
命令 ...
}
所有函数在使用前必须定义,必须将函数放在脚本开始部分,直至shell解析器首次发现它时,才可以使用
调用函数的格式为:函数名 param1 param2 ...
使用参数同在一般脚本中使用特殊变量$1,$2,$3...$9
一样
函数可以使用return提前结束并带回返回值
return 从函数中返回,用最后状态命令决定返回值。
return 0 无错误返回
return 1 有错误返回
- 案例:求最值
#!/bin/bash
#函数定义
function my_max () {
if [ $1 -gt $2 ]; then
return $1
else
return $2
fi
}
read -p "请输入数值1:" data1
read -p "请输入数值2:" data2
#函数调用
my_max $data1 $data2
echo "$data1和$data2的最大值为:$?"
- 案例:函数分文件
fun.sh
#!/bin/bash
function my_max () {
if [ $1 -gt $2 ]; then
return $1;
else
return $2;
fi
}
15_dzf.sh
#!/bin/bash
#导入函数
source fun.sh
read -p "请输入数值1:" data1
read -p "请输入数值2:" data2
#函数调用
my_max $data1 $data2
echo "$data1和$data2的最大值为:$?"