技术经验分享:Bash脚本命令使用详解

本文涉及的产品
云原生内存数据库 Tair,内存型 2GB
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Redis 版,经济版 1GB 1个月
简介: 技术经验分享:Bash脚本命令使用详解

什么是 Bash


简介


Bash(GNU Bourne-Again Shell)是一个为 GNU 计划编写的 Unix shell,它是许多 Linux 平台默认使用的 shell。


shell 是一个命令解释器,是介于操作系统内核与用户之间的一个绝缘层。准确地说,它也是能力很强的计算机语言,被称为解释性语言或脚本语言。它可以通过将系统调用、公共程序、工具和编译过的二进制程序”粘合“在一起来建立应用,这是大多数脚本语言的共同特征,所以有时候脚本语言又叫做“胶水语言”。


事实上,所有的 UNIX 命令和工具再加上公共程序,对于 shell 脚本来说,都是可调用的。Shell 脚本对于管理系统任务和其它的重复工作的例程来说,表现的非常好,根本不需要那些华而不实的成熟紧凑的编译型程序语言。


运行 Bash 脚本的方式:


#!/bin/bash


#这一行是表示使用 /bin/bash 作为脚本的解释器


#这行要放在脚本的行首并且不要省略。


# 使用shell来执行


sh hello.sh


# 使用bash来执行


bash hello.sh


# 使用.来执行


. ./hello.sh


# 使用source来执行


source hello.sh


# 还可以赋予脚本所有者执行权限,允许该用户执行该脚本


chmod u+rx hello.sh


./hello.sh


bash特殊字符(上)


