当前位置: 首页 > news >正文

【Linux】3. Shell语言

  本文主要介绍了Shell程序和Shell语言,Shell语言常被用来访问Linux操作系统,因此我们需要简单了解一些关于Shell语言的知识。我们需要重点了解Shell的概念变量,它对我们学习Linux有重要的作用,其中的环境变量更是会影响程序的行为。对于其他运算符、流程控制语句、函数等了解即可(除了专业写Shell脚本的),这些语法与C语言有相似之处,可以在使用时再去查询。

Shell语言

  • 一、Shell的介绍
    • 1. Shell简介
    • 2. Shell脚本的运行
  • 二、注释与输出
    • 1. 注释
    • 2. 输出
  • 三、变量
    • 1. 变量的定义
      • 1.1 变量的定义与使用
      • 1.2 变量类型
    • 2. 特殊变量
    • 3. 环境变量
      • 3.1 常见环境变量
      • 3.2 环境变量的操作命令
      • 3.3 代码中操作环境变量
  • 四、运算符
    • 1. 算数运算
    • 2. 逻辑运算
    • 3. 括号
    • 4. 通配符
    • 5. 字符串与文件运算
  • 五、流程控制语句
    • 1. 分支语句
    • 2. 循环语句
  • 六、函数

一、Shell的介绍

1. Shell简介

  Shell程序、Shell语言和Shell脚本在现实中常会被简称为Shell,这导致很多人对Shell的概念比较混乱,其实它们本质是完全不同的东西。

(1)Shell程序

  Shell程序是一种用C语言编译的程序,是Shell语言的解释器,专门将Shell语言翻译成CPU可以执行的二进制指令。该程序提供了一个界面,可以让用户输入Shell语言命令并解释成Linux操作系统可执行的指令,是用户与Linux操作系统内核沟通的桥梁。

Linux中的Shell程序种类众多,常见的有:

  • Bourne Shell:/usr/bin/sh/bin/sh
  • Bourne Again Shell:/bin/bash,该程序是大多数Linux系统的默认Shell程序。
  • C Shell:/usr/bin/csh
  • K Shell:/usr/bin/ksh
  • Shell for Root:/sbin/sh

注意:

  • Bourne Shell是shell程序的英文叫法,sh才是程序本身的文件名。
  • 由于这些Shell程序都在系统目录里,可以直接使用程序名执行程序。
/bin/sh		# 直接打开sh程序
ksh			# 运行ksh程序

(2)Shell语言

  Shell语言是用户访问Linux操作系统的计算机编程语言,用户在Shell程序中输入Shell语言操作Linux系统。Shell语言是一种解释型语言,即不需要编译成可执行文件,而是在运行时被解释器一条一条翻译成CPU认识的二进制指令并执行。

  我们常用的Linux命令就使用的Shell语言,此外Shell语言也具有变量、流程控制语句等语法。

(3)Shell脚本

  Shell脚本是一种用Shell语言编写的文本文件,可以直接在Shell中执行。由于Shell脚本文件可以直接被Linux环境中的Shell程序执行,就像命令一样,因此也会有人将其称为可执行程序。

​ Shell脚本文件以.sh为后缀。

2. Shell脚本的运行

(1)运行Shell脚本

  • 作为可执行程序直接运行(需要指定文件路径,除非在系统目录下或被添加到环境变量中)。
  • 作为解释器的参数运行,即指定Shell程序运行脚本,此时脚本开头的#!语句会失效。
./test.sh				# 执行./test.sh脚本
/bin/bash ./test.sh		# 用bin/bash执行./test.sh脚本

(2)指定Shell程序

Shell脚本文件开头通常会有一句#! /bin/bash#!用以指定执行该脚本的Shell程序,若是没有则使用默认Shell程序执行。

#! /bin/bash		# 使用/bin/bash程序执行该脚本

(3)包含Shell文件

Shell脚本文件也能像C/C++的头文件一样,被多个源文件引用。在Shell文件中用. 文件路径source命令的方式就能引用其他Shell文件。

