shell脚本的使用该熟练起来了,你说呢?(篇四)
阅读原文时间:2023年07月10日阅读:1

继续前一篇的文章:

shell脚本的使用该熟练起来了,你说呢?(篇一)

shell脚本的使用该熟练起来了,你说呢?(篇二)

shell脚本的使用该熟练起来了,你说呢?(篇三)

文章里面测试的命令脚本文件,大家关注我公众号后,可以私信我领取文件。

作者:良知犹存

转载授权以及围观:欢迎添加微信公众号:羽林君


Shell test 命令

Shell中的 test 命令用于检查某个条件是否成立,它可以进行数值、字符和文件三个方面的试。

参数

说明

-eq

等于则为真

-ne

不等于则为真

-gt

大于则为真

-ge

大于等于则为真

-lt

小于则为真

-le

小于等于则为真

num1=100num2=100
if test $[num1] -eq $[num2]
then
    echo '两个数相等!'
else
    echo '两个数不相等!'
fi

输出结果:

两个数相等!

代码中的 [] 执行基本的算数运算,如:

a=5
b=6

result=$[a+b] # 注意等号两边不能有空格
echo "result 为:$result"

结果为:

result 为:11

参数

说明

=

等于则为真

!=

不相等则为真

-z 字符串

字符串的长度为零则为真

-n 字符串

字符串的长度不为零则为真

num1="run"
num2="run1"
if test $num1 = $num2
then
    echo '两个字符串相等!'
else
    echo '两个字符串不相等!'
fi

输出结果:

两个字符串不相等!

参数

说明

-e 文件名

如果文件存在则为真

-r 文件名

如果文件存在且可读则为真

-w 文件名

如果文件存在且可写则为真

-x 文件名

如果文件存在且可执行则为真

-s 文件名

如果文件存在且至少有一个字符则为真

-d 文件名

如果文件存在且为目录则为真

-f 文件名

如果文件存在且为普通文件则为真

-c 文件名

如果文件存在且为字符型特殊文件则为真

-b 文件名

如果文件存在且为块特殊文件则为真

cd /usr

if test -e bin
then
    echo '文件已存在!'
else
    echo '文件不存在!'
fi

输出结果:

另外,Shell 还提供了与( -a )、或( -o )、非( ! )三个逻辑操作符用于将测试条件连接起来,其优先级为: ! 最高, -a 次之, -o 最低。

cd /usr
if test -e bin -o -e ros
then
    echo '至少有一个文件存在!'
else
    echo '两个文件都不存在'
fi

输出结果:

Shell 流程控制

和Java、PHP等语言不一样,sh的流程控制不可为空,如(以下为PHP流程控制写法):实例

<?php
if&nbsp;(isset($_GET["q"]))&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;search(q);
}
else&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;不做任何事情
}
?>

在sh/bash里可不能这么写,如果else分支没有语句执行,就不要写这个else。


if 语句语法格式:

if&nbsp;condition
then
&nbsp;&nbsp;&nbsp;&nbsp;command1&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;command2
&nbsp;&nbsp;&nbsp;&nbsp;...
&nbsp;&nbsp;&nbsp;&nbsp;commandN&nbsp;
fi

写成一行(适用于终端命令提示符):

if&nbsp;[&nbsp;$(ps&nbsp;-ef&nbsp;|&nbsp;grep&nbsp;-c&nbsp;"ssh")&nbsp;-gt&nbsp;1&nbsp;];&nbsp;then&nbsp;echo&nbsp;"true";&nbsp;fi

末尾的fi就是if倒过来拼写,后面还会遇到类似的。

if else

if else 语法格式:

if&nbsp;condition
then
&nbsp;&nbsp;&nbsp;&nbsp;command1&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;command2
&nbsp;&nbsp;&nbsp;&nbsp;...
&nbsp;&nbsp;&nbsp;&nbsp;commandN
else
&nbsp;&nbsp;&nbsp;&nbsp;command
fi

if else-if else

if else-if else 语法格式:

