【Linux】提升工作效率必备技能shell脚本(建议收藏,方便查看)

shell编程

快速入门

初识

shell是我们通过命令行与操作系统沟通的语言。

shell脚本可以直接在命令行中执行,也可以将一套逻辑组织成一个文件,方便复用。

Linux中常见的shell脚本有很多:

  • Bourne Shell(/usr/bin/sh或/bin/sh)
  • Bourne Again Shell(/bin/bash)
  • C Shell(/usr/bin/csh)
  • K Shell(/usr/bin/ksh)
  • zsh

但是Linux系统中一般默认使用bash

脚本格式

1.脚本需要以#!/bin/bash开头

2.脚本需要可执行权限

脚本的常用执行方式

方式一:输入脚本的相对路径或者绝对路径

前提要求是:必须要给脚本增加可执行权限

方式二:sh(bash) + 脚本

这个可以不用给脚本可执行权限

创建第一个Shell脚本

# 创建一个文件
vim hello.sh

# vim中编辑的内容
#!/bin/bash
echo "hello world"

# 两种方式运行
# 第一种方式
sh hello.py
# 第二种方式
chmod u+x hello.sh
./hello.sh # 这里使用相对路径,也可以使用绝对路径

shell变量

shell变量的介绍

1.Linux Shell中的变量分为:系统变量和用户自定义变量

2.系统变量:$HOME $SHELL $UESR等等

3.显示当前shell中所用的变量:set命令

shell变量的定义

基本语法

1、定义变量:变量=数值注意:等号两边不能加空格

1.1变量定义的3中方式

name1='zhy'  # 单引号定义字符串
name2="zhy"	 # 双引号定义字符串
name3=zhy    # 也可以不加引号,同样表示字符串

1.2使用变量

使用变量的时候需要加上$符号,或者${}。花括号是可选的,主要是为了帮助解释器识别变量的边界。

name=zhy    
echo $name      # zhy
echo ${name}    # zhy
echo ${name}ALG # zhyALG
echo $name ALG  # zhy ALG
echo $nameALG   # 错误

2、删除变量:unset 变量

name=zhy
unset name
echo $name # 输出空

3、声明静态变量:readonly 变量名或者declare -r 变量名,注意:静态变量不可以unset

name=zhy
readonly name   # 写法1
declare -r name # 写法2

name=abc        # 报错

4、将指令/命令的返回值赋值给变量,可以使用 反引号或者$()

案例

1.定义变量A,并赋值为666,打印变量A,撤销变量A

2.定义变量B,并赋值为888,打印并撤销

#!/bin/bash 
A=666
echo A=$A # 输出A=666
echo "A=$A" # 这两种输出方式都可以
unset A
echo A=$A # 输出A=  (这里无输出)

readonly B=888
echo B=$B # 输出B=888

​ 3.将date指令的返回值赋值给变量C

#!/bin/bash
# 两种方式
C=`date`
C=$(date)
变量类型之设置环境变量

变量有两种类型:

1.自定义类型变量(局部变量)

子进程不能访问的变量

2.环境变量(全局变量)

子进程可以访问的变量

基本语法

1.将自定义变量改成环境变量

1.1.export 变量名=变量值(设置shell的环境变量/全局变量),或者declare -x 变量名

1.2.source 配置文件 (让修改后的配置文件立刻生效)

name=zhy        # 定义变量
# 第一种方式
export name     # 也可以直接写成一行,即export name=zhy
# 这里需要 source 文件名

# 第二种方式
declare -x name 

2.将环境变量改成自定义变量

2.1declare +x 变量名

export name=zhy # 创建一个环境变量
declare +x name # 设置成为自定义变量

案例

1.在/home 中创建一个文件homepath设置环境变量HOMEPATH

2.查看HOMEPATH环境变量

3.在shell程序中查看环境变量

cd /home
vim homepath

#!/bin/bash
export HOMEPATH=/home # 设置环境变量

source homepath # 刷新配置文件