. ./test.sh		# 引用./test.sh
source ./a.sh	# 引用./a.sh
  • 注意.的后面有空格,不是紧挨文件路径的。
  • 被引用的shell文件可以不用可执行x权限。

二、注释与输出

1. 注释

(1)单行注释

# 这是一个单行注释

(2)多行注释

  • :<<EOF 注释内容 EOF,其中EOF可以是其他符号,包括!'等。
  • :'注释内容'
:<<EOF
这是一个多行注释
这是一个多行注释
EOF:<<!
这是一个多行注释
这是一个多行注释
!:'
这是一个多行注释
这是一个多行注释
'

2. 输出

在Shell语言中,常使用3中方式将数据输出到控制台、文件或其他命令中。

(1)输出数据到控制台的命令

  1. echo:输出一串字符串(自带换行)。
echo 'abcdef'	# 输出'abcdef'
abcdef
var="23456"
echo $var		# 输出变量var的值
23456
  • -e:启用转义字符。
  • -n:不换行输出。
  1. printf:用法与C语言的printf相似,但是参数都以字符串的形式传输进去,变量需要用$获取值,用空格隔开。
printf "Hello World"
printf "var=%s n=%d\n" "$var" "$n"		# 与C语言的printf("var=%s n=%d\n", var, n);十分相似

printfecho的区别:

  • printf能像C语言一样,控制输出字符串格式。
  • echo自带换行,而printf不自带,需要手动打。

(2)重定向

重定向:将原本输入到A文件的内容,输入到B文件中,这就是将A文件重定向到B文件。

重定向的应用场景举例:

——printf应该将内容打印到标准输出流,我们不想更改代码,但是想让内容打印到txt文件中,就将该程序中printf打印的内容输出到txt文件中了。

——如echo "1234" > file则是将echo原本打印到标准输出流的"1234"写入到file文件里。

  1. 输入、输出、追加重定向

常用的重定向类型有3种:

  • 输出重定向>:将标准输出流重定向到指定文件。输出重定向会覆盖指定文件原有的内容
  • 输入重定向<:将标准输入流重定向到指定文件,即输入到标准输入流的内容都会写入指定文件中。
  • 追加重定向>>:将标准输出流的内容以追加的形式重定向到指定文件,不会覆盖指定文件的内容。
cat hello.cpp > file.txt	# 使用cat打印hello.cpp的内容,并重定向到file.txt中
wc -l < file.txt			# 将wc -l中输入到标准输入流的内容重定向到file.txt中
cat hello.cpp >> file.txt	# 以追加的形式重定向到file.txt中

重定向的本质是更改文件描述符表中的文件地址,如将标准输出流的地址改为file.txt的地址,那么该进程写入标准输出流的内存都会进入file.txt文件里。具体原理在《IO操作》种有说明

  1. 特殊的重定向

<1> 将屏幕输入的内容提供给进程。

wc -l << EOF		# 将EOF包裹的内容作为输入提供给wc命令,EOF可以是其他字符"Hello World"Good Good StudyDay Day Up
EOF					# 这里必须要顶格,不能空格。

<2> /dev/null文件:写入它的内容都会被丢弃,在这个文件里是读取不到内容的。

  • 它可以相当于一个垃圾桶,重定向到该文件可以自动丢弃写入该文件的任何内容。
  • 将某个IO流重定向到这个文件,可以起到屏蔽这个IO流的效果,即往这里输入内存没有效果。
command > /dev/null		# 屏蔽command命令的标准输出流

(3)管道

在Linux中,可以使用管道将进程的输出信息发送给其他进程,使用符号进程A | 进程B(A发送给B)。

cat txt | grep "abcde"	# 将cat txt打印的结果发送给grep进程,让grep进程在打印结果中筛选abcde所在的行

管道的原理在《进程间通信》中说明。

三、变量

Shell语言的变量有3种:

  • 普通变量:也叫局部变量,该变量只能在当前Shell程序中使用,其他Shell程序中无法使用该变量。
  • 环境变量:这些是操作系统或用户设置的特殊变量,用来配置Shell程序的运行环境,会影响Shell命令的行为。
  • 特殊变量:如$0$1$#等特殊符号组成的变量,这些变量通常用来获取该脚本执行时的参数及其他信息等。