if&nbsp;condition1
then
&nbsp;&nbsp;&nbsp;&nbsp;command1
elif&nbsp;condition2&nbsp;
then&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;command2
else
&nbsp;&nbsp;&nbsp;&nbsp;commandN
fi

以下实例判断两个变量是否相等:

a=10
b=20
if&nbsp;[&nbsp;$a&nbsp;==&nbsp;$b&nbsp;]
then
&nbsp;&nbsp;&nbsp;echo&nbsp;"a&nbsp;等于&nbsp;b"
elif&nbsp;[&nbsp;$a&nbsp;-gt&nbsp;$b&nbsp;]
then
&nbsp;&nbsp;&nbsp;echo&nbsp;"a&nbsp;大于&nbsp;b"
elif&nbsp;[&nbsp;$a&nbsp;-lt&nbsp;$b&nbsp;]
then
&nbsp;&nbsp;&nbsp;echo&nbsp;"a&nbsp;小于&nbsp;b"
else
&nbsp;&nbsp;&nbsp;echo&nbsp;"没有符合的条件"
fi

输出结果:

if else 语句经常与 test 命令结合使用,如下所示:

num1=$[2*3]
num2=$[1+5]
if&nbsp;test&nbsp;$[num1]&nbsp;-eq&nbsp;$[num2]
then
&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;'两个数字相等!'
else
&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;'两个数字不相等!'
fi

输出结果:


与其他编程语言类似,Shell支持for循环。

for循环一般格式为:

for&nbsp;var&nbsp;in&nbsp;item1&nbsp;item2&nbsp;...&nbsp;itemN
do
&nbsp;&nbsp;&nbsp;&nbsp;command1
&nbsp;&nbsp;&nbsp;&nbsp;command2
&nbsp;&nbsp;&nbsp;&nbsp;...
&nbsp;&nbsp;&nbsp;&nbsp;commandN
done

写成一行:

for&nbsp;var&nbsp;in&nbsp;item1&nbsp;item2&nbsp;...&nbsp;itemN;&nbsp;do&nbsp;command1;&nbsp;command2…&nbsp;done;

当变量值在列表里,for循环即执行一次所有命令,使用变量名获取列表中的当前取值。命令可为任何有效的shell命令和语句。in列表可以包含替换、字符串和文件名。in列表是可选的,如果不用它,for循环使用命令行的位置参数。

例如,顺序输出当前列表中的数字:

for&nbsp;loop&nbsp;in&nbsp;1&nbsp;2&nbsp;3&nbsp;4&nbsp;5
do
&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;"The&nbsp;value&nbsp;is:&nbsp;$loop"
done

输出结果:

顺序输出字符串中的字符:

for&nbsp;str&nbsp;in&nbsp;'This&nbsp;is&nbsp;a&nbsp;string'
do
&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;$str
done

输出结果:

shell 中的 for 循环不仅可以用文章所述的方法。

对于习惯其他语言 for 循环的朋友来说可能有点别扭。

for((assignment;condition:next));do
&nbsp;&nbsp;&nbsp;&nbsp;command_1;
&nbsp;&nbsp;&nbsp;&nbsp;command_2;
&nbsp;&nbsp;&nbsp;&nbsp;commond_..;
done;

如上所示,这里的 for 循环与 C 中的相似,但并不完全相同。

通常情况下 shell 变量调用需要加 $,但是 for 的 (()) 中不需要,下面来看一个例子:

for((i=1;i<=5;i++));do
&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;"这是第&nbsp;$i&nbsp;次调用";
done;

执行结果:

与 C 中相似,赋值和下一步执行可以放到代码之前循环语句之中执行,这里要注意一点:如果要在循环体中进行 for 中的 next 操作,记得变量要加 $,不然程序会变成死循环。


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

while&nbsp;condition
do
&nbsp;&nbsp;&nbsp;&nbsp;command
done

以下是一个基本的while循环,测试条件是:如果int小于等于5,那么条件返回真。int从0开始,每次循环处理时,int加1。运行上述脚本,返回数字1到5,然后终止。

