Shell是用C语言编写的程序,是用户使用Linux的桥梁。下面文章主要介绍一个超详细的Shell脚本讲解,通过示例代码详细介绍,有需要的朋友可以参考一下。
目录
一、shell脚本的基本概念1.1什么是Shell?1.2 Shell脚本1.3是什么意思?2.创建一个简单的shell脚本2.1创建一个shell脚本文件2.2运行一个Shell脚本2.2.1脚本文件没有执行权限2.2.2脚本文件有执行权限3, 基本语法3.1变量3.1.1变量类型3.1.2变量运算3.1.3字符串变量3.1.4数组3.1.5变量参数3.2运算符3.2.1算术运算符3.2.2关系运算符3.2.3布尔运算符3.2.4逻辑运算符3.2.5字符串运算符3.2 3.3.1 if语句结构3.3.2循环结构3.3.3 case-esac多项选择语句3.3.3 select-in语句4、函数4.1定义
一、Shell脚本基础概念
1.1 什么是shell?
shell的英文翻译是贝壳的意思。作为一门计算机语言,可以看作是操作系统的外壳。我们可以通过shell命令来操作和控制操作系统。比如Linux中的shell命令有ls、cd、pwd等等。
Shell是一个应用程序在kernel基础上写的。它将用户与linux内核连接起来,让用户更方便、高效、安全地使用Linux内核。这其实就是贝壳的本质。
用专业术语解释,Shell实际上是一个命令解释器,通过接受用户输入的Shell命令来启动、暂停、停止程序或控制计算机。
1.2 什么是shell脚本
脚本由Shell命令组成的执行文件组成,将一些命令集成到一个文件中,处理业务逻辑。该脚本无需编译即可运行。它通过解释器解释操作,所以速度比较慢。
1.3 shell脚本的意义
我们在1.2中也解释过,shell脚本实际上是一个由shell命令组成的文件。shell脚本可以记录命令执行的过程和逻辑,以便以后重复执行。还可以批量、定时处理主机,方便管理员设置或管理。
二、创建一个简单的Shell脚本
2.1 创建一个shell脚本文件
当创建一个shell脚本时,我们创建一个以。sh/。脚本默认,主要是为了程序员更快地识别它是一个shell脚本文件。
我们创建一个test.sh的shell脚本文件,内容如下:
#!/bin/bash
回声你好
' # '的开头是一个注释,单行注释EOF … EOF或:… !多行评论#!/bin/bash:主要用于指定Linux中提供的shell解释器有:
/bin/sh/bin/bash/usr/bin/sh/usr/bin/bash
2.2 运行一个Shell脚本
根据脚本文件是否具有可执行权限,我们将运行shell脚本的方法分为两类。
2.2.1 脚本文件无执行权限
在这种情况下,我们有三种方法来运行脚本:
在环境中手动打开指定的解释器:shtest.sh。
在当前环境中运行的shell中直接运行脚本:test.sh
直接在当前环境中运行的shell中运行脚本:sourcetest.sh。
2.2.2 脚本文件有执行权限
在这一部分,因为我们假设脚本文件具有可执行权限,所以我们使用chmod x test.sh向我们的test.sh文件添加可执行权限。
我们知道,当一个文件具有可执行权限时,我们可以使用其路径名直接运行该文件。运行脚本有两种方式:
1.使用绝对路径名运行脚本文件
路径肯定是从根目录记录的文件的路径名,是文件在电脑上实际存在的路径。(如果不知道自己的文件路径名,可以在当前位置的shell中使用pwd查询当前位置)
2./运行与路径名格式相关的脚本文件。
相对路径是指与当前目录位置相比,当前文件作为起点指向并引用的文件资源。
比如我们知道test.sh文件的绝对路径是/home/westos/desktop/text CPP/test.sh,那么当我们在testcpp文件夹中时,test.sh文件的相对路径就是test . sh。
因为。表示当前位置,实际上是。/test.sh实际上是文件的绝对路径,只是表达方式不同。
三、基本语法
3.1 变量
变量名实际上是一个内存区域的地址或一个寻址符号。有了变量,我们可以用一个固定的字符串来表示一个不固定的目标。
3.1.1 变量类型
shell中有三种类型的变量。
局部变量:局部变量是在脚本或命令中定义的,并且只在当前shell实例中有效。其他shell启动的程序不能访问局部变量。环境变量:所有程序,包括shell启动的程序,都可以访问环境变量,有些程序需要环境变量才能保证正常运行。必要时,shell脚本也可以定义环境变量。外壳变量:外壳变量是由外壳程序设置的特殊变量。有些shell变量是环境变量,有些是局部变量,这些变量保证了shell的正常运行。
3.1.2 变量操作
创建一个公共变量:name="test "。小组应注意等号两边不能有空格。创建一个局部变量:local name="test "。用local修饰的变量不能在函数体外部访问,只能在函数体内使用。创建一个只读变量:name=" only _ read "-只读名称,不可修改。使用变量:echo $name或echo ${name}删除变量:unset name。无法访问已删除的变量。请注意,只读变量不能删除。
3.1.3 字符串变量
3.1.3.1 字符串变量的创建
用单引号创建:var='test '。
这样创建的变量只能按原样输出,变量无效。我们可以借用C中“字符串常量”的定义来理解这个特性。另外,单引号中不能有单个单引号,不允许转义。使用双引号创建:var='我的名字是${name} '。以这种方式创建的字符串变量是有效的,也可以出现转义字符。
3.1.3.2 拼接字符串
字面量拼接
St01=' 1'' 2 '或St01=' 1'' 2 ',以便字符1和2拼接在一起。请注意,两个字符串之间不能有空格。可变剪接
字符串变量可以由str03=${part01}${part02}或str04=${part01}'end '或str05='${part01} ${part02} '拼接。命令拼接
str 02=date“end”,其中date是一个shell命令,需要引用如下:
str 02=` date `` end '
3.1.3.3 获取字符串长度
1.使用wc -L命令
Wc -L可以得到当前行的长度,所以用这个简单的方法就可以得到单行的字符串。另外,wc -l是获取当前字符串内容的行数。
echo 'abc' |wc -L
2.使用expr length获取字符串的长度
表达式长度${!- {C} <!--->-str }
3.awk获取域的数量
但如果超过10个字符,是否有问题需要后期确认。
echo 'abc' |awk -F '' '{print NF} '
4.通过awk长度获得字符串长度
echo " Alex " | awk“{打印长度($0)}”
5.通过回显$ {# name}
name=Alex
echo ${#name}
3.1.3.4提取子串
1.如下所示:
含义从左到右截取最后一个字符串后的$ {variable # # * string}字符串从左到右截取第一个字符串后的$ {variable%% string *}字符串从右到左截取最后一个字符串后的$ {variable% string *}字符串从右到左截取第一个字符串后的
例如,下面的代码:
$ MYVAR=food fort thought . jpg
$ echo ${MYVAR##*fo}
结果是rthought.jpg。
2.使用$ {variable: n1: n2}
截取变量variable从n1到n2的字符串,根据特定的字符偏移量和长度选择特定的子串,如下面的代码所示:
$ EXCLAIM=cowabunga
$ echo ${EXCLAIM:0:3}
运行结果最终显示牛。
3.1.4 数组
如果变量是存储单个变量的内存空间,那么数组就是多个变量的集合,在连续的内存空间中存储多个元素。在bash中,只支持一维数组,不支持多维数组。
3.1.3.1 数组定义与引用
按如下方式定义数组:
数组名=(元素1,元素2,元素3.元素n)
指定数组应该为具有相应下标的元素赋值:
数组名[下标]=值
同时指定多个数组元素进行赋值:
数组名=([下标1]=值1[下标2]=值2.[下标n]=值n)
引用数组相应下标的元素:
$ {数组名称[下标]}
3.1.3.2 遍历数组元素
使用for循环遍历数组元素(或while循环):
#!/bin/bash
a=(1 2 3 4 5 6)
for((I=0;i10我))
做
echo 'a[$i]=${a[$i]} '
完成的
此外,我们还可以使用${a[*]}或${a[@]}来遍历数组元素,具体代码如下:
#!/bin/bash
a=(1 2 3 4 5 6)
echo ${a[*]}
echo ${a[@]}
3.1.3.3 获取数组长度
我们可以用#来获得数组的长度。应该注意的是,在shell脚本中,当我们越界访问数组时,我们不会报告错误。
#!/bin/bash
a=(1 2 3 4 5 6)
echo ${a[*]}
echo 'a len: ${#a[*]} '
我们可以先用它来获取数组中的元素,然后用#来获取元素个数。
3.1.3.4 合并数组
我们可以拼接如下:
#!/bin/bash
a=(1 2 3 4 5 6)
b=('hello' 'zhaixue.cc ')
c=(${a[*]} ${b[*]})
这样,我们拼接两个数组。
3.1.3.5 删除数组元素
如果我们要删除一个数组元素,具体代码如下:
#!/bin/bash
a=(1 2 3 4 5 6)
echo ${a[*]}
echo 'a len: ${#a[*]} '
取消设置a[5]
echo ${a[*]}
echo 'a len: ${#a[*]} '
执行结果如下:
如果我们想删除整个数组,我们可以执行unset a,以下面的代码为例:
#!/bin/bash
a=(1 2 3 4 5 6)
echo ${a[*]}
echo 'a len: ${#a[*]} '
取消设置
echo ${a[*]}
echo 'a len: ${#a[*]} '
3.1.5 变量传参
相关变量的含义是:
变量$0表示要执行的文件名$1表示传入的第一个参数$n表示传入的第n个参数$ # number of parameters $ *将所有传入脚本的参数显示为单字符串。$ @与$ *相同,但使用时加引号并返回当前进程号$!在引号中运行的每个参数$$脚本。在后台运行的最后一个进程的ID $?显示最后一个命令的退出状态。0表示没有错误,任何其他值表示有错误。
3.2 运算符
最初的bash不支持简单的数学运算,它通常由其他命令实现。
3.2.1 算数运算符
下表中的a和B是变量。
格式加法表达式$a $b减法表达式$a-$b乘法表达式$a \* $b除法表达式$b/$a余数表达式$b% $a赋值a=$b shell [$a==$b]不等[$a!=$b ]
注意:
条件表方法需要放在带空格的方括号内。用expr计算时,需要用反引号。为了让读者更容易理解,下面给出了示例代码。
#!/bin/bash
a=10
b=20
val=`expr $ a $ b '
回声' a b : $val '
3.2.2 关系运算符
关系运算符只支持数字,不支持字符串,除非字符串的值是数字。
操作shell中的主符号检测两个数是否相等[$a -eq $b ]-eq检测两个数是否不相等[$a -ne $b ]-ne检测左数是否大于右数[$a -gt $b ]-gt检测左数是否小于右数[$a -lt $b ]-lt检测左数是否大于等于右数[
示例代码如下:
#!/bin/bash
a=1
b=2
如果[ $a!=$b ]
然后
回声$a!=$b: a不等于B '
其他
Echo '$a==$b: a等于b '
执行结果如下:
3.2.3 布尔运算符
如下所示:
操作shell中的主要符号不是operation [!false ]!或操作[$a -lt 20 -o $b -gt 100 ]-o和操作[$a -lt 20 -a $b -gt 100 ]-a
3.2.4 逻辑运算符
如下所示:
操作外壳中主符号逻辑的OR [[$ AND[[ $a -lt 100 $b -gt 100 ]]]和[[$ a-lt 100 || |]
布尔运算符和逻辑运算符的区别:
语法上,逻辑运算需要双括号,布尔运算只需要单括号。逻辑运算有一个特殊的短路功能,即当AND运算中的第一个表达式为假时,不执行第二个表达式,当OR运算中的第一个表达式为真时,不执行第二个表达式。
3.2.5 字符串运算符
下表列出了常用的字符串运算符:
shell操作中的主符号检测两个字符串是否相等[$a=$b ]=检测两个字符串是否不相等[$a!=$b ]!=检查字符串长度是否为0[ -z $a ]-z检查字符串长度是否不为0 [-n "$ a"]-n检查字符串是否为空[$a ]$
3.2.6 文件测试运算符
主要用于检测unix文件的各种属性:
操作外壳中的主符号检测文件是否为块设备文件[-b $file ]-b文件检测文件是否为字符设备文件[-c $file ]-c文件检测文件是否为目录[-d $file ]-d文件检测文件是否为普通文件(既不是目录, 也不是设备文件)[-f $file]返回true-f file检查文件是否设置了SGID位[-g $file ]-g file检查文件是否有粘滞位)[ -k $file ]-k file]-k file检查文件是否是已知管道[-p $file] -p文件检测SUID位是否置位[-u $file ]-u文件检测文件是否可读[-r $file ]-r文件检测文件是否可写[-w $file ]-w文件检测文件是否可执行[-x $file ]-x文件检测文件是否为空(文件大小是否大于0)[ -s $file ]-s文件
例子如下:
#!/bin/bash
file='/home/westos/Desktop/text CPP/test . sh '
if [ -r $file ]
然后
回显'文件可读'
其他
回显'文件不可读'
船方不负担装货费用
执行结果是:
3.2.7 运算指令
1.(( ))
我们可以直接计算括号里的内容,比如((var=a b))。在if/while等条件判断中需要计算时,经常使用该指令。
2.let
计算表达式时我们可以直接用let,比如let var=a b。
3.expr
我们在之前的内容中也提到过,是很常见的计算指令,需要在外面加上反引号。
var=`expr a b '
4.bc计算器
Bc计算器支持shell中的小数运算,可以交互使用,也可以非交互使用。基本使用模式是var=$(echo '(1.1 2.1)' | BC);
5.$[]
我们可以直接用这个方法计算括号里的内容,比如echo $[1 2]
3.3 控制语句
与其他语句不同,shell的循环控件不能为空。接下来,我们来介绍一下sehll中的常用语法。
3.3.1 if语句结构
3.3.1.1 if-fi
该判断类似于C中的if条件,如下所示:
if条件
然后
命令1
命令2
.
命令n
船方不负担装货费用
3.3.1.2 if-else-fi
代码如下:
if条件
然后
命令1
其他
命令2
船方不负担装货费用
如果条件成立,执行命令1,否则,执行命令2。
3.3.1.3 if else-if else
代码如下:
如果条件1
然后
命令1
elif条件2
然后
命令2
其他
命令3
船方不负担装货费用
如果条件1成立,则执行命令1,如果条件1不成立,则执行命令2,如果条件2成立,则执行命令3,如果两个条件都不成立。
3.3.2 循环结构
3.3.2.1 for循环
格式是:
对于项目1和项目2中的变量.itemN
做
命令1
命令2
.
命令n
完成的
上面也可以写成一行。如果变量var在列表中,for循环将执行所有命令一次。以下面的代码作为测试:
#!/bin/bash
for循环1 2 3 4 5
做
echo '值为:$loop '
完成的
执行结果是:
3.3.2.2 while循环
格式如下:
while条件
做
命令
完成的
我们运行以下代码:
#!/bin/bash
int=1
while(( $int=5))
做
echo $int
let 'int '
完成的
执行的最终结果是:
3.3.2.3 无限循环
我们可以用上面两个语句给出无限循环的实现。首先,看看for循环是如何实现的:
for((;))
此外,我们还可以使用while循环来实现以下功能:
同时:
做
命令
完成的
或者直接将while中的判断语句设置为true:
虽然是真的
做
命令
完成的
3.3.2.4 until循环
Until循环执行一系列命令,直到条件为真。语法如下:
直到条件
做
命令
完成的
3.3.2.5 跳出循环
在循环过程中,有时在不满足循环结束条件时,需要跳出循环。Shell使用两个命令来实现这个功能:break和continue。
1 .打破循环
当我们需要跳出当前循环,或者终止无限循环时,可以使用break跳出循环。接下来,我们运行以下代码:
#!/bin/bash
var=1
while(( $var 5))
做
if(( $var3))
然后
回声“循环之外”
破裂
船方不负担装货费用
echo '$var '
var=`expr $ var 1 '
完成的
执行结果是:
在这个循环中,var3 break,但是直接跳出循环。
2 .继续跳出循环
continue命令类似于break命令,只是它不跳出所有循环,只跳出当前循环。接下来,我们运行以下代码:
#!/bin/bash
var=1
while(( $var 5))
做
if(( $var3))
然后
回声“循环之外”
继续
船方不负担装货费用
echo '$var '
var=`expr $ var 1 '
完成的
执行结果是:
使用continue跳出的循环只是当前循环,不能跳出整个循环。由于这段代码每次执行continue都跳出当前循环,所以不能执行var=expr $var 1,所以循环条件一直成立,就变成了无限循环。
3.3.3 case-esac多选择语句
情况.esac是一个多选语句,类似于switch.其他语言的case语句。它是一个多分支选择结构。每个case分支都以右括号开始,并使用两个分号;意思是break,即执行结束,全案… esac语句跳出,以esac(即案件依次)为结束标记。
case值后面必须跟单词in,并且每个模式必须以右括号结束。该值可以是变量或常数。通过匹配发现值符合某种模式后,所有命令都会执行到;
如果在检测匹配时没有匹配,使用*来捕获值,然后执行后续命令。
语法如下:
案例值在
1)模式
命令1
命令2
.
命令n
;
2)模式
命令1
命令2
.
命令n
;
*)
命令1
environmental systems applications center 环境系统应用程序中心
3.3.3 select-in语句
Select in是外壳中特有的循环,非常适合终端交互场景。它可以显示数字菜单,用户可以通过输入和离开不同的数字来选择不同的菜单和执行不同的功能。
语法如下:
选择序列中的变量
做
行为
完成的
我们执行以下代码:
#!/bin/bash
“你最喜欢的操作系统是什么?”
在“Linux”“Gnu Hurd”“Free BSD”“Other”中选择var做
打破;
完成的
echo '您选择了$var '
执行结果是:
四、函数
其实函数就是把一段代码打包在一起实现一个特定的函数或者返回一个特定的值。当我们定义一个函数时,我们需要从函数名开始。我们在使用的时候,可以直接调用函数名。
4.1 定义函数
shell中定义的函数格式如下:
[函数] funname [()]
{
行动;
[return int;]
}
注意:
1.上面的[功能]也可以省略
2.当函数没有返回值时,默认返回最后一条命令的运行结果作为返回值。
4.2 函数参数
在shell中,您可以在函数被调用时向它传递参数。直接通过函数内部的$n获取参数的值。我们举一个例子如下:
#!/bin/bash
funWithParam(){
Echo '第一个参数是$1!'
Echo '第十个参数是${10}!'
}
funWithParam 1 2 3 4 5 6 7 8 9 34 73
注意$10不能返回第十个参数。n10时,需要用$(n)来获取参数。
4.3 函数作用域
当在脚本中执行一个函数时,子流程将不会打开。默认情况下,在函数外部或内部定义和使用变量具有相同的效果。函数外部的变量可以在函数内部直接调用,而函数内部的变量也可以在函数外部直接调用。但是,这会导致变量混淆,数据可能被错误地修改等等。那么如何解决这些问题呢?
系统给我们提供了一个局部语句,可以使函数内部定义的变量只在函数内部有效。定义时,直接在变量前面加local。
五、重定向
命令通常从一个叫做标准输入的地方读取输入。默认情况下,这恰好是您的终端。类似地,一个命令通常将其输出写入标准输出,这也是您的默认终端。
通常,每个Unix/Linux命令在运行时都会打开三个文件:
标准文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。标准输出文件(stdout):stdout的文件描述符为1,Unix程序输出数据stdout):默认为stdout。标准错误文件(stderr):stderr的文件描述符为2,Unix程序会将错误信息写入stderr):stderr。
但有时我们可能需要读取或从其他文件中读取数据,这就需要我们进行重定向。
5.1 输入重定向
我们可以从文件中获取命令,因此原始命令需要从标准输入stdin中获取,并转换为从我们指定的文件中获取。这样,需要从键盘输入的命令就会转移到文件中读取内容。语法如下:
命令1文件
5.2 输出重定向
与输入重定向类似,输出重定向是将原本需要输出的标准输出文件stdout转换成我们指定的文件。语法如下:
命令1文件
5.3 标准错误文件重定向
我们可以借助标准错误文件的文件描述符直接重定向stderr。语法如下:
$ command文件
扩展一下,如果我们想合并stdout标准输出文件和stderr标准错误文件,并将它们重定向到一个指定的文件,语法如下:
$命令文件21
5.4 Here Document
这里的Document是Shell中的一种特殊重定向方法,用于将输入重定向到交互式Shell脚本或程序。它的功能是在两个分隔符之间传递内容(文档)作为命令的输入。基本语法如下:
命令分隔符文档分隔符
注意:
结尾的分隔符必须用大写字母书写,前后没有任何字符,包括空格和制表符缩进。起始分隔符前后的空格将被忽略。
5.5 /dev/null 文件
如果想执行一个命令,但又不想在屏幕上显示输出结果,可以将输出重定向到/dev/null,这是一个特殊的文件,写入其中的东西都会被丢弃;如果你试图读取这个文件,你不能读取任何东西。但是,/dev/null文件非常有用。将命令的输出重定向到它将具有“禁止输出”的效果。语法如下:
$ command /dev/null
总结
关于Shell脚本的这篇文章到此为止。关于Shell脚本的更多细节,请搜索我们以前的文章或继续浏览下面的相关文章。希望你以后能支持我们!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。