1. 变量的定义

1.1 变量的定义与使用

(1)定义变量

var="value"
PI=3.14
readonly PI		# PI被设置为只读变量
  • 变量名和等号直接不能有空格
  • 变量名只能包含字母、数字和下划线,不能以数字开头,避免Shell的关键字。
  • 通常使用大写字母表示常量。等号两侧避免使用空格。
  • 使用readonly关键字定义只读变量,只读变量的值不能改变。

(2)删除变量

unset var		# 删除var变量

(3)获取变量值

使用$符号获取变量值。

echo $var		# 打印var的值
b=${var}		# 将var的值赋值给b变量${var}abc"		# 其中获取var变量的值,若是没有{}就会被识别成获取varabc的值
  • 获取变量值时,建议用{}将变量名包裹起来,方式变量后紧贴着字符时,被识别成其他变量名。

1.2 变量类型

与其他语言一样,Shell语言同样有多种变量类型,但是实际上只有字符串和整型被广泛使用:

(1)字符串

在Shell中变量通常被视为字符串类型,如var=value中的value,也可以使用单引号和双引号来定义字符串。

  • 单引号:单引号里面的任意字符都会被原样输出,里面的变量是无效的,里面不能出现单引号(使用转义字符后也不行),但可以字符串拼接。
  • 双引号:字符串里可以出现变量和转义字符。
'${var}abc'		# var变量不会被识别,${var}会被当成字符串的一部分
'abc\'edf'		# 会出现错误,\'不会被识别成转义字符'
"${var}abc\'def"	# var会被当做变量读取值,\'也会被当成转义字符'

