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,每个人都有自己的优点和困难。但在大多数情况下,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 允许在 Linux 操作系统上使用 Linux 命令,例如sedgrepteecat以及所有其他基于命令行的实用程序。事实上,几乎任何命令行 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主机命令的包装器。如果我们想做更多的事情,让我们自己的应用程序像主机一样在 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 自动执行任务。

输入输出和重定向

处理标准输出到另一个命令 -

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

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

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

数字 文件描述符 特点
0 标准输入 <
1 标准输出 >
2 标准误
附加标准输出 >>
分配重定向 &
将标准输出通过管道传输到标准输入 |

我们在第一章中介绍了这一点,但没有真正讨论重定向或分配重定向。在 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 的示例 -

标准输出

[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 传递到文本文件时需要注意的是>>>之间的区别。双“>>”将追加到文件中,而单数形式将破坏文件并写入新内容(因此所有先前的数据将丢失)。

标准输入

[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.htm