Linux 管理员 - Shell 脚本

Bash Shell 简介

与 GNU Linux 的版本一样,shell 也有很多种,兼容性也各不相同。CentOS 中的默认 shell 称为 Bash 或 Bourne Again Shell。Bash shell 是 Stephen Bourne 开发的 Bourne Shell 的现代修改版本。Bash 是 Ken Thompson 和 Dennis Ritchie 在贝尔实验室开发的 Unix 操作系统上原始 Thompson Shell 的直接替代品(Stephen Bourne 也受雇于贝尔实验室)

每个人都有自己喜欢的 shell,每个 shell 都有自己的优点和缺点。但在大多数情况下,Bash 将成为所有 Linux 发行版的默认 shell,并且是最常用的 shell。有了经验,每个人都会想探索和使用最适合自己的 shell。但与此同时,每个人都希望掌握 Bash shell。

其他 Linux shell 包括:Tcsh、Csh、Ksh、Zsh 和 Fish。

对于 CentOS 管理员来说,掌握使用任何 Linux shell 的专家级技能非常重要。正如我们前面提到的,与 Windows 不同,Linux 的核心是命令行操作系统。shell 只是一个用户界面,允许管理员(或用户)向操作系统发出命令。如果 Linux 系统管理员是航空公司的飞行员,使用 shell 就像是将飞机从自动驾驶仪上取下,然后抓住手动控制,以实现更灵活的飞行。

Linux shell,如 Bash,在计算机科学术语中被称为命令行解释器。 Microsoft Windows 还有两个命令行解释器,分别称为 DOS(不要与原始 DOS 操作系统混淆)和 PowerShell。

大多数现代 shell(如 Bash)都提供构造,允许更复杂的 shell 脚本 自动执行常见和复杂任务。

构造包括 −

  • 脚本流控制(ifthen 和 else)
  • 逻辑比较操作(大于、小于、相等)
  • 循环
  • 变量
  • 定义操作的参数(类似于命令中的开关)

使用 Shell 脚本与脚本语言