字符串操作

  • 拼接字符串:直接将让多个字符串紧跟着写即可拼接,单引号和双引号字符串均可拼接。
  • 获取字符串长度:${#var}便能获取变量var的字符串长度(var被视为字符数组,${#var}获取数组var的长度)。
  • 截取子串:${var:i:n}在var变量中从下标为i的字符开始,截取n个字符。
var="edf""abc"${var}"ghi"	# 拼接为abcdefghi
${#var}				# 获取变量var的字符串长度
${var:0:2}			# 从下标0开始截2个字符,即ed

(2)整型

整型变量就是整数,为了防止将整数当成字符串,可以使用declare -i [var]来显示定义整型变量。

declare -i var=20	# 定义整型变量var

(3)数组

bash只支持一维数组,不支持多维数组,但没有限制一维数组的大小。

数组的定义有以下3种方式

array1=(value1 value2 value3)array2=(
value1
value2
value3
)array3[0]=value1
array3[1]=value2
array3[9]=value3			# 可以不连续,且大小没有限制

获取数组的值:使用下标获取,若下标为@*则代表获取全部元素。

${array[0]}		# 获取下标为0的元素
${array[@]}		# 获取所有元素

(4)关联数组

关联数组:下标为字符串类型,bash支持关联数组,使用declare -A来定义。

# 定义并赋值
declare -A array1=(["key1"]="value1" ["key2"]="value2" ["key3"]="value3")declare -A array2			# 定义关联数组
array2["key1"]="value1"		# 赋值
array2["key2"]="value2"
array2["key3"]="value3"

获取关联数组的值与普通数组差不多,下标用字符串。

${array["key1"]}
${array["key2"]}
${array["key3"]}

2. 特殊变量

​ 特殊变量用于获取当前Shell脚本文件的参数等信息,执行Shell脚本文件时可以传递参数,这些参数靠特殊变量获取,Shell脚本的其他信息,如进程pid等。

  • $0:表示执行的文件名,包含文件路径。
  • $1$2、…、$n:表示第1个、第2个、……、第n个参数。当n不止一位数时要加上{},如${10}
  • $#:参数的个数。
  • $*:显示所有参数为1个字符串,格式为"$1 $2 $3 ..."。(以$*作为参数传递的是一个字符串参数)
  • $@:显示所有参数,每个参数为1个字符串,"$1" "$2" "$3" …。(以$@作为参数传递的是多个字符串,即多个参数)
  • $$:脚本当前运行的进程的pid
  • $!:后台运行的最后一个进程的pid
  • $?:获取最后一个命令退出的状态(通常在命令结束后紧接着获取该命令的退出码或返回值),0表示没问题,其他表示有错误。
./test.sh t1 t2 -t3 t4 t5	# 执行./test.sh脚本,参数为t1 t2 -t3 t4 t5# ./test.sh中获取当前的参数等信息
$0		# 显示test.sh的路径和文件名
$1		# 第一个参数,即t1
$#		# 参数个数,即5
$*		# 全部参数为一个字符串,即"t1 t2 -t3 t4 t5"
$@		# 全部参数为多个字符串,即"t1" "t2" "-t3" "t4" "t5"

3. 环境变量

3.1 常见环境变量

(1)环境变量的概念

​ 环境变量是操作系统的变量,它通常用于配置程序的运行环境,即程序可以获取环境变量的值,并根据环境变量的值决定自己的功能。如通过环境变量SHELL知道当前使用的哪个Shell程序运行。用户也可以自己设置环境变量。

​ 局部变量仅在程序内部使用,环境变量作为系统的变量,可以被多个程序共同访问。因此一些环境变量的改变会导致大部分软件的配置发生变化。

(2)常见的环境变量

  • HOSTNAME:主机名称。
  • SHELL:当前使用的Shell程序。
  • SSH_CLIENT:主机的IP地址、端口号等。
  • USER:当前登录的用户。
  • LOGNAME:当前用户名。
  • HISTSIZE:历史命令的数量。
  • history:历史命令。
  • PWD:当前路径。
  • HOME:当前用户的家目录。
  • PATH(重要):可执行程序的路径,使用每条路径使用:隔开。
    • 执行程序时需要指定路径,否则系统找不到程序的位置。
    • 没有指定路径的程序在运行时,系统会在环境变量PATH中找该程序的地址,若是找不到则报错。
# PATH中有多个目录地址,这些目录里的可执行程序不需要指定路径就可以执行。
PATH=/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/wss/.local/bin:/home/wss/bin

(3)环境变量的继承

​ 子进程会继承父进程的变量,即使父进程没有导出为环境变量,子进程也能使用。

3.2 环境变量的操作命令

(1)查看环境变量

  1. env:打印所有环境变量。
env
HOSTNAME=VM-12-10-centos
SHELL=/bin/bash
USER=wss
PATH=/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/wss/.local/bin:/home/wss/bin
PWD=/home/wss
LANG=en_US.utf8
HOME=/home/wss
_=/usr/bin/env
# 此处省略n个字
  1. echo:打印环境变量的值
echo $PATH
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/wss/.local/bin:/home/wss/bin

(2)环境变量的定义

环境变量的定义与普通变量一样,但是普通变量只能在当前程序中使用,因此要让变量全局生效,则需要用export导出变量。

  • 环境变量命名:环境变量通常使用大写字母,单词间用_隔开。
  • 环境变量的值通常为字符串类型。

export:导出为环境变量,即让普通变量全局生效。

MY_ENV="Hello World"			# 定义普通变量
export MY_ENV					# 导出为环境变量export MY_ENV="Hello World"		# 一步到位

(3)删除环境变量

unset:删除变量,与删除普通变量一样都是用unset

unset MY_ENV

(4)修改环境变量

与修改普通变量一样,赋值即可。

  • 直接赋值会导致新值覆盖旧值,若是使用追加的方式,则可以先$获取环境变量值,再拼接字符串,最后赋值。
MY_ENV="Hi"				# 将环境变量赋值为Hi
MY_ENV="${MY_ENV}Hi"	# 追加Hi

(5)永久生效的环境变量

​ 使用export定义的环境变量只能在本次登录中使用,下次登录时该环境变量就不存在了。永久生效的环境变量是通过文件中的命令导入环境变量的,系统每次加载或用户登录时会自动执行这些文件里的命令。

  • /etc/profile/etc/bashrc:系统加载时自动执行该文件,里面的命令在开机时执行,所以对所有用户都生效。
  • ~/.bash_profile~/.bashrc:用户登录bash时才会执行该文件,只对单一的用户生效。

往这些文件写入导入环境变量的命令即可,第一次刚更改完文件需要用source命令执行一下才能即刻生效。

# 修改~/.bash_profile文件,在里面加入export MY_ENV="Hello World"命令
sudo vim ~/.bash_profilesource ~/.bash_profile		# 执行该文件里的命令,即将新内容执行,使其立刻生效。

3.3 代码中操作环境变量

(1)环境表

代码中通常会用以下方式组织环境变量:

  1. 每个程序都会收到一张环境表,环境表是一个字符指针数组,被二级指针char** environ指向。
  2. 环境表中的每个指针都指向一个字符串,字符串中就是环境变量及内容。
    在这里插入图片描述

(2)main函数参数获取环境变量

C/C++语言中,main函数的第三个参数char* env[]就是环境变量。

  • env是一个指针数组(有些代码也会写成二级指针的形式),数组中都是环境变量值的首地址,数组以空指针结尾。
int main(int argc, char* argv[], char* env[]) {// 遍历环境变量int i = 0;for (i = 0; env[i]; i++) {printf("%s\n", env[i]);}return 0;
}

(3)全局变量environ获取环境变量

environ是系统提供的一个char**类型的全局变量,使用前要用extern声明一下。

int main() {extern char** environ;	// 声明envrion变量// 遍历环境变量int i = 0;for (i = 0; environ[i]; i++) {printf("%s\n", environ[i]);}return 0;
}

(4)使用库函数获取getenv环境变量

stdlib.h里的库函数getenv获取环境变量。

#include <stdlib.h>char* getenv(const char* name);		// 获取环境变量名name的值
  • 返回值:环境变量的内容。
  • 参数
    • name:环境变量的名字。

(5)导入环境变量的函数

putenv:导入环境变量。如果导入的是已存在的环境变量,则会修改原来的环境变量的内容。

int putenv(char* string);
  • 返回值:成功返回0,失败返回-1。
  • 参数
    • string:需要改变或导入的环境变量,格式为变量名=内容
#include <stdio.h>
#include <stdlib.h>int main()
{// 导入自定义环境变量ABCint ret = putenv("ABC=123456789");if (ret != 0){perro("导入失败\n");exit(1);}// 获取环境变量ABC的值并打印char* abc = getenv("ABC");printf("ABC = %s\n", abc);return 0;
}

四、运算符

1. 算数运算

(1)算数运算符

bash不支持原生的算术运算符,即+ - * / %等,但是可以通过其他命令实现,如awkexpr,其中expr最常见。

expr:表达式计算工具,使用它能完成表达式的计算。

  • 表达式计算需要被反引号`包裹起来,不是单引号’。被反引号包裹起来的语句会被当成命令执行
  • 表达式要与运算符直接有空格,连起来是不对的。(expr 2 + 3expr是命令,2 + 3分别是3个参数,不能连一起)
var1=`expr 2 + 3`	# 加
var2=`expr 2 - 3`	# 减
var3=`expr 2 * 3`	# 乘
var4=`expr 2 / 3`	# 除
var5=`expr 2 % 3`	# 取余

(2)自增与自减运算符

  • expr:将变量加一,然后赋值给该变量。
  • let:该命令允许对整数进行算数操作,并且支持++--作为参数
  • $((表达式))
  • ((表达式))
a=`expr a + 1`
let b++
c=$((c - 1))
((d--))

2. 逻辑运算

(1)关系运算符

除了==!=bash同样不支持原生的关系运算符,如> < >= <=,依然是通过其他命令实现——test

test:关系运算的工具,使用它能完成关系表达式的运算。

  • test的结果是truefalse,它可以被变量赋值,但不会被echoprintf打印出来。
  • test命令的语法可以写成[ 表达式 ][]必须与表达式之间有空格。
  • 关系运算符作为参数出现在表达式里,以下运算符只能运算数字:
    • -eq(equal):等于==
    • -ne(not equal):不等于!=
    • -gt(greater):大于>
    • -lt(less):小于<
    • -ge(greater or equal):大于等于>=
    • -le(less or equal):小于等于<=
test $a == $b		# a == b
[ $a != $b ]		# a != b[ $a -eq $b]		# a == b
b=test 1 -ne 2		# 1 != 2,并将结果赋值给变量b
c=[ $c -lt $d]		# c < d,并将结果赋值给变量c

(2)逻辑运算符

bash依然不支持原生的逻辑运算符,如&& || !,这些依然是通过test实现,但test的参数中支持这些符号,但它同样提供了选项参数的格式:

  • 与运算:&&-a(and)。
  • 或运算:||-o(or)。
  • 非运算:!
test $a == $b && $c != $d	# a == b && c != d
[ $a -gt 30 -o $b -lt 60 ]	# a > 30 || b < 60
[ ! $a == $b ]				# 对a == b的取反

3. 括号

(1)小括号

单小括号()

  • (命令组):小括号里面是命令组,括号中的命令会开一个新的Shell子进程按顺序执行,命令之间用分号隔开,命令和括号之间不需要空格。

  • $(命令组):新开一个子进程执行小括号里面的命令,并用标准输出流的内容替换它所在的位置。

  • 常用于初始化数组:arr=(a b c d)

注意:由于()里的命令会新开一个子进程执行,所以里面定义的变量无法在外面使用。

(cd ./dir; ls -l; touch file)	# 新开一个子进程顺序执行cd、ls、touch命令
array=(1 2 3 4 5)				# 初始化数组

双小括号(())(部分Shell程序不支持)

  • ((表达式)):用于给整数扩展运算方式,双小括号里支持C语言的整数运算(甚至包括三目运算符),多个表达式用逗号隔开。
    • 双括号里面的变量可以不用$前缀获取值。
    • 用于逻辑运算时(iffor等的条件)运算结果为0返回true,否则返回false。若是运算结果为0,则该语句的进程退出码为1,否则为0(即运算结果非0时代表没有出错)
((a++))					# 执行a++
for ((i=1;i<5;i++))		# for循环

(2)中括号

单中括号[]

  • [ 表达式 ][test命令的别名,中括号里的表达式是test的参数,需要用空格隔开。
  • arr[n]:中括号也用来随机访问数组。
[ 20 -gt 30 ]		# 20 > 30
array[20]

双中括号[[]]

  • [[ 表达式 ]]:常用于逻辑判断,支持&&||等符号,且支持正则表达式和通配符。
[[ hello == hell? ]]	# ?代表任意字符,是通配符
[[ $a == 2 && $b == 3 ]]

(3)大括号

<1> 通配符

  • 大括号中可以用逗号扩展文件名,如touch {a,b}.txt的结果就是a.txtb.txt。(中间不能使用空格)
  • 大括号中以..分割文件代表顺序扩展,如touch {a..d}.txt的结果是a.txtb.txtc.txtd.txta..d即a到d)。
ls {ex1,ex2}.sh    
ex1.sh  ex2.shls {ex{1..3},ex4}.sh
ex1.sh  ex2.sh  ex3.sh  ex4.shls {ex[1-3],ex4}.sh
ex1.sh  ex2.sh  ex3.sh  ex4.sh

<2> 代码块

  • 代码块也叫内部组,创建了一个匿名函数,不会新开子进程,里面创建的变量可以被外面使用。
  • 代码块里面的命令必须用分号结尾(最后一个也要分号),第一个命令必须与{中间隔一个空格。
{ cd ./dir; ll; mkdir empty;}	# 执行3格命令

大括号还有其他作用,如字符串提取等,不常用的就不赘述了。

(4)$后的括号

  • ${var}:获取变量值,不连着其他字符的情况下可以省略。
  • $(cmd):新开一个子进程执行小括号里面的命令,并用标准输出流的内容替换它所在的位置。
  • $((expression)):效果与`expression`一样,将里面的表达式当做命令执行,支持C语言表达式。
${var}
var=$(ls -l)	# 新开一个子进程执行ls、并将标准输出流的内容赋值给var
$((a>b))

4. 通配符

通配符通常用来匹配文件名。

通配符含义
*匹配任意字符串。如cat *.h打印所有以.h结尾的文件。
?匹配任意字符(只能一个字符),如cat abc?打印文件名为abc+任意字符的文件。
[abcd]匹配中括号中的任意字符,如cat [abcd].h,只能打印a.hb.hc.hd.h中的一个。
[a-z]匹配中括号中的a到z之间的所有字母,也能用[A-Z]匹配大写或[0-9]匹配数字。
{a,b}将大括号中的字符展开,如{a,b}.h就是a.hb.h两个文件。
{a...z}展开大括号中a到z之间的所有字母。(中间不能有空格)
[!abcd][^abcd]匹配中括号中没有的字符,如左边的式子代码没有abcd中的任意一个。

5. 字符串与文件运算

(1)字符串运算

test也可以对字符串进行运算:

  • ==:检测2个字符串相等。(不能用-eq
  • !=:检测2个字符串不相等。(不能用-ne
  • -z:检测字符串长度为0。
  • -n:检测字符串长度不为0。
  • $:在test内给字符串取值,字符串不为空时就会返回true,否则返回false。
[ $a == $b ]	# 判断a == b
[ -z $a ]		# 判断a长度为0
[ $a ]			# 若a非空,则返回ture,否则false

(2)文件检测运算

test可以对文件进行一些判断。

<1> 检测文件是否存在或为空

  • -e:检测文件是否存在。
  • -s:检测文件是否为空。
test -e $file	# file是否存在
[ -s $file ]	# file是否为空

<2> 检测文件类型

  • -f:检测文件是否为普通文件。
  • -d:检测文件是否为目录。
  • -L(大写):检测文件是否为符号链接(软链接)。
  • -c:检测文件是否为字符设备文件。
  • -b:检测文件是否为块设备文件。
  • -p:检测文件是否为有名管道文件。
  • -S(大写):检测文件是否为socket文件。
if [ -f $file ]
thenecho "普通文件"
elif [ -d $file ]
thenecho "目录文件"
elif [ -L $file ]
thenecho "软链接"
elif [ -c $file ]
thenecho "字符设备文件"
elif [ -p $file ]
thenecho "管道文件"
elif [ -S $file ]
thenecho "socket文件"
elseecho "块设备文件"
fi

<3> 检测文件权限

  • -r:检测文件是否为可读。
  • -w::检测文件是否为可写。
  • -x:检测文件是否为可执行。
  • -k:检测文件是否设置了粘滞位。
if [ -r $file ]
thenecho "文件可读"
elseecho "文件不可读"
fiif [ -w $file ]
thenecho "文件可写"
elseecho "文件不可写"
fiif [ -x $file ]
thenecho "文件可执行"
elseecho "文件不可执行"
fi

五、流程控制语句

1. 分支语句

(1)if语句

  • if起始,中间用elif添加判断条件,else后是条件以外的语句,fi结束。
  • 除了else,条件判断后都要加上then才到执行语句。
  • 写成一行时,要在条件判断和执行语句后加上;,通常用来在Shell终端中写命令行。
  • 条件判断语句有多种编写方式:
    • test命令或[ 表达式 ],里面的大于小于只能用-gt-lt等。
    • ((表达式)),大于小于可以直接用><等C语言表达式符号。
# 写成多行
if [ $a -gt 10 ]				# 使用[]
thenecho "a > 10" echo "a大于10"
elif (($a > 5))					# 使用(())
thenecho "5 < a <= 10"echo "a大于5且小于等于10"
elseecho "a <=5"echo "a小于等于5"
fi# 写成一行
if test $b -gt 3; then echo "b > 3"; fi

(2)case语句

  • case相当于C语言里的switch语句,以case开头,esac结尾(case倒过来写)。
  • 每个分支以值)开始,以2个分号;;结束,值可以是常量或变量,匹配到哪个值就执行哪个分支。
  • 若是都没有匹配到,则会执行*)分支。
case $var in1)  echo 'var=1'			# var==1时执行该语句;;2)  echo 'var=2';;3)  echo 'var=3';;4)  echo 'var=4';;*)  echo 'var!=1,2,3,4'		# var都没有匹配到时执行该语句;;
esac

2. 循环语句

(1)for循环

  • for后面的变量用于每次循环取值,in后面是每次取值的元素。循环体用dodone包裹起来。
  • 若是in后面是数组变量,则需要用${arr[@]}将数组展开。
# 循环多个元素
for var in 1 2 3 4 5
doecho "本次循环的var值是${var}"
done# 循环数组
for var in ${array[@]}
doecho "本次var的值是$var"
done

(2)while循环

除了条件判断格式、循环体被包裹、shell特色的自增自减语句,基本上与C语言的while一样了。

while (( $a<=5 ))
doecho "a=$a"let a++;
done

死循环

# 用:作为条件语句
while :
docommand
done# 用true作为条件
while true
docommand
done# for循环里俩冒号
for (( ; ; ))

(3)until循环

while相反,当条件为false才执行循环体,条件为true时停止执行。

until [ ! $a -lt 10 ]		# 结果为false时才执行
doecho $aa=`expr $a + 1`
done

(4)跳出循环

  • break:中止所在的循环语句。
  • continue:中止该循环语句的本次循环。
for var in 1 2 3 4 5
doif [ $var == 3 ] thencontinue				# 结束var==3时的循环,其他1245不影响fiecho "本次循环的var值是${var}"
done

六、函数

  • 函数定义:函数在使用前必须定义,因此函数通常要写在前面。

  • 函数参数:

    • 函数在定义时不用写参数类型和参数名。
    • 获取参数时使用特殊变量,如$1等。
  • 函数调用:与执行命令一样,函数名 参数列表

  • 返回值:

    • 返回值只能返回0到255之间的整数。
    • 函数调用后,只能紧接着使用特殊变量$?获取返回值。
func(){			# func函数,不用在小括号中写参数名。var=$1		# 获取第一个参数... ...return $n	# 只能返回0到255之间的整数。
}func 1 2 3 4	# 调用func函数并传参1 2 3 4
echo $?			# 获取func的返回值。
http://www.lryc.cn/news/594558.html

相关文章:

  • 双8无碳小车“cad【17张】三维图+设计说名书
  • XTTS实现语音克隆:精确控制音频格式与生成流程【TTS的实战指南】
  • XSS GAME靶场
  • 仙盟数据库应用-外贸标签打印系统 前端数据库-V8--毕业论文-—-—仙盟创梦IDE
  • Apache基础配置
  • ESMFold 安装教程
  • 深度相机的工作模式(以奥比中光深度相机为例)
  • 近期工作感想:职业规划篇
  • 【RAG Agent】Deep Searcher实现逻辑解析
  • 尚庭公寓--------登陆流程介绍以及功能代码
  • Linux:线程控制
  • API获取及调用(以豆包为例实现图像分析)
  • 《计算机网络》实验报告三 UDP协议分析
  • 单线程 Reactor 模式
  • 【PyTorch】图像二分类项目
  • SSE和WebSocket区别到底是什么
  • 渗透笔记(XSS跨站脚本攻击)
  • `MYSQL`、`MYSQL_RES` 和 `MYSQL_FIELD`的含义与使用案例
  • [硬件电路-59]:电源:电子存储的仓库,电能的发生地,电场的动力场所
  • 2025最新 PostgreSQL17 安装及配置(Windows原生版)
  • BST(二叉搜索树)的笔试大题(C语言)
  • 【web安全】SQL注入与认证绕过
  • 【算法300题】:双指针
  • c#转python第四天:生态系统与常用库
  • XSS的介绍
  • Linux主机 ->多机器登录
  • 从零到精通:用DataBinding解锁MVVM的开发魔法
  • 【JS逆向基础】数据库之MongoDB
  • Django接口自动化平台实现(四)
  • SpringBoot的配置文件