大家好,今天小编来为大家解答一万字总结:完全掌握Shell编程这个问题,很多人还不知道,现在让我们一起来看看吧!
作为Shell终端软件,其实就是泛指的。之所以这么说,是因为Shell终端软件的种类有很多种。不过,基本上所有的Linux和大多数Mac OS X都默认使用Bourne Again Shell,也就是我们通常所说的bash。它是由Brian Fox 于1987 年开发的。
除了bash 之外,还有其他shell 应用程序:
外壳应用
不过,我们今天要学习的其实是一种在Shell上执行的脚本语言,所以我们讲的是Shell脚本。由于是解释性语言,Shell脚本编程不需要额外安装编译器。可以直接用编辑器编辑,然后直接在Shell上运行。通常,我们在编写脚本时,需要使用#!第一行指定运行Shell脚本的解释器,例如#!/bin/sh。
下面我们将从以下几个方面全面系统地为大家梳理Shell编程的相关知识点。
外壳编程
输入输出
shell 中有两个输出命令:echo 和printf。学习程序时,硬文本永远不如代码那么直接、容易理解。我们直接通过例子来学习吧。
echo ‘hello world’printf ‘%s %s’ ‘hello’ ‘world’printf ‘!\n’输出
从上面的例子不难发现,echo命令默认有换行符,而printf没有。与C语言类似,printf可以进行格式化输出。其中%s为格式控制字符,另外还有%c %d %f等控制字符。此外,还可以通过在控制字符上添加数字来指定字符的长度。例如%3s表示三个字符的长度; %4.3f 表示4 位整数和3 位小数。
#!/bin/shprintf ‘%6s %3s %4s %5s\n’ 公司名称评级销售市场份额printf ‘%6s %3c %4d %5f\n’ 公司A A 5001 0.5001printf ‘%6s %3c % 4d % 5f\n’ 公司B C 1999 0.1999printf ‘%6s %3c %4d %5f\n’ 公司B B 3000 0.3printf
如果需要字符对齐,也可以使用- 使字符左对齐,省略默认的右对齐。
shell中以read命令作为输入,可以接受标准键盘的输入;另外,还可以作为文件描述符的输入来操作文件。
读取命名的格式如下:
read [选项名] [变量名] 当执行read命令时,输入的数据将被放置在一个变量中。通常,我们会指定一个自定义变量。如果未指定变量,则将保存输入数据。到REPLY 变量中。有关变量的一些具体信息可以在下面的变量部分中找到。
读取命令的选项名称具有以下参数。我们可以选择一项或者多项来设置。
-p:设置提示信息,屏幕会输出提示信息; -t:设置等待时间(秒),等待用户输入的时间; -n:设置接收指定数量的字符数; -s:隐藏输入数据,以便比较私人机密信息的输入。具体使用方法可以参考以下示例:
#!/bin/shread -p ‘输入名称:’ nameread -p ‘输入密码:’ -s passwdecho ”echo $nameecho $passwdread
注释
任何语言都少不了注释,Shell 也是如此。好的注释可以使代码更易于阅读和维护。 shell 脚本中还可以使用两种类型的注释:单行注释和多行注释。单行注释可以直接使用#就行,多行注释需要:和!
# 这是一行内容# 这是一行内容:这是一行内容这是一行内容!除了使用!多行注释符号,也可以使用EOF’.
除了这两种方法之外,还可以通过条件语句来实现。
变量
Shell可以定义变量并通过=给变量赋值。与其他语言不同,=和变量以及指定值之间不能有空格。习惯了其他语言的同学可能会觉得有点不适应,但是请注意这一点。
命名规则其实和其他语言类似:
使用英文字母、数字和下划线,但不能以数字开头。不能使用shell的保留关键字v1=1234 #正确v2=’hello’ #正确v3_1=’world’ #正确v4_1=’world’ #错误,’=’字符前后不能有空格。另外,访问变量时需要在变量前使用$符号来访问。如果需要区分变量的边界,还需要在变量前后添加{}来区分变量名的边界。使用变量时建议添加{}。
a=’地狱世界:’b=’敲代码的厨师’echo ${a}${b}
Shell的数据类型比较简单,变量的默认数据类型是字符串类型。我们可以使用单引号,也可以使用双引号,因此,不使用引号也是可以的。
让我们看另一个例子:
a=1b=2echo ${a}+${b}你认为最后应该输出多少?
答案是不是超出了大家的预期呢?这样大家就应该明白为什么Shell在定义变量的时候默认是字符串类型了。
那么问题来了,如何表示数字呢?其实我们这里只需要做一点特殊处理即可。在进行数据运算时,我们可以直接使用$[运算表达式]的形式。
a=1b=2echo $[${a}+${b}]a+b
除了这种方法之外,还有其他方法可以进行数据操作。我们将在后续的数据操作章节中对此进行详细阐述。让我们继续讨论变量。
我们可以将变量分为局部变量和环境变量:
局部变量:是在Shell命令或脚本中定义的变量,仅在当前Shell命令或脚本中有效。环境变量:用在创建它们的shell以及从它们派生的任何子进程等中。它可以保证某些程序的正常运行。在一些特殊场景下,我们不希望我们定义的变量的值被改变。在这种情况下,我们可以使用readonly命令将变量设置为只读。
a=’hello world’只读aecho ${a}a=’hahah’
还有一些场景需要清除变量。我们可以使用unset命令来删除变量。需要注意的是,只读变量不能被删除。
a=’hello world’b=’会写代码的厨师’readonly Bunset aunset becho ${a}echo ${b}
字符串变量操作
了解了上面变量的内容后,我们知道变量pattern是字符串类型。字符串有哪些操作?
一般我们可以对字符串变量进行如下操作:
获取字符串的长度:可以在变量前添加#符号,${#变量};截取字符串:可以在变量后面使用:来截取,${variable :x:y};替换字符串中的子字符串:可以在变量后面使用/符号,${变量/子字符串/替换的字符串};删除字符串中的子串:这个其实可以通过替换子串来实现;字符串大小写替换:可以使用^^转换为大写,使用,转换为小写;下面,我们通过下面的例子可以更直观的理解这些操作。
a=’Hello World’echo ‘${#a}’ #获取字符串的长度echo ‘${a:6:3}’ #截断从下标6开始的3个字符echo ‘${a/ll/hh}’ #转换string Replace ll in with hhecho ‘${a/or/}’ #删除子字符串orecho ‘${a^^}’ #全部转换为大写echo ‘${a,}’ #全部转换为小写字符串opera
数字运算
在上面的变量章节中,我们了解到可以使用$[运算表达式]形式对数值变量进行运算。在本章中,我们将了解更多有关数字运算的知识。事实上,Shell可以使用命令和运算表达式进行数值运算,并且它们可以支持+ – */%等算术运算。
主要的命令方法有let declare expr等命令。下面我们就通过例子来一一学习它们的使用。
使用let命令执行数值运算。只需命名let 后跟运算表达式即可。
#!/bin/sha=’4’b=’2’let c1=${a}+${b}let c2=${a}-${b}let c3=${a}*${b }let c4=${a}/${b}let c5=${a}%${b}echo ‘a + b=’ ${c1}echo ‘a – b=’ ${c2}echo ‘a * b=’ ${c3}echo ‘a/b=’ ${c4}echo ‘a % b=’ ${c5}let 命令
通过expr命令进行数值运算,可以查看下面的示例代码,但是需要注意两点:
运算符和两边的变量需要用空格分隔;请注意,* 需要转义为\*。 #!/bin/sha=4b=2c1=$(expr ${a} + ${b})echo ‘a + b=’ ${c1}c2=$(expr ${a} – ${b}) echo ‘a – b=’ ${c2}c3=$(expr ${a} \* ${b})echo ‘a * b=’ ${c3}c4=$(expr ${a}/${ b})echo ‘a/b=’ ${c4}c5=$(expr ${a} % ${b})echo ‘a % b=’ ${c5}expr
声明命令声明命令
通过运算表达式实现数字运算的主要方式有$((运算表达式))和$[运算表达式]。我们依次看看它们的用法。
#!/bin/sha=4b=2c1=$((${a}+${b}))c2=$((${a}-${b}))c3=$((${a}) *${b}))c4=$((${a}/${b}))c5=$((${a}%${b}))echo ‘a + b=’ ${c1} echo ‘a – b=’ ${c2}echo ‘a * b=’ ${c3}echo ‘a/b=’ ${c4}echo ‘a % b=’ ${c5}表达式方法1
#!/bin/sha=4b=2c1=$[${a}+${b}]c2=$[${a}-${b}]c3=$[${a}*${b} ]c4=$[${a}/${b}]c5=$[${a}%${b}]echo ‘a + b=’ ${c1}echo ‘a – b=’ ${c2 }echo ‘a * b=’ ${c3}echo ‘a/b=’ ${c4}echo ‘a % b=’ ${c5}表达式方法2
除了这些操作之外,shell还支持自动递增和自动递减操作。下面以let 命令为例:
#!/bin/shc1=2c2=2c3=2let c1++let c2–let c3+=1echo ‘c1=’ ${c1}echo ‘c2=’ ${c2}echo ‘c3=’ ${c3}自增加和减少
以上的操作方法都有各自的要求,我们在使用的时候一定要清楚如何使用。另外,默认情况下,shell不支持小数运算。可以发现上面的运算都是整数运算。如何进行小数运算?
我们可以使用Linux平台下的bc计算器进行小数运算。
#!/bin/sha=1.411b=1.332c1=`回显’$a+$b’|bc`c2=`回显’$a-$b’|bc`c3=`回显’$a*$b’| bc`c4=`echo ‘scale=3;$a/$b’|bc` #scale用于指定小数位数echo $c1echo $c2echo $c3echo $c4 小数运算
数组
Shell 可以定义一个数组来存储多个数据。格式如下。数组中的每个元素需要用空格分隔。定义数组时不需要指定数组的大小。
数组=(值1 值2 值3 .)
访问数组时,可以使用方括号和下标([下标])来访问每个元素,其下标也从0开始。
#!/bin/sha=(hello world code)echo ${a[0]}echo ${a[1]}echo ${a[2]} 数组访问
除了使用下标访问单个元素之外,还有其他方法获取所有元素吗?我们可以使用* 和@ 符号获取数组的所有元素。这两个符号是不是很熟悉?我们在字符串变量操作章节中使用了这两个符号。
#!/bin/sha=(hello world code)echo ${a[*]}echo ${a[@]} 获取数组所有元素
同样,与获取字符变量的长度类似,我们也可以使用#符号来获取数组的长度。
#!/bin/sha=(hello world code)echo ${#a[*]}获取数组长度
关系运算
关系运算也是比较运算,因为它们在shell中都是字符串类型。我们如何比较数字的大小? shell提供了一些专门用于关系操作的运算符。如下:
-eq:可以判断两个数是否相等。如果它们相等,则为真。格式为[ $a -eq $b ]; -ne:可以判断两个数是否不相等。如果它们不相等,则为真。格式为[ $a -ne $b ]; -gt:可以判断左边的数字是否大于右边的数字。如果是这样,那就是真的。格式为[ $a -gt $b ]; -lt:可以判断左边的数字是否小于右边的数字。如果是这样,那就是真的。则为true,格式为[ $a -lt $b ]; -ge:判断左边的数字是否大于等于右边的数字,如果是则为真,格式为[ $a -ge $b ]; -le:可以判断左边的数字是否小于或等于右边的数字,如果是则为真,格式为[ $a -le $b ]。这里需要注意的是,变量和括号之间用空格分隔,运算符和变量之间也用空格分隔。具体来说,我们可以通过一个例子来进一步了解它们的使用。
#!/bin/sha=1b=2if [ $a -eq $b ];then echo ‘yes’else echo ‘no’fiif [ $a -ne $b ];then echo ‘yes’else echo ‘no’fiif [ $a -gt $b ];then echo ‘yes’else echo ‘no’fiif [ $a -lt $b ];then echo ‘yes’else echo ‘no’fi 使用判断语句if.else这里,详细内容可以在条件语句章节中深入了解。
关系运算
以上是数值关系运算。当然,字符串也有类似的元素符号。
=:判断两个字符串是否相等,如果相等则为真,[ $a=$b ];=判断两个字符串是否不相等,如果不相等则为真,[ $a !=$ b]; -z 判断字符串长度是否为0,如果是则为真,[-z $a]; -n 判断字符串长度是否不为0,如果是则为真,[-n ‘$a’]; $ 判断字符串是否为空,否则为true,[ $a ]; #!/bin/sha=’hello’b=’hello’c=’world’d=”echo ‘a=b ?’ if [ $a=$b ];then echo ‘yes’else echo ‘no’fiecho ‘a !=b ?’if [ $a !=$b ];then echo ‘yes’else echo ‘no’fiecho ‘a !=c ?’if [ $a !=$c ];then echo ‘yes’else echo ‘no’fiecho ‘len(c)=0 ?’if [ -z $c ];then echo ‘yes’else echo ‘no’fiecho ‘len(d) !=0 ?’if [ -n ‘$d’ ];then echo ‘yes’else echo ‘no’fiecho ‘len(a)=0 ?’if [ $a ];然后echo ‘yes’else echo ‘no’fi 字符串
逻辑运算
除了上面我们介绍的算术运算和关系运算之外,Shell还有逻辑运算。逻辑运算主要包括逻辑与和逻辑或运算。
逻辑与运算用表达式表示,如果运算符两边都为真,则结果为真;逻辑或运算用||表示,只要该运算符两侧之一为真,结果就为真。让我们通过一个例子来进一步了解逻辑运算。
#!/bin/sha=1b=2c=1echo ‘a=c a !=b ?’if [[ $a -eq $c $a -ne $b ]];then echo ‘yes’else echo ‘no’fiecho ‘a=b || a=c ?’if [[ $a -eq $b || $a -eq $c ]];then echo ‘yes’else echo ‘no’fi 逻辑运算
条件语句
和其他语言一样,shell脚本编程也可以进行流程控制,比如条件语句、循环语句等。本章我们学习条件语句。
条件语句主要由if else then elif fi等关键字组成。主要可以形成以下几种情况:
单分支、双分支、多分支:多个条件、多个执行分支。单分支的情况,结构比较简单,只有一个条件,一个执行分支。
a=1if [ $a==1 ];then echo ‘a=1’fi 单分支
在双分支的情况下,比单分支多一个分支来执行分治。
a=1if [ $a==2 ];then echo ‘a=1’else echo ‘a !=1’fi 双分支
多分支结构更适合多条件、多执行分支的情况。
a=2if [ $a==1 ];然后echo ‘a=1’elif [ $a==2 ];然后echo ‘a=2’else echo $afi 多分支
对于if分支语句,大家要注意格式问题。 []中的条件表达式与两边的括号之间必须用空格分隔。
另外,还有一种多分支语句case语句,格式为:
case $variable in ‘value1’) 执行语句1 ; ‘value2’) 执行语句2 ; *) 执行其他语句;esac 让我们看一个case 语句的示例:
#!/bin/shread -p ‘请输入一个数字:’ numcase $num in’1′) echo ‘开始第1 个流程’ ;’2′) echo ‘开始第2 个流程’ ;*) echo ‘不执行任何操作’逃逸声明
以上只是一些简单的语句结构。只要掌握了这些分支语句的用法,就可以组成更复杂的分支语句,比如多个判断条件、多个分支嵌套等。
循环语句
过程控制的另一种方法是循环语句。 Shell中有四种常见的循环语句:for while Until select。我们依次来看看这四种循环方式。
我们可以根据需要在for 循环for(()) 和for.in 两种形式之间进行选择。
我们先看一下for(())的循环格式:
for((ex1;exp2;exp3))do循环体done这里我们可以结合数组的知识来举一个循环的例子。
a=(‘hello’ ‘world’ ‘hello’ ‘shell’)for((i=0;i4;i++))do echo ${a[i]}donefor 循环
我们通过定义递增变量i 来按顺序访问数组的每个元素。有没有更简单的变量方法?让我们看下面的例子。
a=(‘hello’ ‘world’ ‘hello’ ‘shell’)for v in ${a[*]}do echo $vdonefor.in
上面的示例使用第二个for.in 循环格式。格式如下。它可以方便地遍历列表或数组,而无需定义递增/递减变量。
for var in listdo 循环体完成接下来我们看一下while 循环。 while循环的格式如下:
while [条件表达式] do 循环体done 让我们看另一个例子:
a=(‘hello’ ‘world’ ‘hello’ ‘shell’)i=0while [ $i -lt 4 ]do echo ${a[i]} let i++donewhile
while循环需要注意条件表达式的写法。相信看过上面关于条件语句的同学已经很清楚了。
在shell中,有一个until循环,它与while循环正好相反; while循环中,条件表达式为true,进入循环体。在until循环中,条件表达式不为真,进入循环。直到循环的格式如下:
直到[条件表达式] do循环体完成我们稍微改变上面的while循环示例的条件表达式。
a=(‘hello’ ‘world’ ‘hello’ ‘shell’)i=0until [ $i -ge 4 ]do echo ${a[i]} let i++doneuntil
对于until循环语句来说,一般上面的循环语句都比较常用。
最后,还有一个比较特殊的循环选择。我们先看一下它的格式:
select var in listdo statementsdone 为什么说是特殊循环呢?让我们看下面的例子:
a=(‘hello’ ‘world’ ‘hello’ ‘shell’)i=0select v in ${a[*]}do echo $vdoneselect
从这个例子中我们可以发现,每行打印的前面都有一个序列号。我们也可以选择其中一个序号,就会输出相应的所需结果。它是外壳中独特的结构。它通常与case.in 语句一起使用。通过选择不同的序列号,您可以选择在case.in中执行不同的操作。
a=(‘公司A’ ‘公司B’ ‘公司C’ ‘公司D’)select v in ${a[*]}do case $v in ‘公司A’) echo ‘恭喜,您选择了A公司! ‘ 休息; ‘B公司’) echo ‘恭喜,您选择了B公司! ‘ 休息; ‘C公司’) echo ‘恭喜你,您选择了C公司! ‘ 休息; ‘D公司’) echo ‘恭喜你选择了D公司! ‘ 休息; *) echo ‘您还没有选择任何公司,请重新选择! ‘ esacdoneselect in 和case in
函数
在功能复杂的脚本程序中,会出现很多重复或类似的功能。为了避免大量的重复代码,函数的作用此时就体现出来了。一般我们会把一些类似或者重复的操作抽象成一个函数,根据不同的参数返回相应的结果。这样,程序会更加模块化,逻辑更加清晰,更容易开发和维护。
当然,shell中也可以使用函数。其格式如下:
function name() { # 函数体返回值} 这里function是用来定义函数的关键字,name是需要自定义的函数名,return value是函数的返回值。现在让我们定义一个函数:
function test1() { echo ‘这是一个函数’ return 0} 如何调用函数?直接写函数名就可以了。让我们看一下该程序的完整版本:
function test1() { echo ‘这是一个函数’ return 0}test1 #调用函数function 1
上面的函数没有参数,那如果有参数呢?我们继续看例子:
function test2() { echo ‘parameter1 : $1’ echo ‘parameter2 : $2’ return 3}test2 1 2 #调用函数echo $? #获取函数返回值函数2
事实上,函数中不需要定义形参。调用时只需在函数后面添加实际参数即可。在函数体中,可以通过添加$和参数号来访问参数。例如第一个参数$1,而第十个参数上方需要添加{}符号,如${10},并且调用函数时需要调用函数返回值。然后通过$? 得到它。
文件包含
有时,多个脚本可能会使用某个函数。在这种情况下,您需要将此函数放在公共文件中。需要该功能的脚本可以直接包含该公共文件。这是文件
的包含,同样的Shell也是支持文件包含的。
在Shell中可以使用.或source加上文件名来包含文件。直接来看例子:
先建一个文件test_one.sh:
#test_one.shvar1=1再建一个文件test_two.sh:
#test_two.shvar2=2下面我们在建一个文件包含test_one.sh和test_two.sh这两个文件。
. ./test_one.shsource ./test_two.shecho “file one var1=${var1}”echo “file two var2=${var2}”文件包含
原创文章,作者:小su,如若转载,请注明出处:https://www.sudun.com/ask/112802.html
用户评论
追忆思域。
万字总结真的太详细了!我之前学 Shell 总是卡在某个地方,看完了这篇博客,终于通透了。受益匪浅!以后可以用来写自己的脚本了,感谢分享!
有16位网友表示赞同!
坠入深海i
虽然标题说“完全”掌握,还是感觉有些难实现,毕竟 Shell 的应用场景实在太多了吧? 但这篇总结确实很有帮助,让我对基础语法和常用命令有了更加清晰的认识!
有19位网友表示赞同!
不忘初心
看完这份总结,我算是初步理解了 Shell 编程的一些基本原理。其实很多东西都能自己探索出来,但有这样的详细总结真的可以节省很多时间嘛!佩服博主!
有11位网友表示赞同!
反正是我
作为一个完全小白来说,这篇万字总结也太长了点吧?虽然内容很全面,但是一下子看完太累人,我还是更喜欢一些短小精悍的教程。希望以后还能看到一些针对特定主题的小结哦!
有19位网友表示赞同!
心亡则人忘
我一直在学习 linux 的各种命令,这篇文章确实很有帮助!帮我梳理了很多模糊的概念,特别是那些比较高级的 Shell 命令都解释得很清楚,让我茅塞顿开!
有7位网友表示赞同!
百合的盛世恋
Shell 编程真的太实用了一点,虽然看的时候感觉有点枯燥乏味,但还是得认真学习理解。这篇总结写的很全面,把很多关键问题都罗列出来了,对于想要深入学习 Shell 的朋友来说非常有参考价值!
有11位网友表示赞同!
素颜倾城
万字总结也太长了吧? 我只想快速掌握Shell编程的基本语法和常用命令,太浪费时间了。希望博主以后能更新一些更精炼的学习资源,针对不同类型的学习者提供不同的学习内容。
有20位网友表示赞同!
命硬
这篇博客写的真的太好了! 把Shell编程从基础语法到进阶应用都介绍得很详细,而且还配有详细的代码示例,非常实用!我之前学习的时候也遇到过很多问题,现在有了这份总结可以完美解决!
有6位网友表示赞同!
看我发功喷飞你
感觉这部总结缺少实战环节,理论讲解虽好,但如果没有实际案例操作练习,很难真正理解和掌握Shell编程。希望能看到一些更有针对性的练习题或案例分析!
有11位网友表示赞同!
有一种中毒叫上瘾成咆哮i
学习编程最重要的一点是实践!这篇总结虽然很全面,但仅仅停留在理论讲解上还不足够。希望博主能后续分享一些具体的项目实战,让读者在实践中学习和巩固Shell编程知识!
有8位网友表示赞同!
迷路的男人
我觉得这篇文章写的很好,很有帮助! 我一直想学习 Shell 编程,但一直不知道从哪里开始,这篇总结让我有了清晰的学习方向。
有7位网友表示赞同!
泪湿青衫
学习 Shell 编程真是太难了! 这篇文章虽然很长,但是内容还是比较系统的,至少帮我理清楚了部分概念。希望以后能够学习更多的实践技巧!
有5位网友表示赞同!
抚涟i
对于新手来说,这份总结简直是宝典! 我以前对 Shell 编程完全不知道该如何下手,这篇博文让我明确了许多概念,并且提供了很多详细的示例代码,非常实用!
有11位网友表示赞同!
我没有爱人i
Shell 编程是一个很有意思的领域! 本篇文章写的很好,尤其是那些高级命令的解释,对于想要深入学习 Shell 的朋友来说非常有帮助!
有20位网友表示赞同!
千城暮雪
太棒了! 我一直想学习 Shell 编程,但一直找不到合适的学习资源。这篇总结简直是救星! 希望能看到更多的类似文章分享!
有5位网友表示赞同!
半梦半醒i
这篇文章让我对 Shell 编程的学习有了新的启发!之前我一直觉得 Shell 编程很复杂,看完这篇博文后发现它其实并不难懂。内容非常详细,值得推荐!
有7位网友表示赞同!
不离我
我感觉这篇万字总结写的很有深度,解释了 Shell 编程的核心概念和常用技巧。对想要系统学习 Shell 编程的人来说是一个很好的参考材料!
有15位网友表示赞同!
七级床震
作为一名初学者,我觉得这篇总结有点难理解。我希望能够看到一些更加浅显易懂的入门教程,帮助我更好地掌握 Shell 编程的基础知识!
有10位网友表示赞同!
龙吟凤
这篇文章虽然很详细,但缺少一些交互环节,无法真正检验自己的学习成果。期待博主后续更新一些练习题和案例分析,让学习过程更有趣更有针对性!
有9位网友表示赞同!