注释(#)


行首以 # 开头(除#!之外)的是注释。#! 是用于指定当前脚本的解释器,我们这里为 bash,且应该指明完整路径,所以为 /bin/bash


分号(;)


使用分号 ; 可以在同一行上写两个或两个以上的命令。


点号(.)


等价于 source 命令


bash 中的 source 命令用于在当前 bash 环境下读取并执行 FileName.sh 中的命令。


source test.sh


. test.sh


引号


双引号(")


“STRING” 将会阻止(解释)STRING 中大部分特殊的字符。后面的实验会详细说明。


单引号(’)


‘STRING’ 将会阻止 STRING 中所有特殊字符的解释,这是一种比使用"更强烈的形式。后面的实验会详细说明。


反引号()</p> <p>命令替换</p> <p>反引号中的命令会优先执行,如:</p> <p>cpmkdir backtest.sh back</p> <p>ls</p> <p>先创建了 back 目录,然后复制 test.sh 到 back 目录。</p> <p>冒号(:)</p> <p>空命令</p> <p>等价于“NOP”(no op,一个什么也不干的命令)。也可以被认为与 shell 的内建命令 true 作用相同。“:”命令是一个 bash 的内建命令,它的退出码(exit status)是(0)。</p> <p>#!/bin/bash</p> <p>while :</p> <p>do</p> <p> echo "endless loop"</p> <p>done</p> <p>等价于</p> <p>#!/bin/bash</p> <p>while true</p> <p>do</p> <p> echo "endless loop"</p> <p>done</p> <p>可以在 if/then 中作占位符:</p> <p>#!/bin/bash</p> <p>condition=5</p> <p>if 【 $condition -gt 0 】 </p> <p>#gt表示greater than,也就是大于,同样有-lt(小于),-eq(等于)</p> <p>then : # 什么都不做,退出分支</p> <p>else</p> <p> echo "$condition"</p> <p>fi</p> <p>变量扩展/子串替换</p> <p>在与 > 重定向操作符结合使用时,将会把一个文件清空,但是并不会修改这个文件的权限。如果之前这个文件并不存在,那么就创建这个文件。</p> <p>: > test.sh # 文件“test.sh”现在被清空了</p> <p># 与 cat /dev/null > test.sh 的作用相同</p> <p># 然而,这并不会产生一个新的进程, 因为“:”是一个内建命令</p> <p>在与 ] 重定向操作符结合使用时,将不会对预先存在的目标文件 : ] target_file 产生任何影响。如果这个文件之前并不存在,那么就创建它。</p> <p>问号(?)</p> <p>测试操作符</p> <p>在一个双括号结构中,? 就是 C 语言的三元操作符,如:</p> <p>vim test.sh</p> <p>输入如下代码,并保存:</p> <p> #!/bin/bash</p> <p> a=10</p> <p> (( t=a<50?8:9 ))</p> <p> echo $t</p> <p>运行测试</p> <p>bash test.sh</p> <p>8</p> <p>美元符号($)</p> <p>引用变量</p> <p>bash特殊字符(下)</p> <p>小括号(( ))</p> <p>在括号中的变量,由于是在子 shell 中,所以对于脚本剩下的部分是不可用的。父进程,也就是脚本本身,将不能够读取在子进程中创建的变量,也就是在子 shell 中创建的变量。如:</p> <p>vim test20.sh</p> <p>输入代码:</p> <p>#!/bin/bash</p> <p>a=123</p> <p>( a=321; )</p> <p>echo "$a" #a的值为123而不是321,因为括号将判断为局部变量</p> <p>运行代码:</p> <p>bash test20.sh</p> <p>a = 123</p> <p>在圆括号中 a 变量,更像是一个局部变量。</p> <p>2.初始化数组</p> <p>创建数组</p> <p>vim test21.sh</p> <p>输入代码:</p> <p>#!/bin/bash</p> <p>arr=(1 4 5 7 9 21)</p> <p>echo ${arr【3】} # get a value of arr</p> <p>运行代码:</p> <p>bash test21.sh</p> <p>7</p> <p>大括号({ })</p> <p>文件名扩展</p> <p>复制 t.txt 的内容到 t.back 中</p> <p>vim //代码效果参考:http://hnjlyzjd.com/hw/wz_24539.html<p></p> test22.sh</p> <p>输入代码:</p> <p>#!/bin/bash</p> <p>if 【 ! -w 't.txt' 】;</p> <p>then</p> <p> touch t.txt</p> <p>fi</p> <p>echo 'test text' ] t.txt</p> <p>cp t.{txt,back}</p> <p>运行代码:</p> <p>bash test22.sh</p> <p>查看运行结果:</p> <p>ls</p> <p>cat t.txt</p> <p>cat t.back</p> <p>注意: 在大括号中,不允许有空白,除非这个空白被引用或转义。</p> <p>代码块</p> <p>代码块,又被称为内部组,这个结构事实上创建了一个匿名函数(一个没有名字的函数)。然而,与“标准”函数不同的是,在其中声明的变量,对于脚本其他部分的代码来说还是可见的。</p> <p>vim test23.sh</p> <p>输入代码:</p> <p>#!/bin/bash</p> <p>a=123</p> <p>{ a=321; }</p> <p>echo "a = $a"</p> <p>运行代码:</p> <p>bash test23.sh</p> <p>a = 321</p> <p>变量 a 的值被更改了。</p> <p>中括号(【 】)</p> <p>条件测试</p> <p>条件测试表达式放在 【 】 中。下列练习中的 -lt (less than)表示小于号。</p> <p>vim test24.sh</p> <p>输入代码:</p> <p>#!/bin/bash</p> <p>a=5</p> <p>if 【 $a -lt 10 】</p> <p>then</p> <p> echo "a: $a"</p> <p>else</p> <p> echo 'a>=10'</p> <p>fi</p> <p>运行代码:</p> <p>bash test24.sh</p> <p>a: 5</p> <p>数组元素</p> <p>在一个 array //代码效果参考:http://hnjlyzjd.com/hw/wz_24547.html<p></p> 结构的上下文中,中括号用来引用数组中每个元素的编号。</p> <p>vim test25.sh</p> <p>输入代码:</p> <p>#!/bin/bash</p> <p>arr=(12 22 32)</p> <p>arr【0】=10</p> <p>echo ${arr【0】}</p> <p>运行代码:</p> <p>bash test25.sh</p> <p>10</p> <p>尖括号()</p> <p>重定向</p> <p>test.sh > filename:重定向 test.sh 的输出到文件 filename 中。如果 filename 存在的话,那么将会被覆盖。</p> <p>test.sh &> filename:重定向 test.sh 的 stdout(标准输出)和 stderr(标准错误)到 filename 中。</p> <p>test.sh >&2:重定向 test.sh 的 stdout 到 stderr 中。</p> <p>test.sh ] filename:把 test.sh 的输出追加到文件 filename 中。如果 filename 不存在的话,将会被创建。</p> <p>竖线(|)</p> <p>管道</p> <p>分析前边命令的输出,并将输出作为后边命令的输入。这是一种产生命令链的好方法。</p> <p>破折号(-)</p> <p>波浪号(~)</p> <p>目录</p> <p>表示 home 目录。</p> <p>特殊变量</p> <p>位置参数</p> <p>从命令行传递到脚本的参数:$0,$1,$2,$3…</p> <p>$0 就是脚本文件自身的名字,$1 是第一个参数,$2 是第二个参数,$3 是第三个参数,然后是第四个。9 之 后 的 位 置 参 数 就 必 须 用 大 括 号 括 起 来 了 , 比 如 , 9 之后的位置参数就必须用大括号括起来了,比如,9之后的位置参数就必须用大括号括起来了,比如,{10},11 , {11},11,{12}。</p> <p>$# : 传递到脚本的参数个数</p> <p>$* : 以一个单字符串显示所有向脚本传递的参数。与位置变量不同,此选项参数可超过 9 个</p> <p>$$ : 脚本运行的当前进程 ID 号</p> <p>$! : 后台运行的最后一个进程的进程 ID 号</p> <p>$@ : 与 $* 相同,但是使用时加引号,并在引号中返回每个参数</p> <p>$: 显示 shell 使用的当前选项,与 set 命令功能相同</p> <p>$? : 显示最后命令的退出状态。 0 表示没有错误,其他任何值表明有错误。</p> <p>位置参数实例</p> <p>vim test30.sh</p> <p>#!/bin/bash</p> <p># 作为用例, 调用这个脚本至少需要10个参数, 比如:</p> <p># bash test.sh 1 2 3 4 5 6 7 8 9 10</p> <p>MINPARAMS=10</p> <p>echo</p> <p>echo "The name of this script is \"$0\"."</p> <p>echo "The name of this script is \"basename $0\"."</p> <p>echo</p> <p>if 【 -n "$1" 】 # 测试变量被引用.</p> <p>then</p> <p>echo "Parameter #1 is $1" # 需要引用才能够转义"#"</p> <p>fi</p> <p>if 【 -n "$2" 】</p> <p>then</p> <p>echo "Parameter #2 is $2"</p> <p>fi</p> <p>if 【 -n "${10}" 】 # 大于$9的参数必须用{}括起来.</p> <p>then</p> <p>echo "Parameter #10 is ${10}"</p> <p>fi</p> <p>echo "-----------------------------------"</p> <p>echo "All the command-line parameters are: "$*""</p> <p>if 【 $# -lt "$MINPARAMS" 】</p> <p>then</p> <p> echo</p> <p> echo "This script needs at least $MINPARAMS command-line arguments!"</p> <p>fi</p> <p>echo</p> <p>exit 0</p> <p>运行代码:</p> <p>bash test30.sh 1 2 10</p> <p>The name of this script is "test.sh".</p> <p>The name of this script is "test.sh".</p> <p>Parameter #1 is 1</p> <p>Parameter #2 is 2</p> <p>-----------------------------------</p> <p>All the command-line parameters are: 1 2 10</p> <p>This script needs at least 10 command-line arguments!</p> <p>基本运算符</p> <p>算数运算符</p> <p>vim test.sh</p> <p>#!/bin/bash</p> <p>a=10</p> <p>b=20</p> <p>val=expr $a + $b</p> <p>echo "a + b : $val"</p> <p>val=expr $a - $b</p> <p>echo "a - b : $val"</p> <p>val=expr $a * $b</p> <p>echo "a * b : $val"</p> <p>val=expr $b / $a</p> <p>echo "b / a : $val"</p> <p>val=expr $b % $a`


echo "b % a : $val"


if 【 $a == $b 】


then


echo "a == b"


fi


if 【 $a != $b 】


then


echo "a != b"


fi


运行


bash test.sh


a + b : 30


a - b : -10


a b : 200


b / a : 2


b % a : 0


a != b


原生 bash 不支持简单的数学运算,但是可以通过其他命令来实现,例如 awk 和 expr,expr 最常用。


expr 是一款表达式计算工具,使用它能完成表达式的求值操作。


注意使用的反引号(esc 键下边)


表达式和运算符之间要有空格 $a + $b 写成 a + a+a+b 不行


条件表达式要放在方括号之间,并且要有空格 【 $a == b 】 写 成 【 b 】 写成 【b】写成【a==$b】 不行


乘号()前边必须加反斜杠()才能实现乘法运算


关系运算符


关系运算符只支持数字,不支持字符串,除非字符串的值是数字。


#!/bin/bash


a=10


b=20


if 【 $a -eq $b 】


then


echo "$a -eq $b : a == b"


else


echo "$a -eq $b: a != b"


fi


逻辑运算符


#!/bin/bash


a=10


b=20


if 【【 $a -lt 100 && $b -gt 100 】】


then


echo "return true"


else


echo "return false"


fi


if 【【 $a -lt 100 || $b -gt 100 】】


then


echo "return true"


else


echo "return false"


fi


字符串运算符


#!/bin/bash


a="abc"


b="efg"


if 【 $a = $b 】


then


echo "$a = $b : a == b"


else


echo "$a = $b: a != b"


fi


if 【 -n $a 】


then


echo "-n $a : The string length is not 0"


else


echo "-n $a : The string length is 0"


fi


if 【 $a 】


then


echo "$a : The string is not empty"


else


echo "$a : The string is empty"


fi


结果


abc = efg: a != b


-n abc : The string length is not 0


abc : The string is not empty


文件测试运算符


实例:


#!/bin/bash


file="/home/shiyanlou/test.sh"


if 【 -r $file 】


then


echo "The file is readable"


else


echo "The file is not readable"


fi


if 【 -e $file 】


then


echo "File exists"


else


echo "File not exists"


fi


结果


The file is readable


File exists


思考


浮点运算,比如实现求圆的面积和周长。


expr 只能用于整数计算,可以使用 bc 或者 awk 进行浮点数运算。


#!/bin/bash


radius=2.4


pi=3.14159


girth=$(echo "scale=4; 3.14 2 $radius" | bc)


area=$(echo "scale=4; 3.14 $radius $radius" | bc)


echo "girth=$girth"


echo "area=$area"


以上代码如果想在环境中运行,需要先安装 bc。


sudo apt-get update


sudo apt-get install bc


流程控制


if else


if


if 语句语法格式:


if condition


then


command1


command2


...


commandN


fi


if else


if else 语法格式:


if condition


then


command1


command2


...


commandN


else


command


fi


if-elif-else 语法格式:


if condition1


then


command1


elif condition2


then


command2


else


commandN


fi


for 循环


for 循环一般格式为:


for var in item1 item2 ... itemN


do


command1


command2


...


commandN


done


while 语句


while 循环用于不断执行一系列命令,也用于从输入文件中读取数据;命令通常为测试条件。其格式为:


while condition


do


command


done


无限循环


无限循环语法格式:


while :


do


command


done


或者


while true


do


command


done


或者


for (( ; ; ))


until 循环


until 循环执行一系列命令直至条件为真时停止。 until 循环与 while 循环在处理方式上刚好相反。 一般 while 循环优于 until 循环,但在某些时候—也只是极少数情况下,until 循环更加有用。 until 语法格式:


until condition


do


command


done


case


Shell case 语句为多选择语句。可以用 case 语句匹配一个值与一个模式,如果匹配成功,执行相匹配的命令。case 语句格式如下:


case 值 in


模式1)


command1


command2


...


commandN


;;


模式2)


