Linux/C 高级——shell脚本

1. shell脚本基础概念

1.1概念

shell使用方式:手动下命令和脚本
脚本本质是一个文件,文件里面存放的是特定格式的指令,系统可以使用脚本解析器翻译或解析指令并执行(它不需要编译)。

shell脚本本质:shell命令的有序集合,扩展名可以为sh见名知意,也可以没有。

shell 既是应用程序,又是一种脚本语言(应用程序 解析 脚本语言)。

编译型语句:编译器gcc, g++

解释型语句:不需要编译,解释一条执行一条,python、shell脚本。

1.2创建和执行

新建一个shell脚本: touch xx.sh

第一行为: #!/bin/bash

意思是使用/bin/bash来解释执行
执行方式:

  1. sudo chmod 权限 xx.sh #使脚本具有执行权限
  2. ./xx.sh #执行脚本

练习:

1)在当前路径下创建file_1到file_5, 5个普通文件

2)删除 file_2和file_3文件(使用通配符)

3)将剩下的file文件用tar压缩成bz2的格式

4)将压缩文件复制到家目录下

5)进入到家目录解压压缩文件

6)删除压缩包

2.变量

2.1用户自定义变量

名命一般用大写

进行赋值时用=,左右两边不能有空格

引用变量在变量名前面加$

2.2位置变量

0或者{0}代表包含脚本文件名的命令行参数./xx.sh

$1,$2...代表第二个命令行参数、第三个命令行参数以此类推

$# 代表命令行参数个数(不包含第一个也就是带脚本名的命令行参数)

@或者* 代表所有命令行参数(不包含第一个也就是带脚本名的命令行参数)

2.3预定义变量

$? 代表前一个命令的退出状态(0为真,非0为假)

代表执行进程的ID号

2.4环境变量

变量没有类型,都看作是字符串。
环境变量一般是指在操作系统中用来指定操作系统运行环境的一些参数,如:临时文件夹位置和系统文件夹位置等。

HOME: /etc/passwd文件中列出的用户主目录

PATH :shell搜索路径,就是是一系列目录,当执行命令时,linux就在这些目录下查找。

3.功能语句

3.1说明性语句

以#开头
注释用#

3.2功能性语句

3.2.1 read

功能:read从标准输入读入一行,并赋值给后面的变量

格式:read 变量列表

把读入行中的第一个单词赋值给第一个变量,第二个单词赋值给第二个变量以此类推

read -p "提示语句" 变量列表: 可以将提示语句输出,同时输入变量

3.2.2 expr

expr 表达式

注意:表达式符号之间必须有空格,元素引用用$

可以直接输出结果,不过脚本里一般结合命令置换符把结果重新赋值给其他变量

算术运算符命令expr主要用于进行简单的整数运算,包括加(+)、减(-)、乘(\*)、整除(/)和取余数(%)等操作。注意小圆括号()前面也要加转义符\。

例子:

练习1:通过expr实现变量自加运算(++i)

练习2:计算表达式值a*b+c-d/b,a=2,b=3,c=15,d=18

要求:

1)从终端读入4个数a,b,c,d

2)进行运算

3)打印结果输出到终端

复制代码
#!/bin/bash`

`I=0`
`#I=`expr $I + 1``
`((++I ))`
`echo` `$I`

`read -p "input: " a b c d`
`#NUM=`expr $a \* $b + $c - $d / $b``
`((NUM=a*b+c-d/b))`
`#NUM=$((a*b+c-d/b))`
`echo` `$NUM

也可以用(())进行数学运算

3.2.3 let

let 表达式

3.2.4 test

可测试对象三种:字符串 整数 文件属性

每种测试对象都有若干测试操作符

1)字符串的测试:

s1 = s2 测试两个字符串的内容是否完全一样

s1 != s2 测试两个字符串的内容是否有差异

-z s1 测试s1 字符串的长度是否为0

-n s1 测试s1 字符串的长度是否不为0

2)整数的测试:

a -eq b 测试a 与b 是否相等 equal

a -ne b 测试a 与b 是否不相等 not equal

a -gt b 测试a 是否大于b greater than

a -ge b 测试a 是否大于等于b greater equal

a -lt b 测试a 是否小于b litter than

a -le b 测试a 是否小于等于b litter equal

3)文件属性的测试:

-d name 测试name 是否为一个目录

-f name 测试name 是否为普通文件

-e name 测试文件是否存在

复制代码
#!/bin/bash`

`#测试字符串`
`VAR="hello"`
`test` `$VAR` `=` `"hello"`
`echo` `$?`

`test` `$VAR` `!=` `"hello"`
`echo` `$?`

`test -z $VAR`
`echo` `$?`

`test -n $VAR`
`echo` `$?`

`#测试整数`
`test` `10 -eq 5`
`echo` `$?`

`test` `10 -ne 5`
`echo` `$?`

`test` `10 -gt 5`
`echo` `$?`

`test` `10 -lt 5`
`echo` `$?`

`#测试文件属性`
`read -p "input filename: " FILE`
`test -e $FILE`
`echo` `$?`

`test -f $FILE`
`echo` `$?`

`test -d $FILE` 
`echo` `$?

3.3结构性语句

3.3.1 if语句

基本结构:

复制代码
`	`if 条件`
	`then`
`		命令表1`
	`else`
`		命令表2`
	`fi

多路分支结构:

复制代码
if 条件1`
`then`
`    命令表1`
`elif 条件2`
`then`
`    命令表2`
`fi

嵌套结构:

复制代码
if 条件1`
`then`
    `if 条件2`
    `then`
`        命令表1`
    `fi`
