# 一, 创建并执行 Shell 脚本

# 1. 脚本文件格式
  • 编写一个脚本。 Shell 脚本就是普通的文本文件。所以我们需要一个文本编辑器来书写它们。最好的文本 编 辑器都会支持语法高亮,这样我们就能够看到一个脚本关键字的彩色编码视图。语法高亮会帮助我们查看某 种常见 错误。为了编写脚本文件,vim,gedit,kate,和许多其它编辑器都是不错的候选者。
  • 使脚本文件可执行。 系统会相当挑剔不允许任何旧的文本文件被看作是一个程序,并且有充分的理由!所以 我们需要设置脚本文件的权限来允许其可执行。
  • 把脚本放置到 shell 能够找到的地方 当没有指定可执行文件明确的路径名时,shell 会自动地搜索某些目录, 来查找此可执行文件。为了最大程度的方便,我们会把脚本放到这些目录当中。
# 2. 创建一个 hello_world 文件,使用 vim 编辑
1
2
3
4
5
#!/bin/bash

#这是我们的第一个脚本文件

echo 'Hello world!'
# 3. 可执行权限
  • 使得脚本能够执行,用 chmod 设置权限
1
$ chomd 755 hello_world(文件名)
# 4. 执行脚本
1
$ ./hello_world

​ 执行结果:

# 二,编写 html 并在浏览器启动

# 1. 变量与常量
  • Shell 并不在意变量赋值的数据类型,它将一切都视为字符串,可以之接为变量赋值
1
2
3
title="System Infomation Report"
使用 '$' 符号引用变量
echo $title 输出即为: System Infomation Report

  • #a=z 将字符串 z 赋给变量 a
  • #b=“a string” 内嵌空格符的字符串必须放入双引号中
  • #c=“a string and $b” 赋值中包含其他扩展(例如,变量扩展)
  • #d="$(ls -l foo.txt)" 命令的执行结果
  • #e=$((5*7)) 算术扩展
  • #f="\t\ta string \n" 转义序列,例如制表符,换行符

# 2. 编写文件内容
  • 创建文件 sys_info_page,输入下列程序:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/bin/bash
#程序输出一个系统信息页
TITLE="System Information Report For $HOSTNAME"
#生成时间
CURRENT_TIME="$(date +"%x %r %Z")"
#创建者用户名
TIMESTAMP="Generated $CURRENT_TIME ,by $USER"
echo "<html>
<head>
<title>$TITLE</title>
</head>
<body>
<h1 align="center">$TITLE</h1>
<p align="center">$TIMESTAMP</p>
</body>
</html>"

说明:$HOSTNAME为主机名,$(date + "%x %r %Z")为当前用户时间

  • 设置 sys_info_page 可执行权限
1
2
$ chmod 755 sys_info_page
$ ./sys_info_page
  • 当程序运行的时候,我们应该看到 HTML 文本在屏幕上显示出来,因为脚本中的 echo 命令会输出 发送到标准 输出。我们再次运行这个程序,把程序的输出重定向到文件 sys_info_page.html 中, 从而我们可以通过网络浏 览器来查看输出结果:
1
2
$ ./sys_info_page > sys_info_page.html
$ firefox sys_info_page.html

​ 执行结果:

  • 也可在浏览器地址栏中输入:file:// 文件所在路径,进行查看
# Here Documents
  • 我们已经知道了两种不同的文本输出方法,两种方法都使用了 echo 命令。还有第三种方法,叫做 here document 或者 here script。一个 here document 是另外一种 I/O 重定向形式,我们 在脚本文件中嵌入正文 文本,然后把它发送给一个命令的标准输入。它这样工作:
1
2
3
command << token
text
token
  • 这里的 command 是一个可以接受标准输入的命令名,token 是一个用来指示嵌入文本结束的字符串。

  • 这个字符串_EOF_(意思是 “文件结 尾”, 一个常见用法)被选作为 token,并标志着嵌入文本的结尾。注意这个 token 必须在一行中单独出现, 并且文本行中 没有末尾的空格。

来看以下命令行示例:

1
2
3
4
5
6
7
8
9
10
11
$ foo="some text"
$ cat << _EOF_
> $foo
> "$foo"
> '$foo'
> \$foo
> _EOF_
some text
"some text"
'some text'
$foo
  • 正如我们所见到的,shell 根本没有注意到引号。它把它们看作是普通的字符。这就允许我们 在一个 here document 中可以随意的嵌入引号。

  • 如果我们把重定向操作符从 “<<” 改为 “<<-”,shell 会忽略在此 here document 中开头的 tab 字符。