command1


command2


...


commandN


;;


esac


取值后面必须为单词 in,每一模式必须以右括号结束。取值可以为变量或常数。匹配发现取值符合某一模式后,其间所有命令开始执行直至 ;;。


取值将检测匹配的每一个模式。一旦模式匹配,则执行完匹配模式相应命令后不再继续其他模式。如果无一匹配模式,使用星号 捕获该值,再执行后面的命令。


下面的脚本提示输入 1 到 4,与每一种模式进行匹配:


echo 'Enter a number between 1 and 4:'


echo 'The number you entered is:'


read aNum


case $aNum in


1) echo 'You have chosen 1'


;;


2) echo 'You have chosen 2'


;;


3) echo 'You have chosen 3'


;;


4) echo 'You have chosen 4'


;;


) echo 'You did not enter a number between 1 and 4'


;;


esac


输入不同的内容,会有不同的结果,例如:


Enter a number between 1 and 4:


The number you entered is:


3


You have chosen 3


跳出循环


在循环过程中,有时候需要在未达到循环结束条件时强制跳出循环,Shell 使用两个命令来实现该功能:break 和 continue。


break 命令


break 命令允许跳出所有循环(终止执行后面的所有循环)。


下面的例子中,脚本进入死循环直至用户输入数字大于 5。要跳出这个循环,返回到 shell 提示符下,需要使用 break 命令。


