shell脚本相关知识点

  1. 执行方式

方式1: ./脚本名

方式2: bash 脚本名

方式3: source 脚本名

三种执行方式的区别:

1. ./脚本名的方式需要加执行权限(chmod u+x 脚本名) 其他两种不需要执行权限。

2. ./脚本名 和 bash 脚本名 方式执行时,是在后台打开了一个新的终端(我们看不到)来执行脚本,并将执行结果返回给当前终端,而source 脚本名 方式执行,是在当前终端执行的。

  1. shell中的变量

2.1 特点

shell中使用变量时无需提前定义,直接使用即可。

shell中的变量默认都是字符串类型,就没有整型、浮点型、字符型之分

shell中的变量也要符合标识符的命名规范:

1.数字、字母、下划线组成

2.不能以数字开头

3.不能和shell的关键字冲突(ls cd pwd..)

shell中使用变量时,一般情况下变量名都大写

shell中每条指令结束不需要加分号

2.2 引用变量的值

$变量名 或者 ${变量名}

注意千万不能写成 $(变量名) 这种写法是命令置换符。

清空变量的值:unset 变量名 。

  1. shell中的位置变量

位置变量相当于C语言中 main函数的参数

$0

$0 脚本名 三种不同的执行方式 $0 也不一样

./方式执行 ---》 ./脚本名

bash方式执行 --》 脚本名

source方式执行 --》 bash

$1~$9

表示执行脚本时 在命令行传的 第1到第9个参数

如果参数超过9个 就需要用 ${} 了

如 ${10} ${27}

$@ 表示执行脚本时 在命令行传的 所有参数

$* 表示执行脚本时 在命令行传的 所有参数

$# 表示执行脚本时 在命令行传的所有参数的个数

$$ 执行脚本的进程号

$? 表示上一条命令是否执行成功 (成功 0 失败 1)

  1. 变量的作用域

shell中如果没有特殊说明,变量的作用域都是全局的

如果想声明局部使用 需要使用关键字 local 来声明

例:

#!/bin/bash

#shell中的函数定义

function my_func(){

VALUE1=hello

local VALUE2=beijing

}

my_func #shell中的函数调用

echo $VALUE1 #hello

echo $VALUE2 #空的

  1. 只读变量

使用 readonly 关键修饰的变量都是只读变量

  1. 命令置换符

作用:将命令执行的结果赋值给变量

`` 注意:这个不是单引号 这是反引号 键盘上1前面的按键

$()

例:

#!/bin/bash

LIST1=`ls`

echo $LIST1

LIST2=$(pwd)

echo $LIST2

  1. 字符串的截取

STRING1=www.hqyj.com //从前往后是0开始,从后往前是1开始。

STRING2=${STRING1:4} #从STRING1第4位开始 一直截取到最后。

echo $STRING2 #hqyj.com

STRING3=${STRING1:4:4} #从STRING1第4位开始 截取4个字符

echo $STRING3 #hqyj

STRING4=${STRING1:0-6} #从STRING1的倒数第6位 一直截取到最后

echo $STRING4 #yj.com

STRING5=${STRING1:0-6:2} #从STRING1的倒数第6位 截取2个字符

echo $STRING5 #yj

  1. shell中的数组

shell只有一维数组,shell中的数组用 () 来表示

shell中的数组也是无需提前定义 直接使用即可

shell中的数组也是没有类型的 默认都是 字符串

ARR1=(aa bb 'cc' "hello" 123 world) #完全初始化

ARR2=([0]="hello" [3]="world") #不完全初始化 没有初始化的元素就是空的

#给数组元素重新赋值

ARR1[0]="hqyj"

#获取数组元素的值

# ${数组名[下标]}

echo ${ARR1[0]} #hqyj

echo ${ARR1[3]} #hello

#获取数组中所有元素

${数组名[@]}

${数组名[*]}

echo ${ARR1[@]}

echo ${ARR1[*]}

#获取数组元素的个数