`else`
`    命令表2`
`fi

例子:

补充操作符:

-o 或运算 例如 [ $a -lt 20 -o $b -gt 100 ] 返回 true

-a 与运算 例如 [ $a -lt 20 -a $b -gt 100 ] 返回 false

! 非运算 例如 [ ! false ] 返回 true

&& 逻辑与 例如 [[ $a -lt 100 && $b -gt 100 ]] 返回 false

|| 逻辑或 例如 [[ $a -lt 100 || $b -gt 100 ]] 返回 true

| 位或 例如 echo $[2|2]

&位与 例如 echo $[2&1]

3.3.2 case语句

格式:

复制代码
case 变量 in`
`模式1)`
`	命令表1`
	`;;`
`模式2)`
`	命令表2`
	`;;`
`*)`
`	命令表n`
	`;;`
`esac

例子:

练习:学生成绩管理系统,用shell中的case实现

90-100:A

80-89:B

70-79:C

60-69:D

<60:不及格

cs 复制代码
#!/bin/bash

read -p "input score: " SCORE
case $SCORE in
100|9[0-9])
    echo "A"
    ;;
8[0-9])
    echo "B"
    ;;
7[0-9])
    echo "C"
    ;;
6[0-9])
    echo "D"
    ;;
[0-9]|[1-5][0-9])
    echo "lost"
    ;;
*)
    echo "input err"
    ;;
esac

3.3.3 for循环

格式:

复制代码
for 变量名 in 单词表`
`do`
`    命令表`
`done

变量依次取单词表中的各个单词, 每取一次单词, 就执行一次循环体中的命令。循环次数由单词表中的单词数确定。命令表中的命令可以是一条, 也可以是由分号或换行符分开的多条。

例子:

for语句的几种书写格式:

1)for i in 1 2 3 4 do....done :

变量i从单词表中取值

2)for i do...done:

变量i从命令行取值,可以省略in单词表

3)for i in {1..10} do...done:

变量i从1-10个数中取值

4)for ((i = 0; i < 10; i++)) do...done:

书写格式类似c语言

3.3.4 while

格式

复制代码
while 命令或表达式`
`do`
`    命令表`
`done

while语句首先测试其后的命令或表达式的值,如果为真,就执行一次循环体中的命令,然后再测试该命令或表达式的值,执行循环体,直到该命令或表达式为假时退出循环。

练习:分别用for和while实现1-10求和

cs 复制代码
#!/bin/bash

i=1
SUM=0
while test $i -le 10
do
    #((SUM=SUM+i))
    #SUM=`expr $SUM + $i`
    let SUM=SUM+i
    ((i++))
done
echo $SUM

SUM=0
##################################
for ((i=1;i<=10;i++))
do
    ((SUM=SUM+i))
done
echo $SUM

3.3.5 循环控制语句

break n: 结束n层循环

continu n: 结束n层的本次循环,继续下一次循环

cs 复制代码
#!/bin/bash

for ((i=0;i<5;i++))
do
    for((j=0;j<5;j++))
    do
        if [ $j -eq 3 ]
        then 
            #break 1
            #break 2
            #continue 1
            continue 2
        fi 
        echo "$i : $j"  #4 2
    done 
done

4.数组

4.1数组的赋值

a. 直接对数组赋值:
arr=(1 2 3 4 5)

b. 把命令行参数赋值给数组:

arr=($1 $2 $3)

c. 把元素赋值给数组:

read a b c

arr=($a $b $c)

d. 给数组元素输入赋值:

read -a arr

4.2数组的调用

${arr[i]} #访问数组元素,数组下标从0开始到n-1结束

arr[i]=10 #对数组元素重新赋值

${arr[@]} #遍历数组

${#arr[@]} #表示数组元素的个数

练习:从终端输入3个整数,输出三个数中的最小值

cs 复制代码
#!/bin/bash

read -a arr
MIN=${arr[0]}
n=${#arr[@]}
for ((i=0;i<n;i++))
do
    if [ $MIN -gt ${arr[i]} ]
    then
        MIN=${arr[i]}
    fi
done
echo $MIN

冒泡排序:

练习:用shell脚本试下以下功能:
判断当前路径下是否存在目录aa,如果不存在创建;遍历当前路径下的文件,如果是普通文件,将文件复制到aa目录下,并计算文件的个数。

cs 复制代码
#!/bin/bash

if [ -d aa ]    #如果当前目录下有aa目录就删除然后创建
then
    rm -r aa 
fi

mkdir aa

num=0
filelist=`ls`    #将当前目录下所有文件赋值给filelist变量
for file in $filelist  #for file in *  #用file遍历当前目录下所有文件
do
    if [ -f $file ]        #如果是普通文件就复制到aa目录下
    then
        cp $file ./aa        
        ((num++))            #计算文件个数
    fi
done
echo $num
相关推荐
好像是个likun8 分钟前
使用docker拉取镜像很慢或者总是超时的问题
运维·docker·容器
南宫生18 分钟前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论
sanguine__35 分钟前
Web APIs学习 (操作DOM BOM)
学习
数据的世界013 小时前
.NET开发人员学习书籍推荐
学习·.net
cominglately3 小时前
centos单机部署seata
linux·运维·centos
魏 无羡3 小时前
linux CentOS系统上卸载docker
linux·kubernetes·centos
CircleMouse3 小时前
Centos7, 使用yum工具,出现 Could not resolve host: mirrorlist.centos.org
linux·运维·服务器·centos
四口鲸鱼爱吃盐3 小时前
CVPR2024 | 通过集成渐近正态分布学习实现强可迁移对抗攻击
学习
Uu_05kkq3 小时前
【C语言1】C语言常见概念(总结复习篇)——库函数、ASCII码、转义字符
c语言·数据结构·算法
Karoku0663 小时前
【k8s集群应用】kubeadm1.20高可用部署(3master)
运维·docker·云原生·容器·kubernetes