int=1
while((&nbsp;$int<=5&nbsp;))
do
&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;$int
&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;"int++"
done

运行脚本,输出:

以上实例使用了 Bash let 命令,它用于执行一个或多个表达式,变量计算中不需要加上 $ 来表示变量,具体可查阅:let 命令。(let 命令是 BASH 中用于计算的工具,用于执行一个或多个表达式,变量计算中不需要加上 $ 来表示变量。如果表达式中包含了空格或其他特殊字符,则必须引起来。)

while循环可用于读取键盘信息。下面的例子中,输入信息被设置为变量FILM,按结束循环。

echo&nbsp;'按下&nbsp;<CTRL-D>&nbsp;退出'
echo&nbsp;-n&nbsp;'输入你最喜欢的网站名:&nbsp;'
while&nbsp;read&nbsp;FILM
do
&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;"是的!$FILM&nbsp;是一个好网站"
done

运行脚本,输出类似下面:

无限循环

无限循环语法格式:

while&nbsp;:
do
&nbsp;&nbsp;&nbsp;&nbsp;command
done

或者

while&nbsp;true
do
&nbsp;&nbsp;&nbsp;&nbsp;command
done

或者

for&nbsp;((&nbsp;;&nbsp;;&nbsp;))

until 循环执行一系列命令直至条件为 true 时停止。

until 循环与 while 循环在处理方式上刚好相反。

一般 while 循环优于 until 循环,但在某些时候—也只是极少数情况下,until 循环更加有用。

until 语法格式:

until&nbsp;condition
do
&nbsp;&nbsp;&nbsp;&nbsp;command
done

condition 一般为条件表达式,如果返回值为 false,则继续执行循环体内的语句,否则跳出循环。

以下实例我们使用 until 命令来输出 0 ~ 9 的数字:

a=1
until&nbsp;[&nbsp;!&nbsp;$a&nbsp;-lt&nbsp;6&nbsp;]
do
&nbsp;&nbsp;&nbsp;echo&nbsp;$a
&nbsp;&nbsp;&nbsp;a=`expr&nbsp;$a&nbsp;+&nbsp;1`
done

运行结果:

输出结果为:


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

case&nbsp;值&nbsp;in
模式1)
&nbsp;&nbsp;&nbsp;&nbsp;command1
&nbsp;&nbsp;&nbsp;&nbsp;command2
&nbsp;&nbsp;&nbsp;&nbsp;...
&nbsp;&nbsp;&nbsp;&nbsp;commandN
&nbsp;&nbsp;&nbsp;&nbsp;;;
模式2)
&nbsp;&nbsp;&nbsp;&nbsp;command1
&nbsp;&nbsp;&nbsp;&nbsp;command2
&nbsp;&nbsp;&nbsp;&nbsp;...
&nbsp;&nbsp;&nbsp;&nbsp;commandN
&nbsp;&nbsp;&nbsp;&nbsp;;;
esac

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

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

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

echo&nbsp;'输入&nbsp;1&nbsp;到&nbsp;4&nbsp;之间的数字:'
echo&nbsp;'你输入的数字为:'
read&nbsp;aNum
case&nbsp;$aNum&nbsp;in
&nbsp;&nbsp;&nbsp;&nbsp;1)&nbsp;&nbsp;echo&nbsp;'你选择了&nbsp;1'
&nbsp;&nbsp;&nbsp;&nbsp;;;
&nbsp;&nbsp;&nbsp;&nbsp;2)&nbsp;&nbsp;echo&nbsp;'你选择了&nbsp;2'
&nbsp;&nbsp;&nbsp;&nbsp;;;
&nbsp;&nbsp;&nbsp;&nbsp;3)&nbsp;&nbsp;echo&nbsp;'你选择了&nbsp;3'
&nbsp;&nbsp;&nbsp;&nbsp;;;
&nbsp;&nbsp;&nbsp;&nbsp;4)&nbsp;&nbsp;echo&nbsp;'你选择了&nbsp;4'
&nbsp;&nbsp;&nbsp;&nbsp;;;
&nbsp;&nbsp;&nbsp;&nbsp;*)&nbsp;&nbsp;echo&nbsp;'你没有输入&nbsp;1&nbsp;到&nbsp;4&nbsp;之间的数字'
&nbsp;&nbsp;&nbsp;&nbsp;;;
esac

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


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