echo $HOMEPATH # 查看环境变量

# 在一个shell脚本中查看环境变量
vim a.sh
echo HOMEPATH=$HOMEPATH
sh a.sh

shell字符串

shell中的变量其实都是字符串,所以需要了解一下字符串的使用方法和注意事项

1.字符串使用单引号、双引号均可。区别在于单引号‘’中间的内容不会执行,不会转义。双引号“”中间的内容会执行,会转义。(前面说了不加引号也可以定义变量,而不加引号的效果同加了双引号)

name=zhy
echo 'hello $name \"ALG\"'  # hello $name \"ALG\"
echo "hello $name \"ALG\""  # hello zhy "ALG"
echo hello $name \"ALG\"    # hello zhy "ALG"

2.获取字符串长度,${#变量名}

name=zhy
echo ${#name}  # 3

3.提取字符串,${变量名:left:right}(提取从left到right中间的字符)

name="hello zhy!"
echo ${name:6:9}  # zhy

shell变量定义规范

1.变量名称可以由字母、 数字和下划线组成,但是不能以数字开头。5A= 200(x)
2.等号两侧不能有空格
3.变量名称一般习惯为大写,这是一个规范,我们遵守即可

shell注释

  • 单行注释

    # 我是一个单行注释
    
    
  • 多行注释

    :<<!
    我是
    一个
    多行注释
    !
    
    

默认变量-文件参数变量

初识

当我们执行一个shell脚本时 ,如果希望获取到命令行的参数信息,就可以使用到位置参数变量
比如: ./myshell.sh 100 200,这个就是一个执行shell的命令行 ,可以在myshell脚本中获取到参数
信息

基本语法

在执行shell脚本时,可以向脚本传递参数。$1是第一个参数,$2是第二个参数,以此类推。特殊的,$0是文件名(包含路径)。

参数说明
$nn为数字,特殊的,$0是文件名(包含路径), $1~$9表示第一个参数到第九个参数,十以上的参数需要使用大括号包含,如${15}
$#代表文件传入的参数个数
$*表示命令行中所有的参数,$*把所有的参数看成一个整体
$@表示命令行中所有的参数,$@把所有的参数当做单独的参数区别对待
$$脚本当前运行的进程ID
$?上一条命令的退出状态。0表示正常退出,其他值表示错误
$(command)返回command这条命令的stdout
command返回command这条命令的stdout,同$(command)

$n,n为数字,特殊的,$0是文件名(包含路径), $1~$9表示第一个参数到第九个参数,十以上的参数需要使用大括号包含,如${15}

$*,表示命令行中所有的参数,$*把所有的参数看成一个整体

$@,表示命令行中所有的参数,$@把所有的参数当做单独的参数区别对待

$#,表示命令行中参数的个数

案例

编写一个shell脚本pos.sh,在脚本中获取命令行中的各个参数

vim pos.sh

#!/bin/bash
echo "文件名:"$0
echo "第一个参数:"$1
echo "第二个参数:"$2
echo "所有的参数:"$*
echo "所有的参数:"$@
echo "参数的个数:"$#

sh pos.sh 1 2 3

:<<!
输出的内容
文件名:pos.sh
第一个参数:1
第二个参数:2
所有的参数:1 2 3
所有的参数:1 2 3
参数个数:3
!

数组

初识

shell中的数组可以存放多个不同类型的值,但是只支持一维数组初始化时不需要指明数组的大小。而且和其他语言一样数组的下标从0开始

基本语法

1.定义:

有两种方式:

1.1.数组可以直接使用小括号表示,元素之间使用空格隔开。例如:

array=(123 abc "zhy")

1.2.也可以直接定义数组中某一个元素的值,而且可以不用连续的考空间。

array[0]=123
array[1]=abc
array[2]="zhy"
array[666]='ALG' # 可以直接在下标为666的地方定义一个值为'ALG'

2.读取数组中的某一个元素的值:

语法:

${array[index]}

例如:

array=(123 abc "zhy")
echo ${array[0]}
echo ${array[1]}
echo ${array[2]}

3.读取整个数组

语法:

${array[@]} # 第一种方式
${array[*]} # 第二种方式

例如:

array=(123 abc "zhy")

echo ${array[@]} # 第一种方式
echo ${array[*]} # 第二种方式

4.获取数组的长度

语法:

${#array[@]} # 第一种写法
${#array[*]} # 第二种写法

例如:

array=(123 abc "zhy")

echo ${#array[@]} # 第一种写法
echo ${#array[*]} # 第二种写法

运算符

初识

学会在shell中将变量进行计算,就需要运算符

基本语法

有三种方式:

方式一:$((运算式))

注意外面的()不能省略

echo $((1 + 2) + 3)

方式二:$[运算式]

这种方式比较简单,比较推荐

echo $[(1 + 2) + 3]

方式三:expr 运算式(注意这里的运算式和上面的不一样

expr命令

初识

expr命令用户求表达式的值,语法如下:

expr 表达式

表达式注意事项:

1 expr 运算符之间需要有空格,而且必须要是用``(反引号)将计算的值返回

2.用反斜杠放在shell特定的字符前面

3.对包含空格和其他特殊字符的字符串要用引号括起来

4.expr会在stdout中输出结果。如果为逻辑关系表达式,则结果为真,stdout为1,否则为0。

5.expr的exit code:如果为逻辑关系表达式,则结果为真,exit code为0,否则为1。

6.运算符 \*(乘,要注意有一个\),\(除),+(加),-(减)

字符串表达式

1.length STRING

可以返回字符串的长度

str="hello world"
echo `expr length "$str"`

2.index STRING CHAR

CHAR中任意单个字符在STRING中最前面的字符位置,下标从1开始。如果在STRING不存在CHAR中的字符,就返回0。

str="hello world"
echo `expr index "$str" l` # l出现的第一个位置为3

3.substr STRING POSITION LENGHT

返回STRING字符串中从POSITION位置开始(下标从1开始),长度最大为LENGTH的子串。如果POSITION或者LRNGHT为负数,0或者是非数值,就返回空字符串。

str="hello world"
echo `expr substr "%str" 1 5` # 下标从1开始,输出hello

整数表达式

expr支持普通的算术操作,算术表达式优先级低于字符串表达式,高于逻辑关系表达式。

1.+ -加减运算。两端参数会转换为整数,如果转换失败则报错。

2.\* / % 乘,除,取模运算。两端参数会转换为整数,如果转换失败则报错。

3.\(\) 可以该表优先级,但需要用反斜杠转义

例如:

a=1
b=2

echo `expr $a + $b`
echo `expr $a - $b`
echo `expr $a \* $b`   # *需要转义
echo `expr $a / $b`
echo `expr $a % $b`
echo `expr \( $a + $b \) \* 3` # ()需要转义,计算(a+b)*3

逻辑关系表达式

1.|,如果第一个参数非空且非0,则返回第一个参数的值,否则返回第二个参数的值(短路原则)。但要求第二个参数的值也是非空或非0,否则返回0。如果第一个参数是非空或非0时,不会计算第二个参数。

2.&如果两个参数都非空且非0,则返回第一个参数,否则返回0。如果第一个参为0或为空,则不会计算第二个参数。

3.< <= = == != >= >比较两端的参数,如果为true,则返回1,否则返回0。”==”是”=”的同义词。”expr”首先尝试将两端参数转换为整数,并做算术比较,如果转换失败,则按字符集排序规则做字符比较。(使用的时候需要转义或者使用单引号隔开)

4.() 可以该表优先级,但需要用反斜杠转义

a=1
b=2

echo `expr $a \> $b`   #0
echo `expr $a '<' $b`  #1
echo `expr $a \>\= $b` #0
echo `expr $a '<=' $b` #1

c=0
d=3

echo `expr $c \& $d` # 0
echo `expr $d \& $a` # 3
echo `expr $c \| $d` # 3
echo `expr $d \| $a` # 3

案例

1.使用三种方式计算(1 + 2) * 3

#!/bin/bash
# 方式一
ANS1=$(((1 + 2) * 3))
echo "ans1=$ANS1"

# 方式二
ANS2=$[(1 + 2) * 3]
echo "ans2=$ANS2"

# 方式三
TEMP=`expr \( 1 + 2 \) \* 3`
echo "TEMP=$TEMP"

2.求出命令行中的两个参数的和

#!/bin/bash
ANS=$[$1 + $2]
echo ANS

read命令

基本语法即介绍

read命令用于从标准输入中读取单行数据。当读到文件结束符时,exit code为1,否则为0。

当read遇到文件结束符的时候会自动结束,在while循环中可以使用ctrl + d的方式表示文件结束符。

read name
echo $name

可选参数:

-p: 后面可以接提示信息

-t:后面跟秒数,定义输入字符的等待时间,超过等待时间后会自动忽略此命令

案例

定义一个变量name输入,并且设置提示语句和最多等待时间,最后输出在终端上。

read -p "Please Input into your name:" -t 30 name 
echo "hello ${name}!"

echo命令

常见用法

echo用于输出字符串,语法如下:

echo STRING

1、显示字符串

直接echo STIRNG即可,可以使用双引号或者不加引号。注意:不能不加引号

echo "hello world"
echo hello world

2、显示转义字符串

在双引号或者不加引号的情况下,可以输出转义字符。但是如果想要使用\n \t等更多的转义字符,需要使用echo-e选项,才可以使用。

echo " \"hello world\" " # 输出“hello world"
echo \"hello world\" # 输出"hello wordl"

3、显示变量

定义变量,然后$变量使用变量

name=zhy
echo "hello $name"

4、显示换行

使用echo -e输出\n的转义字符,而且必须使用双引号才可以使用。

echo -e "hello \n world"

5、显示不换行

使用echo -e输出\c选项,而且必须使用双引号才可以使用。

echo -e "hello\c "
echo "world"
# 输出 hello world

6、显示结果重定向

可以使用>或者>>方式进行字符串的输入重定向和追加重定向

echo "hello world" > hello.txt # 将字符串的内容覆盖式的加入hello.txt文件当中
echo "Hello World" >> hello.txt # 将字符串的内容添加在hello.txt文件的后面
# 最后得到一个文件hello.txt
# 文件的内容是hello world Hello World

7、原样输出字符串,不进行转义或者取变量

上面说活可以使用双引号或者不加引号的形式形式字符串或者转义字符串。如果使用单引号就可以输出字符串本身。

name=zhy
echo '$name \n' # 输出'$name \n'

8、显示命令的执行结果

使用``或者$() 的方式得到命令的结果

echo `date` # 输出日期

printf命令

和c语言中的printf函数的用法差不多,也是用于格式化输出,但是不需要添加括号。

基本语法

printf format [arguments...]

printf "%d\n" 123 # 输出123
printf "%s\n" zhy # 输出zhy
printf "%d * %d = %d\n" 2 3 `expr 2 \* 3` # 输出2 * 3 = 6

test命令和判断符号[]

逻辑运算符&&和||

&& 表示与,|| 表示或

二者具有短路原则:

  • expr1 && expr2:当expr1为假时,直接忽略expr2。当expr1为真时,才会执行expr2

  • expr1 || expr2:当expr1为真时,直接忽略expr2。当expr1为假时,才会执行expr1

表达式的exit code为0,表示真;为非零,表示假。

注意:exit codestdout不一样,一般在C++/C中的main函数中,最后是以return 0结尾,说明的是这个进程是正常结束的。如果该进程不正常结束,就以非0结尾。

补充:可以使用&&||搭配使用做到if else的条件判断

test -e test.txt && echo "exist" || echo "no exist"

test -e test.txt这个是利用test做出的判断,后面会介绍,其实就是判断test.txt这个文件是否存在。如果文件存在返回0表示真,所以就会执行echo “exist”;如果文件不存在返回1表示假,所以就会不执行echo “exist",然后因为前面都是假,所以最后会执行echo “noexist。这样就是利用test+&& ||使用类似if else的判断。

test命令

test命令用于判断文件类型,以及对变量做比较。

test命令用exit code返回结果,而不是使用stdout。0表示真,非0表示假。

文件类型判断

利用test命令判断文件的类型

格式:

test 选项 filename

选项说明
-e文件是否存在
-f是否为文件
-d是否为目录
文件权限判断

判断一个文件或者目录的权限。

格式:

test 选项 filename

选项说明
-r是否可读
-w是否可写
-x是否可执行
-s是否为非空文件
整数的比较判断

利用test命令判断两个整数之间的关系

格式:

test $a 比较符 $b

比较符说明
-eqa是否等于b
-nea是否不等于b
-lta是否小于b
-gta是否大于b
-lea是否小于等于b
-gea是否大于等于b
字符串的比较判断

利用test命令判断两个字符串之间的比较判断。

参数说明
test -z str判断str是否为空
test -n str判断str是否非空
test str1 == str2判断str1和str2是否相等
test str1 != str2判断str1和str2是否不相等
test str1 \> str2判断str1是否>str2
test str1 \>\= str2判断str1是否>=str2
多重条件判断

利用test命令同时判断两个条件的真假,类似于c/c++中的&& ||

格式:

test 条件1 选项 条件2

选项说明
-a判断两条件是否同时成立
-o判断两条件是否至少一个成立
!取反

[ ]判断命令

[]是一个命令,和test命令用法差不多,更常用于if语句中。另外[[]][]的加强版,支持的特性更多。

例如:

[ 2 -t 3]
echo $? # 输出上一个进程的退出状态.这里输出0

注意:

  • []内的每一项都要用空格隔开,因为[]是一个命令
  • 中括号内的变量,最好用双引号括起来
  • 中括号内的常数,最好用单或双引号括起来

判断语句

if判断

单分支if

语法格式:

if condition
then 
	语句
fi

例如:

if [ 1 -lt 2] && [ 3 -gt 2]
then 
	echo 1最小
fi
# 输出1最小

单分支层if-else

语法格式:

if condition
then
	语句
else
	语句
fi

例如:

a=10
b=20

if [ "$a" -ge "$b" ] || [ "$b" -le "$a" ]
then
	echo "$a"大于"$b"
else
	echo "$a"小于"$b"
fi

多分支判断if-elif-else

语法格式:

if condition
then
	语句
elif
then
	语句
else
	语句
fi

例如:

a=10

if [ $a -eq 1 ]
then
	echo $a==1
elif [ $a -eq 2 ]
then
	echo $a==2
else
	echo $a未知
fi

case判断

语法格式:

case $变量名 in
	...)
		语句
		;;
	...)
		语句
		;;
	*) # 表示默认
		语句
		;;
esac

例如

a=1
case $a in
	1)
		echo "$a == 1"
		;;
	2)
		echo "$a == 2"
		;;
	*)
		echo "$a == $a"
		;;
esac

循环语句

循环语句有3种循环,4中写法

for … in … do … done

将in后面的变量一个一个赋值给in前面的变量,类似于python中的for循环

for var in var1 var2 var3
do
	echo $i
done

例如:

例子1:

for i in 1 a &
do
	echo $i
done
# 输出 1 a &

例子2:

也可以输出,``中命令的返回值。输出当前路径下的所有文件名,每个文件名一行:

for i in `ls`
do
	echo $i
done

例子3:

可以使用seq命令,输出一段范围的数字。

for i in `seq 1 10`
do 
	echo $i
done

例子3:

在文本中可以使用{1..10}这样的语法输出替代seq的作用,而且支持字母。

输出a~z

for i in {a..z}
do
	echo $i
done

for ((…, … , …)) do … done

for循环还有一种写法

for ((expression; condition; expression))
do
    语句
done

例如:

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

while … do … done

语法格式:

while condition
do
    语句
done

例如:

一直输入name,知道遇到文件结束符,ctrl + d

while read name
do
	echo $name
done

untill… do … done

until循环和while循环相反,如果condition为假才继续,为真就停止了。

语法格式:

until condition
do
	语句
done

例如:

当输入yes的时候,才能停止输入

until [ "$word" == yes ]
do
	read -p "please input yes:" word
done

break

跳出当前一层循环,注意与C/C++不同的是:break不能跳出case语句。

例如:

输出1~10,但是到了5就停止

for ((i = 1; i <= 10; i ++))
do 
	if [ $i -eq 5 ]
	then 
		break
	fi
	echo $i
done

continue

跳出当前一次循环。

例如:

输入1~10中间的奇数

for ((i = 1; i <= 10; i ++)) 
do 
	if [ $[$i % 2] == 0 ]
	then 
		continue
	fi
	echo $i
done

处理死循环

1.可以使用top命令找到死循环的进程号PID

2.然后使用kill -9 PID强制结束这个进程

函数

基本语法

bash中的函数类似于C/C++中的函数,但return的返回值与C/C++不同,返回的是exit code,取值为0-2550表示正常结束。

如果想获取函数的输出结果,可以通过echo输出到stdout中,然后通过$(function_name)来获取stdout中的结果。

函数的return值可以通过$?来获取。

语法格式:

func_name () {
	语句
	...
}

例如:

func() {
	name=zhy
	echo $name
}
func # 调用函数不用加(),而是直接像命令一样直接写函数名

获取 return值和stdout值

不写return时,默认return 0。

例如:

func() {
	name=zhy
	echo "hello $name"
	return 100
}

output=$(func) # 使用$()返回nc函数的stdout
returnVal=$?   # 使用$?返回func的返回值

echo "output = $ouput"
echo "returnVal = $returnVal"

函数的输入参数

在函数内,$1表示第一个输入参数,​$2表示第二个输入参数,依此类推。

注意:函数内的$0仍然是文件名,而不是函数名。

例如:

func() {
	for ((i = 0; i <= $1; i ++))
	do
		echo $i
	done
}

echo $(func 10)

函数内的局部变量

可以在函数内定义局部变量,作用范围仅在当前函数内。

可以在递归函数中定义局部变量。

语法格式:

local 变量名=变量值

exit命令

exit命令用来退出当前shell进程,并返回一个退出状态;使用$?可以接收这个退出状态。

exit命令可以接受一个整数值作为参数,代表退出状态。如果不指定,默认状态值是 0。

exit退出状态只能是一个介于 0~255 之间的整数,其中只有 0 表示成功,其它值都表示失败。

if [ $# -eq 1 ]
then 
	eixt 0
else
	exit 1
fi
# 传入一个参数就返回0退出,如果传入的参数参数个数不是1就返回1退出

文件重定向

每个进程默认打开3个文件描述符:

  • stdin标准输入,从命令行读取数据,文件描述符为0

  • stdout标准输出,向命令行输出数据,文件描述符为1

  • stderr标准错误输出,向命令行输出数据,文件描述符为2

可以用文件重定向将这三个文件重定向到其他文件中。

命令说明
command > file将stdout重定向到file中
command < file将stdin重定向到file中
command >> file将stdout以追加方式重定向到file中

例如:

echo "hello world" > tmp.txt
read str < tmp.txt
echo $str

引入外部脚本

类似于C/C++中的include操作,bash也可以引入其他文件中的代码。

语法格式:

. filename
或者
source filename

例如:

创建一个test1.sh

#! /bin/bash
str=hello world

再创建一个test2.sh

#! /bin/bash
source test1.sh
echo $str # 输出hello world

  • 13
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hyzhang_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值