shell脚本基本使用

与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 "提示词" 变量 #显示提示符

复制代码
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

注:把终端读入空格隔开的第一个单词赋值给第一个变量,第二个单词赋值给第二个变量,依次类推赋值,剩余所有单词赋值给最后一个变量。

2. s h e l l 运算

shell本身不擅长运算,需要借助于运算符和其他的指令

(()) $\[\] expr let

2.1. ( ( ) )
  1. (())几乎支持所有的C语言语法,还支持shell中的幂运算**

  2. ((表达式1, 表达式2, 表达式3, ...)) 每一个表达式都会执行,获取最右侧一个表达式的结果

  3. 想要获取运算的结果,需要使用$(()),还可以((变量名=表达式))

  4. 在(())中,使用变量的值,可以加也可以不加

  5. 在(())中,运算符两侧可以有空格

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 字符串
    字符串的长度
复制代码
#!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计算赋值时作为又值无法识别,需要加上命令识别符号··或者$().并且注意等号右边不能有空格
2.3. let

使用方法:

  1. let 变量名=表达式

  2. let运算时,运算符两侧不能有空格

  3. let中使用变量时,可以加$也可以不加

  4. 如果直接写成let 表达式,表达式会运行,但是没有办法接收

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

可以使用\[\]将test省略,\[\]本质上是一个test命令

4) elif
复制代码
if 表达式1
then
    命令表1
elif 表达式2
then
    命令表2
...
else
    命令表n
fi

-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
相关推荐
丑过三八线8 分钟前
Runc 深度解析:从原理到实操
java·linux·开发语言·docker·容器·rpc
手可摘星辰的少年18 分钟前
Linux字符设备驱动的实现与QEMU验证
linux
手可摘星辰的少年18 分钟前
使用额外ext4磁盘镜像在QEMU中传递与加载内核模块
linux
caimouse34 分钟前
Reactos 第 5 章 进程与线程 — 5.12 进程挂靠
c语言·windows
hai31524754336 分钟前
libcore_final.c —— 九章数流矩阵系统
linux·运维·网络
zh路西法1 小时前
【RDKX5交叉编译】基于 QEMU 的 RDK X5 ARM64 rootfs 镜像定制与 chroot 开发环境搭建
linux
iRayCheung1 小时前
virtualbox安装的ubuntu系统跑numpy报错
linux·ubuntu·numpy
Byte Wizard1 小时前
C语言编译与链接
c语言
Dlrb12111 小时前
Linux系统编程-信号量(线程同步机制)
linux·条件变量·互斥锁·信号量·线程同步
无限进步_1 小时前
Linux进程等待——wait、waitpid与僵尸进程
linux·运维·服务器·开发语言