break命令

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

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

while&nbsp;:
do
&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;-n&nbsp;"输入&nbsp;1&nbsp;到&nbsp;5&nbsp;之间的数字:"
&nbsp;&nbsp;&nbsp;&nbsp;read&nbsp;aNum
&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;$aNum&nbsp;in
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1|2|3|4|5)&nbsp;echo&nbsp;"你输入的数字为&nbsp;$aNum!"
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*)&nbsp;echo&nbsp;"你输入的数字不是&nbsp;1&nbsp;到&nbsp;5&nbsp;之间的!&nbsp;游戏结束"
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;
&nbsp;&nbsp;&nbsp;&nbsp;esac
done

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

continue

continue命令与break命令类似,只有一点差别,它不会跳出所有循环,仅仅跳出当前循环。

对上面的例子进行修改:

while&nbsp;:
do
&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;-n&nbsp;"输入&nbsp;1&nbsp;到&nbsp;5&nbsp;之间的数字:&nbsp;"
&nbsp;&nbsp;&nbsp;&nbsp;read&nbsp;aNum
&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;$aNum&nbsp;in
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1|2|3|4|5)&nbsp;echo&nbsp;"你输入的数字为&nbsp;$aNum!"
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*)&nbsp;echo&nbsp;"你输入的数字不是&nbsp;1&nbsp;到&nbsp;5&nbsp;之间的!"
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;continue
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;"游戏结束"
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;
&nbsp;&nbsp;&nbsp;&nbsp;esac
done

运行代码发现,当输入大于5的数字时,该例中的循环不会结束,语句 echo "游戏结束" 永远不会被执行。


case … esac 与其他语言中的 switch … case 语句类似,是一种多分枝选择结构,每个 case 分支用右圆括号开始,用两个分号 ;; 表示 break,即执行结束,跳出整个 case … esac 语句,esac(就是 case 反过来)作为结束标记。

case … esac 语法格式如下:

case&nbsp;值&nbsp;in
模式1)
&nbsp;&nbsp;&nbsp;&nbsp;command1
&nbsp;&nbsp;&nbsp;&nbsp;command2
&nbsp;&nbsp;&nbsp;&nbsp;command3
&nbsp;&nbsp;&nbsp;&nbsp;;;
模式2)
&nbsp;&nbsp;&nbsp;&nbsp;command1
&nbsp;&nbsp;&nbsp;&nbsp;command2
&nbsp;&nbsp;&nbsp;&nbsp;command3
&nbsp;&nbsp;&nbsp;&nbsp;;;
*)
&nbsp;&nbsp;&nbsp;&nbsp;command1
&nbsp;&nbsp;&nbsp;&nbsp;command2
&nbsp;&nbsp;&nbsp;&nbsp;command3
&nbsp;&nbsp;&nbsp;&nbsp;;;
esac

case 后为取值,值可以为变量或常数。

值后为关键字 in,接下来是匹配的各种模式,每一模式最后必须以右括号结束,模式支持正则表达式。

site="baidu"

case&nbsp;"$site"&nbsp;in
&nbsp;&nbsp;&nbsp;"baidu")&nbsp;echo&nbsp;"百度搜索"
&nbsp;&nbsp;&nbsp;;;
&nbsp;&nbsp;&nbsp;"google")&nbsp;echo&nbsp;"Google&nbsp;搜索"
&nbsp;&nbsp;&nbsp;;;
&nbsp;&nbsp;&nbsp;"taobao")&nbsp;echo&nbsp;"淘宝网"
&nbsp;&nbsp;&nbsp;;;
esac

输出结果为:

Shell 函数

linux shell 可以用户定义函数,然后在shell脚本中可以随便调用。