${#数组名[@]}

${#数组名[*]}

echo ${#ARR1[@]} #6

echo ${#ARR1[*]} #6

echo ${#ARR2[*]} #2

#数组元素的追加

ARR3=(aa bb cc)

echo ${ARR3[@]}

ARR3=(${ARR3[@]} "hello" 'world') #在后面追加

echo ${ARR3[@]}

ARR3=(beijing ${ARR3[@]}) #在前面追加

echo ${ARR3[@]}

  1. shell中的输入和输出

9.1 输出--echo

echo有些类似于 printf

例:

V1=hello

echo $V1 #echo是自带换行符的

echo "hello world"

V2=beijing

echo $V1 $V2 #可以一行输出多个值

#默认是不识别转义字符 \n 的 如果需要识别 得加 -e 选项

echo -e "hello\nworld"

9.2 输入--read

(1)read用法类似于scanf,多个变量输入时 用空格分隔,如果要输入的值 本身就有空格,建议写多行 read 指令分别获取,否则有冲突;

(2)如果要输入数组 需要加 -a 选项,输入时要用空格分隔数组元素;

(3)-p 可以加描述字段,用作输入的提示,用“ ”标注内容;

(4)read -n 5 表示最多只获取5个字符,输入5个字符时,即使不敲回车,也会继续向下执行;

(5)read -t 5 表示等待输入时只等待 5秒,超过5秒没输入,程序就会继续向下执行

(6)read -s 表示取消输入的回显;

(7)多个选项可以同时使用,但是要注意:选项和参数必须成对存在。

  1. shell中的运算符

shell本身使用来批量执行命令的,而不是用来做复杂运算的,如果需要用到复杂的运算,可以使用shell调用C程序来处理问题,但是在一些场景下,简单的运算如果也调用C程序处理的话,程序会冗长,比如:计数变量的自增。这时,就可以用shell中的运算符来做一些简单的运算。

shell中如果不使用运算符直接运算,那么默认都会将变量按字符串处理。

shell中的运算符:

(1) (()) 推荐使用

(2) $[]

(3) let

(4) expr

上述四种运算符的执行效率从上到下是依次递减的,其中expr可以做字符串处理。

10.1 (())

格式:((表达式))、((表达式1, 表达式2, ..., 表达式n))

当有多个表达式的时候,每个表达式都会参与运算,而最后一个表达式的结果,就是整个(())运算符表达式的结果。

注意事项:

1.在(())内部,引用变量值的时候,$ 可加可不加;

2.在(())内部,运算符前后的空格,可加可不加;

3.如果想获取表达式的结果 需要在整个(())前加 $ 如 $((A+B));

4.可以做复杂的运算,如 ++ -- for循环;

for((i=0; i<100; i++))

10.2 $[]

格式:$[表达式]、$[表达式1, 表达式2, ..., 表达式n]

当有多个表达式的时候,每个表达式都会参与运算,最后一个表达式的结果,就是整个$[]运算符表达式的结果。

注意事项:

1.在$[]内部,引用变量值的时候,$ 可加可不加;

2.在$[]内部,运算符前后的空格,可加可不加;

3.$[]表达式的结果必须要有变量来接,或者输出到终端,否则报错

$[A+B] 这种格式是错误的 RET=$[A+B] echo $[A+B]

4.不可以做复杂的运算

$[i=0; i<100; i++] #错误的写法

10.3 expr

1.在expr内部,引用变量值的时候,$ 必须加;

2.在expr内部,运算符前后的空格,必须加;

3.expr会自动将运算的结果输出到终端;

4.如果想获取expr的结果,需要用命令置换符 $() 或者 `` ; ret= `expr $v1 + 1`

5.expr不能做复杂的运算 如 ++ -- ,但是可以用其他的写法实现++的功能,如 V1=`expr $V1 + 1`;

  1. expr在做乘法运算的时候 * 要写成 \*。

10.4 let

格式:let 表达式1 表达式2 ... 表达式n //中间用空格分隔

注意:let必须是完整的算术表达式,即有等号两边

如 let C=A+B 正确

C=`let A+B` 错误

1.let会运算所有的表达式:

VAR1=30

VAR2=25

let RET=VAR1+VAR2

RET=RET+VAR1

echo $RET #85

2.let中变量可以加$,也可以不加$;

3.运算符的前后不能加空格。

  1. shell中的 if 语句(很重要)

11.1 格式

if [ 表达式1 ] #注意:if和[ 之间 [] 和表达式之间 都必须有空格

then

分支1

elif [ 表达式2 ] #注意:elif和[ 之间 [] 和表达式之间 都必须有空格

then

分支2

else #else后面没有 then

其他分支

fi

11.2 对字符串的判断

其作用类似于strcmp。

注意:对字符串的判断最好加双引号,否则如果参与判断的字符串中有空格就会报错。

-z 判断字符串是否为空

-n 判断字符串是否为非空

==或者= 判断字符串是否相等

!= 判断字符串是否不相等

\> 判断字符串的大小 大于

\< 判断字符串的大小 小于

拓展:

< 和 << 输入重定向符

> 和 >> 输出重定向符

> 覆盖写

>> 追加写

11.3 将字符串按整型方式判断

-gt 大于 great than

-lt 小于(小写的L) less than

-eq 等于 equal

-ge 大于等于 great equal

-le 小于等于 less equal

-ne 不等于 not equal

逻辑运算

-a 逻辑与 and

-o 逻辑或 or

! 逻辑非

关于逻辑运算符,以逻辑与为例:

在两个 [] 之间要用 &&

在一个 [] 内部要用 -a

11.4 判断文件的类型

-e 判断文件是否存在 存在为真 不存在为假

-s 判断文件是否存在,并判断文件是否为非空,非空为真 空为假

-b 判断文件是否存在,并且判断文件是否为块设备文件

-S (大写)判断文件是否存在,并且判断文件是否为套接字文件

-p 判断文件是否存在,并且判断文件是否为管道文件

-f 判断文件是否存在,并且判断文件是否为普通文件

-L (大写)判断文件是否存在,并且判断文件是否为软链接文件

-c 判断文件是否存在,并且判断文件是否为字符设备文件

-d 判断文件是否存在,并且判断文件是否为目录文件

注意:

判断类型时,要先判断链接文件,

因为链接文件的类型既算是链接文件 也算是他链接的文件的类型

所以先判断链接文件,是因为其他文件不会被识别成链接文件

11.5 判断文件的权限

-r 判断文件是否存在,并判断是否有读权限

-w 判断文件是否存在,并判断是否有写权限

-x 判断文件是否存在,并判断是否有执行权限

注意:哪个用户来执行脚本,判断的就是改基本对哪个用户的权限

11.6 判断文件的时间戳

时间戳:文件最后一次修改的时间

-nt 判断前面文件的时间戳是否比后面的新 new than

-ot 判断前面文件的时间戳是否比后面的旧 old than

注意:离当前时间越近,时间戳越新。

11.7 判断文件的inode号

使用 stat 文件名 可以查看文件的inode号

只有硬链接文件 inode 号才相同

-ef 相同为真 不同为假

  1. case..in 语句

12.1 格式

case $变量 in

选项1)

分支1

;;

选项2)

分支2

;;

选项n)

分支n

;;

*)

其他分支

;;

esac

注意:

case 后面一定是变量的值 也就是说变量名前一定有 $

选项中的值就是case后面的变量所有可能的结果

* 选项表示其他分支,相当于switch..case中的 default分支

12.2 关于case的选项

选项是支持通配符的

[0-9] 通配0-9中的任意一个字符

[a-zA-Z] 通配 a-zA-Z中的任意一个字符 注意 涉及本地语序 LC_ALL=C

"aa"|"bb"|"cc" 通过 aa 或者 bb 或者 cc

[abc] 通配[abc]中的任意一个字符

[^abc] 通配除了[abc]中的任意一个字符。。。这种写法逻辑是反的,基本不使用。

  1. shell中的while循环

13.1 格式

while 表达式

do

循环体

done

其中表达式的用法和 if 的表达式一样

  1. shell中的for循环

14.1 C风格的for循环

for ((i=0;i<10;i++))

do

循环体

done

14.2 shell中特有的for循环

格式

for 变量 in 单词列表

do

循环体

done

关于单词列表:

1.单词列表中的单词用空格分隔;

2.如果单词列表是连续的,可以使用 {start..end} 如 {1..100}

也可以使用序列来处理 `seq 1 100` #遍历 [1, 100];

也可以按照一定的间隔取数据 `seq 1 2 100` #从1开始取数据 步长为2 到100结束;

3.单词列表也可以是命令的结果(只要命令的结果是以空格分隔的就可以);

4.省略 in 的 for循环,这时 变量的值来自于执行脚本时 命令行的参数。

  1. shell中的select..in语句

select 变量 in 单词列表

do

语句

done

select 会将单词列表生成一个可供用户选择的列表:

1) aa

