与c语言有很大不同。
1.shell脚本编程
第一个shell脚本
shell脚本的本质:命令的集合
linux命令是通过shell解析器去解析的,所以linux命令叫shell命令也没有问题
shell脚本编程:将shell命令结合一些按照一定逻辑集合到一起,写一个.sh文件,实现一个或多个功能,这个脚本不用编译直接执行
C语言文件.c结尾,C++文件.cpp,.C结尾 shell脚本以.sh结尾。
1.1执行脚本的三种方式
1) bash 文件名
通过bash解析器,直接解析脚本
#!/bin/bash ##说明用的是bash解析器
echo hello world #输出hellowoerld
#! /bin/bash
#说明使用的是bash解析器
echo hello world #输出hellowoerld
2)直接运行脚本
需要给脚本添加可执行权限
chmod 777 xx.sh
./xx.sh
//注意这里需要。sh文件前面存在#!bin/bash
3) source 脚本名
不需要给脚本添加可执行权限
source xxx.sh
练习:
练习:
1)在当前路径下创建file_1到file_5,5个普通文件
2)删除 file_2和file_3文件,(使用通配符)
3)将剩下的file文件用tar压缩成bz2的格式
4)将压缩文件复制到家目录下
5)进入到家目录解压压缩文件
6)删除压缩包
#! /bin/bash
#说明使用的是bash解析器
echo hello world #输出hellowoerld
touch file_{1..5}
rm file_[23]
tar -cvjf file.tar.bz2 file_*
cp file.tar.bz2 ~/
cd ~/ #空格也是家目录
tar -xvf file.tar.bz2
rm file.tar.bz2
1.2 shell变量
shell中允许建立变量存储数据,但是不支持数据类型,所有的数据类型都会被解释成字符串
(如:整型、字符、浮点类型),所有赋值给变量的值都解释为一串字符
变量的定义格式:
变量名=值
shell不允许等号两边都不能有空格 也就是说:变量名 = 值是不行的
取shell变量值:$变量名
变量的分类
1.查看已有的系统环境变量
系统配置好的,内置的变量
env或者printenv
2.修改新增环境变量(暂时或者永久)
export变量名=值
//export $HISTSIZE为暂时的修改,
永久生效只需要将这这个命令放到用户主目录下的.bashrc 中,当前用户永久有效。
若放到/etc/bash.bashrc这个文件中所有用户永久有效。
定义一个新的环境变量:
3. 自定义变量
最好大写
YY=hello//YY="hello world"
echo $YY //使用自己定义的变量(环境变量也可以这样显示)
unset变量名-->取消变量的值
变量名=变量的值
变量名='变量的值'
变量名="变量的值"
=两侧不能有空格
'' 内不能使用$展开变量的值
#!/bin/bash
YY=hello
echo $YY
echo ${YY} #与命令置换符号不同,那个是小括号
XX=$YY
echo $XX
unset XX
echo $XX
VAL1="hello"
VAL2="$VAL1 world"
echo $VAL2
VAL2="$VAL1world"
echo $VAL2
VAL2="$VAL1}world"
echo $VAL2
VAL2="${VAL1}world" #VAL2="${VAL 1}world"不行,会赋值错误
echo $VAL2
readonly HH=10
HH=10
访问变量:
$变量名
${变量名}-->为了更好区分变量名的范围
修饰变量的关键字:
unset:清空变量的值,不能清空readonly修饰的变量
readonly:只读变量,值不能更改
local:定义局部变量,只能在函数中使用
位置变量
$0 --->脚本名
$1-$9
{n} ---\>n:大于等于10之后的数如:{11}
$# --->获取所有外部参数的个数(不包含脚本名)
$* 或者 $@ --->获取到所有的外部参数(不包含脚本名)
预定义变量
$?获取的是上一条命令是否错误的执行结果
0:不是错误的(正确的) 非0:是错误的
获取进程pid echo $1 #输出第一个位置变量 echo $3 #输出第3个位置变量 echo ${10} #输出第十个位置变量 echo $# #输出所有位置变量的个数 echo $* #输出所有位置变量 echo $@ #输出所有位置变量 echo $$ #预定义变量,输出进程PID echo $? #预定义变量,输出上一个程序输出结果是否正确 ### **1.3 shell中的语句** #### 1) 说明性语句 以#号开始到改行结束,不被解释执行 #!/bin/bash告诉操作系统使用哪种解析器的shell执行此脚本文件 后面最好别加其他东西,否则会被同样识别成#!bin/bash 这一行的东西 #### 2) 功能性语句 任意的shell命令、用户程序或其它shell程序 ##### 1. read (类似c中scanf) 从终端获取值赋值给变量 格式:read 变量名1 变量名2 read -p "提示词" 变量 #显示提示符 ![](https://img-blog.csdnimg.cn/img_convert/5d28a99318f2621d89b00c868b4f50f2.png) read -s 变量名 #输入信息不回显 read -t n 变量名 #输入秒数,n秒后还没输入自动切换到下一行命令 read -n n 变量名 #最多识别n个数,然后自动识别下一行 read -s 变量 ---\> 输入的信息不回显 read -t 秒数 变量 ---\> 如果用户n秒不输入,就结束输入向后执行语句 read -n 个数 变量名 ---\> 如果输入n个字符,自动停止 1、尝试将read的四个参数结合起来使用 需要保证对应的参数跟指定的提示信息即可,-s可以和任意参数拼接在一起 read -p "请在3秒钟之内输入最多一个3位数:" -t 3 -n 3 VAL 注:把终端读入空格隔开的第一个单词赋值给第一个变量,第二个单词赋值给第二个变量,依次类推赋值,剩余所有单词赋值给最后一个变量。 ![](https://img-blog.csdnimg.cn/img_convert/0523750a5d7bef514040d459f68def2a.png) ##### 2. **s** **h** **e** **l** **l** **中** **的** **运算** shell本身不擅长运算,需要借助于运算符和其他的指令 (()) $\[\] expr let ###### 2.1. **(** **(** **)** **)** 1. (())几乎支持所有的C语言语法,还支持shell中的幂运算\*\* 2. ((表达式1, 表达式2, 表达式3, ...)) 每一个表达式都会执行,获取最右侧一个表达式的结果 3. 想要获取运算的结果,需要使用$(()),还可以((变量名=表达式)) 4. 在(())中,使用变量的值,可以加$也可以不加$ 5. 在(())中,运算符两侧可以有空格 ![](https://img-blog.csdnimg.cn/img_convert/abdc6053a00ee557740111da10354693.png) ###### 2.2 expr运算 ###### **expr进行算数运算** ARG1 | ARG2 若ARG1 的值不为0,返回ARG1,否则返回ARG2 ARG1 & ARG2 若两边的值都不为0,则返回ARG1,否则返回 0 ARG1 < ARG2 ARG1 小于ARG2 ARG1 <= ARG2 ARG1 小于或等于ARG2 ARG1 = ARG2 ARG1 等于ARG2 ARG1 != ARG2 ARG1 不等于ARG2 ARG1 >= ARG2 ARG1 大于或等于ARG2 ARG1 > ARG2 ARG1 大于ARG2 ARG1 + ARG2 计算 ARG1 与ARG2 相加之和 ARG1 - ARG2 计算 ARG1 与ARG2 相减之差 ARG1 * ARG2 计算 ARG1 与ARG2 相乘之积 ARG1 / ARG2 计算 ARG1 与ARG2 相除之商 ARG1 % ARG2 计算 ARG1 与ARG2 相除之余数 ###### **expr可以进行的字符串运算** match 字符串 表达式 substr 字符串 偏移量 长度 index 字符串 字符 返回字符在字符串中第一次被查找到时的下标,下标从1开始 length 字符串 字符串的长度 ![](https://img-blog.csdnimg.cn/img_convert/472f8c7ae54c16e221a0627ea75ee4b7.png) #!bin/bash VAL1=10 VAL2=20 expr \( $VAL1 + $VAL2 \) \* 3 NUM=`expr $VAL1 + $VAL2` echo $NUM NUM2=$((VAL1+VAL2)) echo $NUM2 CH1="hello world" CH2="hello" expr match "hello world" "hello w" expr match "$CH1" $CH2 expr substr "$CH1" 7 5 #识别第7个字符后面5位 expr index "$CH1" le #识别le中先出现的字符位置 expr length "$CH1" 易错点: 1. (())功能语句赋值时必须为NUM=$(())格式,NUM=$之间不允许有空格,功能语句(())赋值时前面必须带上$符号 2. expr计算赋值时作为又值无法识别,需要加上命令识别符号··或者$().并且注意等号右边不能有空格 3. ###### 2.3. **let** 使用方法: 1. let 变量名=表达式 2. let运算时,运算符两侧不能有空格 3. let中使用变量时,可以加$也可以不加 4. 如果直接写成**let 表达式**,表达式会运行,但是没有办法接收 ![](https://img-blog.csdnimg.cn/img_convert/39281b5b5eb4fc8d1b46caac8dab9867.png) ##### 3. **test** test语句可以测试三种对象: 字符串、整数、文件属性 每种测试对象都有若干个测试操作符 ###### 3.1. **字符串测试** s1 = s2 测试两个字符串的内容是否完全一样 test "hello" = "world" echo $? # 1 相等为真,不相等为假 s1 != s2 测试两个字符串的内容是否有差异 test "hello" != "world" echo $? # 0 相等为假,不相等为真 -z s1 测试字符串的长度是否为0 test -z "" echo $? # 0 字符串没有长度,则为真 test -z "hello" echo $? # 1 字符串有长度,则为假 -n s1 测试字符串的长度是否不为0 test -n "" echo $? # 1 字符串没有长度,则为假 test -n "hello" echo $? # 0 字符串有长度,则为真 #!bin/bash NUM=10 let sum=NUM++ echo $NUM echo $sum test "hello" = "world" echo $? test "hello" != "world" echo $? test -z "" #字符串长度是不是0 echo $? test -z "hello" echo $? test -n "hello" echo $? test -n "" echo $? ###### 3.2. **整数的测试:** a -eq b 测试a和b是否相等 equal read A B test $A -eq $B echo $? # 如果两个数相等则为真,反之为假 a -ne b 测试a和b是否不相等 not equal read A B test $A -ne $B echo $? # 如果两个数不相等则为真,反之为假 a -gt b 测试a是否大于b greater than read A B test $A -gt $B echo $? # 如果a大于b则为真,反之为假 a -ge b 测试a是否大于等于b greater equal than read A B test $A -gt $B echo $? # 如果a大于等于b则为真,反之为假 a -lt b 测试a是否小于b less than read A B test $A -lt $B echo $? # 如果a小于b则为真,反之为假 a -le b 测试a是否小于等于b less equal than read A B test $A -le $B echo $? # 如果a小于等于b则为真,反之为假 #!bin/bash # 整数的比较 read -p "请输入2个整数,下面对他们进行比较,成功输出0:" a b test $a -eq $b #a是否等于b echo $? test $a -ne $b #a是否不等于b echo $? test $a -gt $b #a是否大于b echo $? test $a -ge $b #a是否大于等于b echo $? test $a -lt $b echo $? test $a -le $b echo $? ###### 3.3. **文件属性测试:** -d name 测试name是否为一个目录 read FILE test -d $FILE echo $? # 如果name是目录则为真,反之为假 -f name 测试name是否为一个普通文件 read FILE test -f $FILE echo $? # 如果name是普通文件则为真,反之为假 -e name 测试name文件是否存在 read FILE test -e $FILE echo $? # 如果文件或目录存在则为真,反之为假 补充: FILE1 -nt FILE2:1的时间戳比2的更新 FILE1 -ot FILE2:1的时间戳比2的更旧 -b FILE:文件存在且是一个块设备文件 -c FILE:文件存在且是一个字符设备文件 -d FILE:文件存在且是一个目录设备文件 -f FILE:文件存在且是一个普通文件 -e FILE:文件存在 -h\-L FILE:文件存在且为软链接文件 -s FILE:文件存在且大小不为0 -S FILE:文件存在且是一个套接字文件 -p FILE:文件存在且是一个管道文件 -w FILE:文件存在且有可写权限 -r FILE:文件存在且有可读权限 -x FILE:文件存在且有可执行权限 #### 3) 结构性语句 ##### **if .. then .. fi** ###### 1) 基本结构 if 表达式 then 命令表 fi ###### 2) **分层结构** if 表达式 then 命令表1 else 命令表2 fi ###### 3) **嵌套结构** if 表达式 then if 表达式 then 命令表 fi else 命令表 fi ![](https://img-blog.csdnimg.cn/img_convert/5a7550240cd0b1b718b7b1f37626ffbb.png) 可以使用\[\]将test省略,\[\]本质上是一个test命令 ![](https://img-blog.csdnimg.cn/img_convert/d50d71db73b7a03a88deda8fac984821.png) ###### 4) **elif** if 表达式1 then 命令表1 elif 表达式2 then 命令表2 ... else 命令表n fi ![](https://img-blog.csdnimg.cn/img_convert/1d1b34baeaefb3b48bf1da59883b9e59.png) -a 与运算 \[ $a -lt 100 -a $b -gt 100 \] 有一假返回false -o 或运算 \[ $a -lt 100 \|\| $b -gt 100 \] 有一真返回true ! 非运算 例如 \[ ! false \] 返回 true \&\& 逻辑与 例如 \[\[ $a -lt 100 \&\& $b -gt 100 \]\] 有一假返回false \|\| 逻辑或 例如 \[\[ $a -lt 100 \|\| $b -gt 100 \]\] 有一真返回true \| 位或 例如 echo $\[2\|2\] \& 位与 例如 echo $\[2\&1\] #!bin/bash read FILE if test -e $FILE then echo "$FILE 文件存在" if test -d $FILE then echo "该文件是目录文件" elif [ -f $FILE ] then echo "${FILE}文件是普通文件" else echo "该文件不是目录文件" fi else echo "文件不存在" fi