bash shell命令学习之构建脚本篇

本博客内容来自《Linux命令行与shell脚本编程大全》第十一章

目录

1、使用多个命令

2、创建shell脚本文件

3、显示消息

4、使用变量

环境变量

用户变量

命令替换(重要)

5、重定向输入和输出

输出重定向

输入重定向

6、管道

7、执行数学运算

expr命令

使用方括号

浮点解决方案

bc的基本用法

在脚本中使用bc

8、退出脚本

查看退出状态码

exit命令


1、使用多个命令

最简单的脚本:在命令行界面直接输入多个bash shell命令,用分号隔开

[root@izwz9194nuv8g0cwqfqsh3z ~]# date;who
Sun Mar  3 21:40:11 CST 2019
root     pts/0        2019-03-03 20:17 (183.157.160.36)

如上所示,date显示当前日期和时间,who显示是谁登陆到了系统上。

2、创建shell脚本文件

必须在文件第一行指定要使用的shell,其格式为

#!/bin/bash

#后面的一般为注释,shell不处理,但是第一行是例外。惊叹后后面会告诉shell用哪个shell来运行脚本。

在shell脚本中不需要分号隔开命令,回车行即可

#!/bin/bash

# this is an example

date

who

将以上内容保存为名为test的脚本文件,接下来运行脚本,两种途径:

1.将shell脚本文件所处的目录添加到PATH环境变量中;

2.在提示符中用绝对或相对文件路径来引用shell脚本文件。

我们一般采用第二种方式,将脚本文件的确切位置告诉shell,为了引用当前目录下的文件,可以在shell中使用单点操作符:

[root@izwz9194nuv8g0cwqfqsh3z ~]# ./test1
-bash: ./test1: Permission denied

我们没有执行文件的权限,查看文件权限:

[root@izwz9194nuv8g0cwqfqsh3z ~]# ll test1
-rw-r--r-- 1 root root 21 Mar  4 21:40 test1

我们发现文件没有被赋予执行权限,使用chmod命令赋予文件属主执行权限:

[root@izwz9194nuv8g0cwqfqsh3z ~]# chmod u+x test1
[root@izwz9194nuv8g0cwqfqsh3z ~]# ./test1
Mon Mar  4 21:45:45 CST 2019
root     pts/0        2019-03-04 21:29 (183.157.160.23)

搞定!

3、显示消息

显示消息一般用echo命令,一般不需要引号就可以显示出文本字符串,如:

[root@izwz9194nuv8g0cwqfqsh3z ~]# echo this is a test
this is a test

但是如果文本字符串中有引号就需要注意,要加引号,如果有单引号就套双引号,有双引号就套单引号:

[root@izwz9194nuv8g0cwqfqsh3z ~]# echo let's see if this'll work
lets see if thisll work
[root@izwz9194nuv8g0cwqfqsh3z ~]# echo "let's see if this'll work"
let's see if this'll work

[root@izwz9194nuv8g0cwqfqsh3z ~]# echo he said "good job"
he said good job
[root@izwz9194nuv8g0cwqfqsh3z ~]# echo 'he said "good job"'
he said "good job"

如果想把文本字符串和命令输出显示在同一行,可以加 -n 参数:

编辑一个名为test1的文件,输入以下内容并保存退出:

#!/bin/bash

echo the time is :
date
echo the user is :
who

执行脚本:

[root@izwz9194nuv8g0cwqfqsh3z ~]# ./test1
the time is :
Wed Mar  6 10:28:57 CST 2019
the user is :
root     pts/0        2019-03-06 10:17 (183.157.160.23)

可以看到echo输出与命令输出不在同一行,在脚本中的echo命令后加参数-n:

#!/bin/bash

echo -n the time is :
date
echo -n the user is :
who

执行脚本:

[root@izwz9194nuv8g0cwqfqsh3z ~]# ./test1
the time is :Wed Mar  6 10:31:20 CST 2019
the user is :root     pts/0        2019-03-06 10:17 (183.157.160.23)

4、使用变量

环境变量

使用set命令可以显示当前环境变量完整的列表

[root@izwz9194nuv8g0cwqfqsh3z ~]# set
BASH=/bin/bash
......
-gnu")
BASH_VERSION='4.2.46(2)-release'
COLUMNS=187
DIRSTACK=()
EUID=0
GROUPS=()
HISTCONTROL=ignoredups
HISTFILE=/root/.bash_history
HISTFILESIZE=1000
HISTSIZE=1000
HOME=/root
HOSTNAME=izwz9194nuv8g0cwqfqsh3z
......

在脚本中,可以在环境变量名称前加上美元符$来使用上述的环境变量,也可以用${变量名}来显示,这样做的好处时变量名不会有歧义。但当我们想显示美元符号时,记得在$符号前加上反斜线\。

用户变量

shell脚本允许在脚本中定义和使用自己的变量,这些变量允许临时存储数据并在整个脚本中使用;在shell脚本结束时,定义的变量会被删除掉

使用等号将值赋给用户变量,在变量、等号和值之间不能出现空格

用户变量也可以使用$符号引用。

命令替换(重要)