2) bb

3) cc

#? //用户选择的时候,要通过编号来选择,不能通过单词来选择

其中 #? 是可以改的 修改环境变量 PS3

如 export PS3="input>>"

实际使用的时候 select..in 语句一般都和 case..in 语句连用,例:

select i in `ls`

do

#配合着case..in 可以根据用户的选择不同 走不同的逻辑

case $i in

"01test.sh")

echo "1111"

;;

"02test.sh")

echo "2222"

;;

*)

echo "other"

;;

esac

break

done

  1. shell中的break和continue

break 结束本层的循环

break n n是一个数字 结束n层循环

continue 结束本层的本地循环

continue n n是一个数字 结束n层的本次循环

  1. shell中的函数

17.1 定义函数的格式

#注意 function可以不写 但是建议写上 方便阅读

function 函数名(){

函数体

}

1.shell中的函数是没有参数列表的

2.shell中的函数也没有返回值类型

3.shell中定义函数使用function关键字,function是可以不写的

4.shell中函数名也是标识符 要符合命名规范

5.shell中的函数如果没有被调用 是不会执行的

17.2 函数的调用

没有参数:函数名

有参数的:函数名 参数1 参数2 ... 用空格分隔

17.3 函数内部使用参数

函数内部通过位置变量来使用参数

$0 脚本名

$1~$9 调用函数时给函数传递的第1个到第9个参数

${10} 9个以上的 必须要用 {}

如果是将命令行的所有参数传递给函数

$@ $* "$@" 将命令行的参数原封不动的逐个的作为参数传递给函数

"$*" 将命令行的参数作为一个整体传递给函数

在函数内部使用 $1 获取到的就是命令行的所有参数

17.4 函数的返回值

1.shell中的变量默认都是全局的,函数内部定义的变量在任何位置都可以访问,只要不加local关键字修饰的就可以,所以可以使用全局变量来处理函数的返回值;

2.可以使用return的方式来返回函数运行的结果,但是要注意,使用return返回的值 只能是 [0,255] 范围内的函数的调用处可以使用 $? 来接收函数的返回值

3.可以使用echo来返回函数运行的结果,在调用处调用函数需要用命令置换符 `` $(),而且要注意 函数中所有的echo都会当做返回值处理,所以这种写法一般只允许函数中有一个 echo。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值