# 三,Shell 函数

# 1. shell 函数两种语法形式
1
2
3
4
5
function name {
commands
return
}
注意name和 '{' 之间有空格

​ 另一种简单的形式:

1
2
3
4
name {
commands
return
}
# 2. shell 函数用法
1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/bash
# Shell 函数展示

function step2 { //函数名与 '{' 之间有空格
echo "Step 2"
return
}
#主函数起点

echo "Step 1"
step2
echo "Step 3"

随着 shell 读取这个脚本,它会跳过第 1 行到第 11 行的代码,因为这些文本行由注释和函数定义组成。 从第 12 行 代码开始执行,有一个 echo 命令。第 13 行会调用 shell 函数 funct,然后 shell 会执行这个函数, 就如执行其 它命令一样。这样程序控制权会转移到第六行,执行第二个 echo 命令。然后再执行第 7 行。 这个 return 命令终 止这个函数,并把控制权交给函数调用之后的代码(第 14 行),从而执行最后一个 echo 命令。注意为了使函数 调用被识别出是 shell 函数,而不是被解释为外部程序的名字,所以在脚本中 shell 函数定义必须出现在函数调 用之前。

# 四,局部变量

  • 局 部变量只能在定义它们的 shell 函数中使用,并且一旦 shell 函数执行完毕,它们就不存在了。 拥有局部变量允许程序员使用的局部变量名,可以与已存在的变量名相同,这些变量可以是全局变量, 或者是其 它 shell 函数中的局部变量,却不必担心潜在的名字冲突。

    下面的例子演示局部变量的定义和用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/bin/bash
# local-vars: 演示本地变量的脚本

foo=0 # global variable foo

funct_1 () {
local foo # variable foo local to funct_1
foo=1
echo "funct_1: foo = $foo"
}
funct_2 () {
local foo # variable foo local to funct_2
foo=2
echo "funct_2: foo = $foo"
}

echo "global: foo = $foo"
funct_1
echo "global: foo = $foo"
funct_2
echo "global: foo = $foo"

执行结果:

正如我们所看到的,通过在变量名之前加上单词 local,来定义局部变量。这就创建了一个只对其所在的 shell 函 数起作用的变量。在这个 shell 函数之外,这个变量不再存在。我们对两个 shell 函数中的局部变量 foo 赋值,不会影响到在函数之外定义的变量 foo 的值。 这个功能就允许 shell 函数能保持各自以及与它们所在脚本之间的独立性。

# 五,完善我们的 Shell 脚本

  • 在我们已编写的 Shell 脚本中添加以下功能:
    • 系统正常运行时间和负载。这是自上次关机或重启之后系统的运行时间,以及在几个时间间隔内当前运行在 处理 中的平均任务量。
    • 磁盘空间。系统中存储设备的总使用量。
    • 家目录空间。每个用户所使用的存储空间数量。
1
2
3
4
命令介绍:
uptime 系统正常运行时间和负载
df -h 查看文件系统硬盘使用情况 -h参数:使用人们习惯的 KB、MB 或 GB 等单位自行显示容量;
du -sh /home/* 查看home文件夹磁盘占用情况 需要root用户权限,如果在普通用户下,在命令前加上sudo

改写我们的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#!/bin/bash
#程序输出一个系统信息页

#大写字母表示常量,小写字母表示变量
TITLE="System Information Report For $HOSTNAME"
#生成时间
CURRENT_TIME="$(date +"%x %r %Z")"
#创建者用户名
TIMESTAMP="Generated $CURRENT_TIME ,by $USER"

report_uptime () {
cat <<- _EOF_
<h2>System Uptime</h2>
<pre>$(uptime)</pre>
_EOF_
return
}
report_disk_space () {
cat <<- _EOF_
<h2>Disk Space Utilization</h2>
<pre>$(df -h)</pre>
_EOF_
return
}
report_home_space () {
cat <<- _EOF_
<h2>Home Space Utilization</h2>
<pre>$(sudo du -sh /home/*)</pre>
_EOF_
return
}

cat << _EOF_
<html>
<head>
<title>$TITLE</title>
</head>
<style>
.box {
width: 400px;
}
</style>
<body>
<h1 align="center">$TITLE</h1>
<p align="center">$TIMESTAMP</p>
<center>
$(report_uptime)
<div align="left" class="box">
$(report_disk_space)
</div>
$(report_home_space)
</center>
</body>
</html>
_EOF_

执行结果如下:

至此,我们成功启动我们编写的 shell 脚本文件。