shell脚本最有用的特性之一就是可以从命令输出中提取信息,并将其赋予变量。把输出赋给变量之后就可以在脚本中随意使用了。

两种方法可以将命令输出赋给变量:

反引号字符(`):result=`date`

$()格式:result=$(date)

例如,有以下名为test2的脚本内容:

[root@izwz9194nuv8g0cwqfqsh3z ~]# cat test2
#!/bin/bash
result=`date`
echo the time is: ${result}.
result=$(who)
echo "the user is:" ${result}.

执行该脚本可以得到:

[root@izwz9194nuv8g0cwqfqsh3z ~]# ./test2
the time is: Wed Mar 6 11:20:01 CST 2019.
the user is: root pts/0 2019-03-06 10:17 (183.157.160.23) root pts/1 2019-03-06 11:04 (183.157.160.23).

来一个比较体现价值的操作,输出以日期为后缀的日志文件:

[root@izwz9194nuv8g0cwqfqsh3z ~]# cat test3
#!/bin/bash
# copy the /usr/bin directory listing to a log file
today=$(date +%y%m%d)
ls /usr/bin -al > log.${today}

执行后输出日志文件:

-rw-r--r-- 1 root   root 47943 Mar  6 11:26 log.190306

[root@izwz9194nuv8g0cwqfqsh3z ~]# cat log.190306 
total 292940
dr-xr-xr-x.  2 root root      20480 Mar  1 13:42 .
drwxr-xr-x. 13 root root       4096 Feb 24 10:19 ..
-rwxr-xr-x   1 root root      41544 Oct 31 03:16 [
-rwxr-xr-x   1 root root     107904 Jan 22 06:10 a2p
-rwxr-xr-x   1 root root      29200 Oct 30 17:55 addr2line
-rwxr-xr-x   1 root root         29 Oct 31 01:07 alias
lrwxrwxrwx   1 root root          6 Feb 24 10:20 apropos -> whatis
-rwxr-xr-x   1 root root      62736 Oct 30 17:55 ar
......

书本上说

命令替换本质上是运行该脚本的shell创建了一个子shell来运行对应的命令,因此该子shell中所执行的命令不能使用脚本中创建出来的变量。

针对这句话我做了个简单测试:

[root@izwz9194nuv8g0cwqfqsh3z ~]# cat test4
#!/bin/bash
var=Mike
result=`echo "the man's name is ${var}"`
echo ${result}
result=`echo "the user's name is ${USER}"`
echo ${result}

[root@izwz9194nuv8g0cwqfqsh3z ~]# ./test4
the man's name is Mike
the user's name is root

结果好像与书本所提到的相反,大家可以自己再测试一下。

5、重定向输入和输出

如果想保存某个命令的输出而不是仅仅在界面显示,需要用到重定向功能。

输出重定向

使用大于号>将命令输出重定向到某个文件:

[root@izwz9194nuv8g0cwqfqsh3z ~]# date > test6
[root@izwz9194nuv8g0cwqfqsh3z ~]# cat test6
Wed Mar  6 15:27:49 CST 2019

此时会新建test6文件并写入内容,如果test6已经存在,则已有内容会被覆盖。

使用>>可以将命令输出重定向,追加到某个文件末尾

[root@izwz9194nuv8g0cwqfqsh3z ~]# who >> test6
[root@izwz9194nuv8g0cwqfqsh3z ~]# cat test6
Wed Mar  6 15:27:49 CST 2019
root     pts/0        2019-03-06 15:27 (183.157.160.51)

输入重定向

输入重定向将文件的内容重定向到命令

输入重定向符号是小于号<,可以发现,与输出重定向相同的地方在于命令在左,文件在右。

command < inputfile

以下为与wc命令一起使用输入重定向的例子:

[root@izwz9194nuv8g0cwqfqsh3z ~]# wc test6
 2 11 85 test6
[root@izwz9194nuv8g0cwqfqsh3z ~]# wc < test6
 2 11 85

wc命令会输出文件中文本的行数、词数与字节数。

还有种输入重定向方法叫内联输入重定向,无需使用文件进行重定向,只需要在命令行中指定用于输入重定向的数据就行。

内联输入重定向使用<<符号,并且要指定一个文本标记符来划分输入数据的开始与结尾——任何字符串都可以作为文本标记,但必须一致。

command << marker

data

marker

[root@izwz9194nuv8g0cwqfqsh3z ~]# wc << END
> tes1 string 1
> test string 2
> test string 3
> END
 3  9 42

6、管道

如果想将一个命令的输出作为另一个命令的输入,使用重定向很麻烦,可以使用管道:

command1 | command2......

Linux系统实际上会同时执行这两个命令,在系统内部将其连接起来,在第一个命令产生输出的同时,输出会被立即送给第二个命令,数据传输不会用到任何中间文件或缓冲区。

[root@izwz9194nuv8g0cwqfqsh3z ~]# ps -ef | grep bio
root        18     2  0 Feb26 ?        00:00:00 [bioset]
root        19     2  0 Feb26 ?        00:00:00 [bioset]
root        20     2  0 Feb26 ?        00:00:00 [bioset]
root     26627 26551  0 16:35 pts/0    00:00:00 grep --color=auto bio

可以将管道输出>重定向给文件。

7、执行数学运算

expr命令

Bourne shell提供的特别命令expr

[root@izwz9194nuv8g0cwqfqsh3z ~]# expr 4 \* 2
8
[root@izwz9194nuv8g0cwqfqsh3z ~]# expr 4 + 2
6
[root@izwz9194nuv8g0cwqfqsh3z ~]# expr 4 - 2
2
[root@izwz9194nuv8g0cwqfqsh3z ~]# expr 4 / 2
2

使用方括号

bash shell为了与Bourne shell兼容而包含expr命令,但还提供了更简单的方法执行数学运算,不过只支持整数运算

$[ operation ]

[root@izwz9194nuv8g0cwqfqsh3z ~]# var1=$[1 + 5]
[root@izwz9194nuv8g0cwqfqsh3z ~]# echo $var1
6
[root@izwz9194nuv8g0cwqfqsh3z ~]# var2=$[$var1 * 2]
[root@izwz9194nuv8g0cwqfqsh3z ~]# echo $var2
12
可以直接在命令行执行计算,也可以用在脚本,不用\进行转义,很方便

浮点解决方案

bash采用内建的bash计算器(又称bc)来解决浮点计算问题。

  • bc的基本用法

bc实际上是一种编程语言,允许在命令行中输入浮点表达式,然后解释并计算该表达式,最后返回结果。

其能够识别:

数字(整型和浮点)

变量(简单变量和数组)

注释(以#或/**/开始的行)

表达式

编程语言

函数

[root@izwz9194nuv8g0cwqfqsh3z ~]# bc
bc 1.06.95
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'. 
12*5.4  ##乘法
64.8

3.156*(5+6)
34.716

5.0/3   ##除法
1
scale=4  ##设置小数位
5/3
1.6666

var1=3  ##支持变量
var1*4
12
print var1  ##打印变量和数字
3
quit

  • 在脚本中使用bc

在脚本中使用bc可以通过命令替换,基本格式为:

variable=$(echo "options; expression" | bc)

例如:

[root@izwz9194nuv8g0cwqfqsh3z ~]# cat test9
#!/bin/bash
var1=$(echo "scale=4; 3.44 / 5" | bc)
echo the answer is $var1

[root@izwz9194nuv8g0cwqfqsh3z ~]# ./test9
the answer is .6880

[root@izwz9194nuv8g0cwqfqsh3z ~]# ./test10
the answer for this is 2.2222
[root@izwz9194nuv8g0cwqfqsh3z ~]# cat test10
#!/bin/bash
var1=100
var2=45
var3=$(echo "scale=4;$var1 / $var2" | bc)
echo the answer for this is $var3

以上适合较短的运算,如果涉及大量运算,可以使用内联输入重定向。

variable=$(bc << EOF

options

statements

expressions

EOF

)

[root@izwz9194nuv8g0cwqfqsh3z ~]# cat test11
#!/bin/bash
var1=100
var2=45
var3=$(bc << EOF

scale=4

a1=var1 * 3

a2=var2 / 5

a1 + a2

EOF

)
echo the answer for this is $var3

8、退出脚本

shell中运行的每个命令都使用退出状态码告诉shell其已经运行完毕。退出状态码是0-255之间的整数值。

查看退出状态码

Linux专门提供了变量 $? 来保存上一个已经执行命令的退出状态码

[root@izwz9194nuv8g0cwqfqsh3z ~]# date
Wed Mar  6 18:56:06 CST 2019
[root@izwz9194nuv8g0cwqfqsh3z ~]# echo $?
0

正确退出状态码为0

如果有错误时会输出错误码

0:命令成功结束

1:一般性未知错误

2:不适合的shell命令

126:命令不可执行

127:没找到命令

128:无效的退出参数

128+x:与Linux信号x相关的严重错误

130:通过Ctrl+C终止的命令

255:正常范围之外的退出状态码

exit命令

正常的shell脚本执行完之后的状态码是其最后一个命令的退出状态码,一般为0,不过我们可以通过exit命令修改退出码

exit num

exit $var

如在脚本最后一句使用exit命令

[root@izwz9194nuv8g0cwqfqsh3z ~]# ./test4
the man's name is Mike
the user's name is root
[root@izwz9194nuv8g0cwqfqsh3z ~]# echo $?
0                          ##正常输出0
[root@izwz9194nuv8g0cwqfqsh3z ~]# vim test4
[root@izwz9194nuv8g0cwqfqsh3z ~]# cat test4
#!/bin/bash
var=Mike
result=`echo "the man's name is ${var}"`
echo ${result}
result=`echo "the user's name is ${USER}"`
echo ${result}
exit 6                     ##增加exit命令

[root@izwz9194nuv8g0cwqfqsh3z ~]# ./test4
the man's name is Mike
the user's name is root
[root@izwz9194nuv8g0cwqfqsh3z ~]# echo $?
6                           ##按照我们设定的输出

你可能感兴趣的:(Linux之路)