shell中函数的定义格式如下:

[&nbsp;function&nbsp;]&nbsp;funname&nbsp;[()]
{
&nbsp;&nbsp;&nbsp;&nbsp;action;

&nbsp;&nbsp;&nbsp;&nbsp;[return&nbsp;int;]
}

说明:

  • 1、可以带function fun() 定义,也可以直接fun() 定义,不带任何参数。

  • 2、参数返回,可以显示加:return 返回,如果不加,将以最后一条命令运行结果,作为返回值。return后跟数值n(0-255

下面的例子定义了一个函数并进行调用:

demoFun(){
&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;"这是我的第一个&nbsp;shell&nbsp;函数!"}
echo&nbsp;"-----函数开始执行-----"
demoFun
echo&nbsp;"-----函数执行完毕-----"

输出结果:

下面定义一个带有return语句的函数:

funWithReturn(){
&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;"这个函数会对输入的两个数字进行相加运算..."
&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;"输入第一个数字:&nbsp;"
&nbsp;&nbsp;&nbsp;&nbsp;read&nbsp;aNum
&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;"输入第二个数字:&nbsp;"
&nbsp;&nbsp;&nbsp;&nbsp;read&nbsp;anotherNum
&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;"两个数字分别为&nbsp;$aNum&nbsp;和&nbsp;$anotherNum&nbsp;!"
&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;$(($aNum+$anotherNum))
}
funWithReturn
echo&nbsp;"输入的两个数字之和为&nbsp;$?&nbsp;!"

输出类似下面:

函数返回值在调用该函数后通过 $? 来获得。

注意:所有函数在使用前必须定义。这意味着必须将函数放在脚本开始部分,直至shell解释器首次发现它时,才可以使用。调用函数仅使用其函数名即可。


在Shell中,调用函数时可以向其传递参数。在函数体内部,通过 $n 的形式来获取参数的值,例如,$1表示第一个参数,$2表示第二个参数…

带参数的函数示例:

funWithParam(){
&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;"第一个参数为&nbsp;$1&nbsp;!"
&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;"第二个参数为&nbsp;$2&nbsp;!"
&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;"第十个参数为&nbsp;$10&nbsp;!"
&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;"第十个参数为&nbsp;${10}&nbsp;!"
&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;"第十一个参数为&nbsp;${11}&nbsp;!"
&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;"参数总数有&nbsp;$#&nbsp;个!"
&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;"作为一个字符串输出所有参数&nbsp;$*&nbsp;!"
}
funWithParam&nbsp;1&nbsp;2&nbsp;3&nbsp;4&nbsp;5&nbsp;6&nbsp;7&nbsp;8&nbsp;9&nbsp;34&nbsp;73

输出结果:

注意,$10 不能获取第十个参数,获取第十个参数需要${10}。当n>=10时,需要使用${n}来获取参数。

另外,还有几个特殊字符用来处理参数:

参数处理

说明

$#

传递到脚本或函数的参数个数

$*

以一个单字符串显示所有向脚本传递的参数

$$

脚本运行的当前进程ID号

$!

后台运行的最后一个进程的ID号

$@

与$*相同,但是使用时加引号,并在引号中返回每个参数。

$-

显示Shell使用的当前选项,与set命令功能相同。

$?

显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。

$? 仅对其上一条指令负责,一旦函数返回后其返回值没有立即保存入参数,那么其返回值将不再能通过 $? 获得。

测试代码:

function&nbsp;demoFun1(){
&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;"这是我的第一个&nbsp;shell&nbsp;函数!"
&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;`expr&nbsp;1&nbsp;+&nbsp;1`
}

demoFun1
echo&nbsp;$?

function&nbsp;demoFun2(){
&nbsp;echo&nbsp;"这是我的第二个&nbsp;shell&nbsp;函数!"
&nbsp;expr&nbsp;1&nbsp;+&nbsp;1
}

demoFun2
echo&nbsp;$?
demoFun1
echo&nbsp;在这里插入命令!
echo&nbsp;$?

输出结果:

调用 demoFun2 后,函数最后一条命令 expr 1 + 1 得到的返回值($?值)为 0,意思是这个命令没有出错。所有的命令的返回值仅表示其是否出错,而不会有其他有含义的结果。

第二次调用 demoFun1 后,没有立即查看 $? 的值,而是先插入了一条别的 echo 命令,最后再查看 $? 的值得到的是 0,也就是上一条 echo 命令的结果,而 demoFun1 的返回值被覆盖了。

下面这个测试,连续使用两次 echo $?,得到的结果不同,更为直观:

function&nbsp;demoFun1(){
&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;"这是我的第一个&nbsp;shell&nbsp;函数!"
&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;`expr&nbsp;1&nbsp;+&nbsp;1`
}

demoFun1
echo&nbsp;$?
echo&nbsp;$?

输出结果:

函数与命令的执行结果可以作为条件语句使用。要注意的是,和 C 语言不同,shell 语言中 0 代表 true,0 以外的值代表 false。

请参见下例:

echo&nbsp;"Hello&nbsp;World&nbsp;!"&nbsp;|&nbsp;grep&nbsp;-e&nbsp;Hello
echo&nbsp;$?
echo&nbsp;"Hello&nbsp;World&nbsp;!"&nbsp;|&nbsp;grep&nbsp;-e&nbsp;Bye
echo&nbsp;$?
if&nbsp;echo&nbsp;"Hello&nbsp;World&nbsp;!"&nbsp;|&nbsp;grep&nbsp;-e&nbsp;Hello
then
&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;true
else
&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;false
fi

if&nbsp;echo&nbsp;"Hello&nbsp;World&nbsp;!"&nbsp;|&nbsp;grep&nbsp;-e&nbsp;Bye
then
&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;true
else
&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;false
fi

function&nbsp;demoFun1(){
&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;0
}

function&nbsp;demoFun2(){
&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;12
}

if&nbsp;demoFun1
then
&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;true
else
&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;false
fi

if&nbsp;demoFun2
then
&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;ture
else
&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;false
fi

其执行结果如下:

grep 是从给定字符串中寻找匹配内容的命令。首先看出如果找到了匹配的内容,会打印匹配部分且得到的返回值 $? 为 0,如果找不到,则返回值 $? 为 1。

接下来分别将这两次执行的 grep 命令当作条件语句交给 if 判断,得出返回值 $? 为 0,即执行成功时,条件语句为 true,当返回值 $? 为 1,即执行失败时,条件语句为 false。

之后再用函数的 return 值作为测试,其中 demoFun1 返回值为 0,demoFun2 返回值选择了任意一个和 0 不同的整数,这里为 12。

将函数作为条件语句交给 if 判断,得出返回值为 0 时,依然为 true,而返回值只要不是 0,条件语句都判断为 false。

Shell 输入/输出重定向

大多数 UNIX 系统命令从你的终端接受输入并将所产生的输出发送回到您的终端。一个命令通常从一个叫标准输入的地方读取输入,默认情况下,这恰好是你的终端。同样,一个命令通常将其输出写入到标准输出,默认情况下,这也是你的终端。

重定向命令列表如下:

命令

说明

command > file

将输出重定向到 file。

command < file

将输入重定向到 file。

command >> file

将输出以追加的方式重定向到 file。

n > file

将文件描述符为 n 的文件重定向到 file。

n >> file

将文件描述符为 n 的文件以追加的方式重定向到 file。

n >& m

将输出文件 m 和 n 合并。

n <& m

将输入文件 m 和 n 合并。

<< tag

将开始标记 tag 和结束标记 tag 之间的内容作为输入。

重定向一般通过在命令间插入特定的符号来实现。特别的,这些符号的语法如下所示:

command1&nbsp;>&nbsp;file1

上面这个命令执行command1然后将输出的内容存入file1。

注意任何file1内的已经存在的内容将被新内容替代。如果要将新内容添加在文件末尾,请使用>>操作符。

实例

执行下面的 who 命令,它将命令的完整的输出重定向在用户文件中(users):

$&nbsp;who&nbsp;>&nbsp;users

执行后,并没有在终端输出信息,这是因为输出已被从默认的标准输出设备(终端)重定向到指定的文件。

你可以使用 cat 命令查看文件内容:

$&nbsp;cat&nbsp;users&nbsp;
lyn&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tty7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2020-12-04&nbsp;10:22&nbsp;(:0)

输出重定向会覆盖文件内容,请看下面的例子:

$&nbsp;echo&nbsp;"学习shell不迷路"&nbsp;>&nbsp;users
$&nbsp;cat&nbsp;users&nbsp;
学习shell不迷路

如果不希望文件内容被覆盖,可以使用 >> 追加到文件末尾,例如:

$&nbsp;echo&nbsp;"学习shell不迷路"&nbsp;>>&nbsp;users
$&nbsp;cat&nbsp;users&nbsp;
学习shell不迷路
学习shell不迷路

输入重定向

和输出重定向一样,Unix 命令也可以从文件获取输入,语法为:

command1&nbsp;<&nbsp;file1

这样,本来需要从键盘获取输入的命令会转移到文件读取内容。

注意:输出重定向是大于号(>),输入重定向是小于号(<)。

实例

接着以上实例,我们需要统计 users 文件的行数,执行以下命令:

$&nbsp;wc&nbsp;-l&nbsp;users
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2&nbsp;users

也可以将输入重定向到 users 文件:

$&nbsp;&nbsp;wc&nbsp;-l&nbsp;<&nbsp;users
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2&nbsp;

注意:上面两个例子的结果不同:第一个例子,会输出文件名;第二个不会,因为它仅仅知道从标准输入读取内容。

command1&nbsp;<&nbsp;infile&nbsp;>&nbsp;outfile

同时替换输入和输出,执行command1,从文件infile读取内容,然后将输出写入到outfile中。

重定向深入讲解

一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件:

  • 标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。

  • 标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。

  • 标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。

默认情况下,command > file 将 stdout 重定向到 file,command < file 将stdin 重定向到 file。

如果希望 stderr 重定向到 file,可以这样写:

$&nbsp;command&nbsp;2>file

如果希望 stderr 追加到 file 文件末尾,可以这样写:

$&nbsp;command&nbsp;2>>file

2 表示标准错误文件(stderr)。

如果希望将 stdout 和 stderr 合并后重定向到 file,可以这样写:

$&nbsp;command&nbsp;>&nbsp;file&nbsp;2>&1

或者

$&nbsp;command&nbsp;>>&nbsp;file&nbsp;2>&1

如果希望对 stdin 和 stdout 都重定向,可以这样写:

$&nbsp;command&nbsp;<&nbsp;file1&nbsp;>file2

command 命令将 stdin 重定向到 file1,将 stdout 重定向到 file2。


Here Document 是 Shell 中的一种特殊的重定向方式,用来将输入重定向到一个交互式 Shell 脚本或程序。

它的基本的形式如下:

command&nbsp;<<&nbsp;delimiter
&nbsp;&nbsp;&nbsp;&nbsp;document
delimiter

它的作用是将两个 delimiter 之间的内容(document) 作为输入传递给 command。

注意:

结尾的delimiter 一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和 tab 缩进。

开始的delimiter前后的空格会被忽略掉。

实例

在命令行中通过 wc -l 命令计算 Here Document 的行数:

wc&nbsp;-l&nbsp;<<&nbsp;EOF
>&nbsp;欢迎来到
>&nbsp;shell教程
>&nbsp;lyn
>&nbsp;EOF
3     #输出结果为 3 行

我们也可以将 Here Document 用在脚本中,例如:

#!/bin/bash
cat&nbsp;<<&nbsp;EOF
欢迎来到shell教程
EOF

执行以上脚本,输出结果:


如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null:

$&nbsp;command&nbsp;>&nbsp;/dev/null

/dev/null 是一个特殊的文件,写入到它的内容都会被丢弃;如果尝试从该文件读取内容,那么什么也读不到。但是 /dev/null 文件非常有用,将命令的输出重定向到它,会起到"禁止输出"的效果。

如果希望屏蔽 stdout 和 stderr,可以这样写:

$&nbsp;command&nbsp;>&nbsp;/dev/null&nbsp;2>&1

注意:0 是标准输入(STDIN),1 是标准输出(STDOUT),2 是标准错误输出(STDERR)。

这里的 2 和 > 之间不可以有空格,2> 是一体的时候才表示错误输出。

$&nbsp;command&nbsp;>&nbsp;file&nbsp;2>&1
$&nbsp;command&nbsp;>>&nbsp;file&nbsp;2>&1

这里的&没有固定的意思

放在>后面的&,表示重定向的目标不是一个文件,而是一个文件描述符,内置的文件描述符如下

1&nbsp;=>&nbsp;stdout
2&nbsp;=>&nbsp;stderr
0&nbsp;=>&nbsp;stdin

换言之 2>1 代表将stderr重定向到当前路径下文件名为1的regular file中,而2>&1代表将stderr重定向到文件描述符为1的文件(即/dev/stdout)中,这个文件就是stdout在file system中的映射

而&>file是一种特殊的用法,也可以写成>&file,二者的意思完全相同,都等价于

>file&nbsp;2>&1

此处&>或者>&视作整体,分开没有单独的含义


顺序问题:

find&nbsp;/etc&nbsp;-name&nbsp;.bashrc&nbsp;>&nbsp;list&nbsp;2>&1
#&nbsp;我想问为什么不能调下顺序,比如这样
find&nbsp;/etc&nbsp;-name&nbsp;.bashrc&nbsp;2>&1&nbsp;>&nbsp;list

这个是从左到右有顺序的

第一种

xxx&nbsp;>&nbsp;list&nbsp;2>&1

先将要输出到stdout的内容重定向到文件,此时文件list就是这个程序的stdout,再将stderr重定向到stdout,也就是文件list

第二种

xxx&nbsp;2>&1&nbsp;>&nbsp;list

先将要输出到stderr的内容重定向到stdout,此时会产生一个stdout的拷贝,作为程序的stderr,而程序原本要输出到stdout的内容,依然是对接在stdout原身上的,因此第二步重定向stdout,对stdout的拷贝不产生任何影响

对于上面 '2>&1',举个例子,比如说:

$&nbsp;find&nbsp;/etc&nbsp;-names&nbsp;"*.txt"&nbsp;&nbsp;>list&nbsp;2>&1

从左往右执行,执行到 >list,此时的 stdout 为 list;而执行到 2>&1,表示 stderr 重定向到 stdout,这里也就是 list 文件。

因为 [ find /etc -names "*.txt" ] 这条命令是错误的( -names 应该是 -name)。

本来要输出到终端屏幕的错误信息:

find:&nbsp;unknown&nbsp;predicate&nbsp;`-names`

被重定向到了 stdout 也就是 list 文件中,所以屏幕不会出现错误信息,而是打印到了 list 文件中。

cat list 可以查看到 find: unknown predicate `-names' 就在里面。

直接在 FreeBSD 或者 csh 中使用 command > file 2>&1 时候会得到这个错误:Ambiguous output redirect

出错的原因在于 FreeBSD 默认使用 csh,在 csh 中如果想把标准输出和错误输出同时重定向到一个文件,需要用下面命令 command >& file。

这就是我分享的shell脚本,其中参考了很多人的文章,如果大家有什么更好的思路,也欢迎分享交流哈。

—END

推荐阅读

【1】C++的智能指针你了解吗?

【2】嵌入式底层开发的软件框架简述 
【3】CPU中的程序是怎么运行起来的 必读
【4】C++的匿名函数(lambda表达式)
【5】阶段性文章总结分析

本公众号全部原创干货已整理成一个目录,回复[ 资源 ]即可获得。

更多分享,扫码关注我

参考链接:

https://www.runoob.com/linux/linux-shell-variable.html