管理员在考虑执行任务时经常会问自己:我应该使用 shell 脚本还是脚本语言(如 Perl、Ruby 或Python?

这里没有固定的规则。shell 与脚本语言之间只有典型的差异。

Shell

Shell 允许使用 Linux 命令,例如 sedgrepteecat 以及 Linux 操作系统上所有其他基于命令行的实用程序。事实上,几乎任何命令行 Linux 实用程序都可以在您的 shell 中编写脚本。

使用 shell 的一个很好的例子是快速脚本来检查主机列表以进行 DNS 解析。

我们简单的 Bash 脚本用于检查 DNS 名称 −

#!/bin/bash 
for name in $(cat $1);
   do 
      host $name.$2 | grep "has address" 
   done 
exit

用于测试 DNS 解析的小单词列表 −

dns 
www 
test 
dev 
mail 
rdp 
remote

针对 google.com 域名的输出 −

[rdc@centos ~]$  ./dns-check.sh dns-names.txt google.com
-doing dns
dns.google.com has address 172.217.6.46
-doing www
www.google.com has address 172.217.6.36
-doing test
-doing dev
-doing mail
googlemail.l.google.com has address 172.217.6.37
-doing rdp
-doing remote

[rdc@centos ~]$

利用 shell 中的简单 Linux 命令,我们能够编写一个简单的 5 行脚本来从单词列表中审核 DNS 名称。即使使用实现良好的 DNS 库,在 Perl、Python 或 Ruby 中,这也会花费相当多的时间。

脚本语言

脚本语言将在 shell 之外提供更多控制。上面的 Bash 脚本使用了 Linux host 命令的包装器。如果我们想做更多事情并让我们自己的应用程序(如 host)在 shell 之外进行交互,该怎么办?这就是我们使用脚本语言的地方。

此外,有了高度维护的脚本语言,我们知道我们的操作在大多数情况下将适用于不同的系统。例如,Python 3.5 可以在任何其他运行 Python 3.5 并安装了相同库的系统上运行。如果我们想在 Linux 和 HP-UX 上运行 BASH 脚本,情况就不一样了。

有时,脚本语言和强大的 shell 之间的界限可能会很模糊。可以使用 Python、Perl 或 Ruby 自动执行 CentOS Linux 管理任务。这样做其实很常见。此外,富裕的 shell 脚本开发人员已经用 Bash 制作了一个简单但功能齐全的 Web 服务器守护进程。

凭借脚本语言和 shell 中任务自动化的经验,CentOS 管理员将能够在需要解决问题时快速确定从哪里开始。使用 shell 脚本启动项目是很常见的。然后随着项目变得越来越复杂,再进展到脚本(或编译)语言。

此外,可以对项目的不同部分同时使用脚本语言和 shell 脚本。一个例子可以是使用 Perl 脚本来抓取网站。然后,使用 shell 脚本通过 sedawkegrep 进行解析和格式化。最后,使用 PHP 脚本通过 Web GUI 将格式化的数据插入 MySQL 数据库。

了解了一些 shell 理论后,让我们开始使用基本构建块来自动执行 CentOS 中 Bash shell 的任务。

输入输出和重定向

将 stdout 处理为另一个命令 −

[rdc@centos ~]$ cat ~/output.txt | wc -l
6039
[rdc@centos ~]$

上面,我们已将 cat'sstoud 传递给 wc 以使用 管道 字符进行处理。 wc 然后处理 cat 的输出,将 output.txt 的行数打印到终端。将 pipe 字符视为传递一个命令的输出以供下一个命令处理的"管道"。

以下是处理命令重定向时要记住的关键概念 −

数字 文件描述符 字符
0 标准输入 <
1 标准输出 >
2 标准错误
附加 stdout >>
分配重定向 &
将 stdout 管道化为 stdin |

我们在第一章中介绍了这一点,但并没有真正谈论重定向或分配重定向。在 Linux 中打开终端时,您的 shell 被视为 −

  • 标准输入 < 0
  • 标准输出 > 1
  • 标准错误 2

让我们看看它是如何工作的 −

[rdc@centos ~]$ lsof -ap $BASHPID -d 0,1,2 
 COMMAND   PID   USER    **FD**   TYPE DEVICE   SIZE/OFF   NODE      NAME 
 bash    13684    rdc    **0u**   CHR  136,0      0t0     3      /dev/pts/0 
 bash    13684    rdc    **1u**   CHR  136,0      0t0     3      /dev/pts/0 
 bash    13684    rdc    **2u**   CHR  136,0      0t0     3      /dev/pts/0
 
[rdc@centos ~]$  

/dev/pts/0 是我们的伪终端。CentOS Linux 会查看它,并将我们的开放终端应用程序视为一个真正的终端,键盘和显示器通过串行接口插入。但是,就像虚拟机管理程序将硬件抽象为操作系统一样,/dev/pts 将我们的终端抽象为应用程序。

从上面的 lsof 命令中,我们可以在 FD 列下看到所有三个文件描述符都设置为我们的虚拟终端 (0,1,2)。我们现在可以发送命令,查看命令输出以及与命令相关的任何错误。

以下是 STDIN 和 STDOUT 的示例 −

STDOUT

[root@centosLocal centos]# echo "I am coming from Standard output or STDOUT." >
output.txt && cat output.txt
I am coming from Standard output or STDOUT. 
[root@centosLocal centos]#

也可以将 stdoutstderr 发送到单独的文件 −

bash-3.2# find / -name passwd 1> good.txt 2> err.txt
bash-3.2# cat good.txt
/etc/pam.d/passwd
/etc/passwd
bash-3.2# cat err.txt 
find: /dev/fd/3: Not a directory
find: /dev/fd/4: Not a directory
bash-3.2#

在搜索整个文件系统时,遇到了两个错误。每个错误都被发送到一个单独的文件以供稍后查看,而返回的结果则被放入一个单独的文本文件中。

在执行向终端输出大量数据的操作(如编译应用程序)时,将 stderr 发送到文本文件非常有用。这将允许查看可能从终端回滚历史记录中丢失的错误。

将 STDOUT 传递给文本文件时需要注意的一点是 >>> 之间的区别。双">>"将附加到文件,而单数形式将破坏文件并写入新内容(因此所有以前的数据都将丢失)。

STDIN

[root@centosLocal centos]# cat < stdin.txt
Hello,
I am being read form Standard input, STDIN.

[root@centosLocal centos]#

在上面的命令中,文本文件 stdin.txt 被重定向到 cat 命令,该命令将其内容回显到 STDOUT

管道符"|"

管道符将获取第一个命令的输出,将其作为输入传递给下一个命令,允许第二个命令对输出执行操作。

现在,让我们将 cat 的标准输出"管道"到另一个命令 −

[root@centosLocal centos]# cat output.txt | wc -l
2
[root@centosLocal centos]#

上面,wc 对从管道传递过来的 cat 的输出执行计算。管道命令在过滤 grepegrep 的输出时特别有用 −

[root@centosLocal centos]# egrep "^[0-9]{4}$" /usr/dicts/nums | wc -l
9000
[root@centosLocal centos]#

在上面的命令中,我们将文本文件中的每 4 位数字传递给 wc,该文本文件包含通过 egrep 过滤器传递的 65535 中的所有数字。

使用 & 重定向输出

可以使用 & 字符重定向输出。如果我们想将 STDOUT 和 STDERR 的输出直接放到同一个文件中,可以按如下方式实现 −

[root@centosLocal centos]# find / -name passwd > out.txt 2>&1
[root@centosLocal centos]# cat out.txt  
find: /dev/fd/3: Not a directory 
find: /dev/fd/4: Not a directory 
/etc/passwd

[root@centosLocal centos]#

使用 & 字符进行重定向的工作方式如下:首先,将输出重定向到 out.txt。其次,STDERR 或文件描述符 2 被重新分配到与 STDOUT 相同的位置,在本例中为 out.txt

重定向非常有用,在解决操作大型文本文件、编译源代码、在 shell 脚本中重定向输出以及发出复杂的 Linux 命令时出现的问题时非常有用。

虽然重定向功能强大,但对于较新的 CentOS 管理员来说可能会很复杂。练习、研究和偶尔向 Linux 论坛(例如 Stack Overflow Linux)提问将有助于解决高级解决方案。

Bash Shell 构造

现在我们对 Bash shell 的工作原理有了很好的了解,让我们学习一些常用来编写脚本的基本构造。在本节中,我们将探索 −

BASH 故障排除提示

与专用脚本语言相比,BASH 可能有点棘手。BASH 脚本中最大的一些问题来自于传递给 shell 的脚本操作错误转义或未转义。如果您查看了几次脚本,发现它没有按预期工作,请不要担心。即使是那些每天使用 BASH 创建复杂脚本的人,这种情况也很常见。

快速搜索 Google 或在专家 Linux 论坛上注册以提出问题,将很快得到解决。很有可能有人遇到过同样的问题,并且已经解决了。

BASH 脚本是一种快速创建强大脚本的好方法,可用于从自动化管理任务到创建有用的工具等所有方面。成为专家级 BASH 脚本开发人员需要时间和实践。因此,尽可能使用 BASH 脚本,它是您 CentOS 管理工具箱中必备的好工具。

linux_admin_shell_scripting.html