#!/bin/bash


while :


do


echo -n "Enter a number between 1 and 5:"


read aNum


case $aNum in


1|2|3|4|5) echo "The number you entered is $aNum!"


;;


) echo "The number you entered is not between 1 and 5! game over!"


break


;;


esac


done


执行以上代码,输出结果为:


Enter a number between 1 and 5:3


The number you entered is 3!


Enter a number between 1 and 5:7


The number you entered is not between 1 and 5! game over!


continue


continue 命令与 break 命令类似,只有一点差别,它不会跳出所有循环,仅仅跳出当前循环。 对上面的例子进行修改:


#!/bin/bash


while :


do


echo -n "Enter a number between 1 and 5: "


read aNum


case $aNum in


1|2|3|4|5) echo "The number you entered is $aNum!"


;;


) echo "The number you entered is not between 1 and 5!"


continue


echo "game over"


;;


esac


done


运行代码发现,当输入大于 5 的数字时,该例中的循环不会结束,语句 echo “Game is over!” 永远不会被执行。


EOF


本文作者: liftsail 本文链接: 关于博主: 评论和私信会在第一时间回复。或者直接私信我。 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处! 声援博主: 如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
2月前
|
监控 安全 Shell
防止员工泄密的措施:在Linux环境下使用Bash脚本实现日志监控
在Linux环境下,为防止员工泄密,本文提出使用Bash脚本进行日志监控。脚本会定期检查系统日志文件,搜索敏感关键词(如&quot;password&quot;、&quot;confidential&quot;、&quot;secret&quot;),并将匹配项记录到临时日志文件。当检测到可疑活动时,脚本通过curl自动将数据POST到公司内部网站进行分析处理,增强信息安全防护。
145 0
|
2月前
|
Linux Shell Windows
4:Bash shell命令-步入Linux的现代方法
4:Bash shell命令-步入Linux的现代方法
64 0
|
9月前
|
关系型数据库 MySQL Shell
【Linux命令】-bash: mysql: command not found
【Linux命令】-bash: mysql: command not found
65 0
|
2月前
|
存储 Shell Linux
Linux Bash 脚本中的 IFS 是什么?
【4月更文挑战第25天】
41 0
Linux Bash 脚本中的 IFS 是什么?
|
2月前
|
存储 弹性计算 运维
用bash脚本创建目录
【4月更文挑战第29天】
21 3
|
2月前
|
Shell
shell 命令(一)概述【别名、 bash重定向 、定义变量】
shell 命令(一)概述【别名、 bash重定向 、定义变量】
29 0
|
2月前
|
Linux Shell 开发工具
linux】-bash:vim:未找到命令
linux】-bash:vim:未找到命令
34 0
|
2月前
|
存储 Unix Shell
【简化Cmake编译过程 】编写通用的bash脚本:简化和构建cmake高效自动化任务
【简化Cmake编译过程 】编写通用的bash脚本:简化和构建cmake高效自动化任务
87 0
|
2月前
|
Shell
-bash: lsb_release: 未找到命令
-bash: lsb_release: 未找到命令
|
8月前
|
Shell
bash 反弹命令的浅分析
bash 反弹命令的浅分析
34 0