一台计算机是一种只能理解特定二进制指令的数字设备。在没有操作系统的情况下,我们只能使用一些内置的固件,比如计算机中的BIOS实用程序。操作系统通过提供执行预开发程序(例如文字处理器、网络浏览器和实用工具)的方式,使计算机对人们可用。现今的大多数操作系统允许用户同时使用图形用户界面(GUI)和命令行界面(CLI)。
程序员通常喜欢使用命令行界面,因为与图形用户界面相比,使用命令行界面更贴近日常的编程活动。他们经常通过命令行界面部署软件、进行文件系统操作和配置计算机系统。命令行界面是一种高效完成所有任务的方式,但我们经常需要运行稍作修改的相同命令。
因此,命令行界面解释器提供了一种从文件中运行预先编写的命令的shell脚本概念。Bash是一种着名的传统的内置(在大多数操作系统中)命令语言,用于运行shell脚本。另一方面,许多程序员使用Python作为shell脚本的替代方案,它提供了Bash所没有的内置功能。
在本文中,我将从shell脚本的角度比较Bash和Python,并解释一些较少为人所知的shell脚本技巧,以帮助您提高使用Bash和Python进行自动化的技能。
Bash:最自然的shell脚本方式
Shell脚本的主要思想是使用shell解释器运行预先编写的命令序列。Bash将每个输入/语句都视为一个命令,并提供了一种高效的自动化方式。还记得第一次使用基于Bash的终端(也许是在大学时?)而没有阅读文档或跟随教程的经历吗?
回想起您第一次使用基于Bash的终端的经历,作者提供的截图 Bash并不作为一种通用的通用编程语言,它总是鼓励您使用其他程序。例如,您可以在上述情况下使用”expr 10 + 15″。然而,现代的Bash支持内置功能,用于满足一般编程需求,因此在某些情况下,您无需调用其他程序。
例如,它通过算术扩展功能让您执行基本的算术运算:
在终端中使用算术扩展,作者提供的截图 Bash可以原生地执行命令,无需专用的扩展语法,并为通用编程需求提供了简洁的语法。
Python: 一种现代化的方式,解决了Bash中的一个缺失功能
如果Bash可以原生执行命令并支持许多通用编程功能,那为什么程序员要使用Python进行自动化呢?看一下下面来自早期版本Python文档的历史资料:
用LaTeX编写的Python文档的早期版本
根据这份文档,Python最初的开发目标是将shell脚本与本地操作系统级编程结合起来。Bash无法原生访问操作系统级API(也称为C API)。因此,如果自动化脚本需要访问C API,程序员必须使用其他编程语言创建一个可执行文件来实现。Python通过提供一个友好的、简洁的语言并具备C API访问权限来解决了这个问题,甚至还提供了一种跨平台的访问操作系统级API的方式。
Python从通用编程的角度评估源代码,因此它不能原生执行其他程序,但提供了一个开发者友好的子进程API。
我们已经对这两种语言的目标和基础知识进行了检查。现在让我们开始进行比较吧!
Bash vs. Python: 哪个更适合自动化?
程序员编写各种各样的shell脚本。有时候,他们编写的shell脚本执行一些POSIX命令(例如mv,cp等)。在某些情况下,他们需要在shell脚本中包含数据处理和操作系统级操作。此外,有时候他们需要编写跨平台的自动化脚本。
和几乎所有现代编程语言的比较总结一样,这里没有赢家——最佳的shell脚本选项取决于我们的开发场景。
Bash适用于以下情况:
- 自动化涉及较少数据处理的POSIX命令行操作,例如系统管理脚本
- 通过其他CLI程序执行配置、处理或其他操作的shell脚本,例如通过CLI工具编写Git提交信息和进行应用部署
- 如果您希望脚本在Unix系统上具有更好的可移植性,Bash是一个不错的选择,因为Bash解释器的预安装范围比Python更广泛
Python适用于以下情况:
- 自动化涉及更多数据处理(算法操作)和访问低级API,而不仅仅是执行其他CLI程序
- 编写跨平台自动化脚本,在GNU/Linux、Windows、macOS和其他Python支持的操作系统上执行命令、使用低级API并进行通用数据处理。以BuildZri项目为例。
总的来说,Bash是使用其他命令行程序编写自动化脚本的最简洁、自然、本地化和类似终端的方式。另一方面,Python是一种跨平台的通用编程语言,您可以将其作为Bash的替代方案,用于编写具有低级操作系统API访问和数据处理功能的shell脚本。
Bash和Python一起使用
Bash和Python之间并不存在极端的竞争,因为它们是两种不同的编程语言类型——Bash是一种命令语言,而Python是一种通用编程语言。我们可以根据需求选择其中一种选项,或者同时使用两种语言。
假设您使用bc来执行两个小数的加法,代码如下:
#!/bin/bash
# Linux迷 www.linuxmi.com
sum=$(bc <<< "1.65 + 2.91")
echo $sum
您也可以使用Python完成相同的任务,代码如下:
#!/bin/bash
sum=$(python3 <<< “print(1.5 + 2.51)”) echo $sum
与许多程序员在Python脚本中所做的一样,使用Bash在Python中也是比使用许多第三方Python包更方便的选择。例如,看看下面的脚本如何查找Gedit程序的进程标识符:
#!/usr/bin/env python3
# Linux迷 www.linuxmi.com
import subprocess
gedit_pid = subprocess \
.getoutput("ps -ef | grep gedit | head -1 | awk '{print $2}'") \
.strip()
print(gedit_pid)
解决现代自动化中的Bash和Python问题
正如我们讨论过的,Bash和Python在现代自动化需求中都存在一些缺点。使用Bash编写具有操作系统级API访问和复杂数据处理的shell脚本很困难。而使用Python的subprocess API执行最小化的命令行程序不具备与Shell语法相似的语法特性。
如果您需要在Bash中使用C API,可以使用ctypes.sh Bash扩展:https://github.com/taviso/ctypes.sh
甚至还有一个使用ctypes.sh外部函数接口以Bash编写的名为httpd.sh的HTTP Web服务器。
pysh 项目提供了一种在Python脚本中使用”>”字符执行Bash语句的简单方法,如下面的代码片段所示:
for i in xrange(100):
index = "%02d" % i
> mv from$index.txt to$index.txt
#! /usr/bin/env zxpy
# Linux迷 www.linuxmi.com
~'echo Hello world!Linux迷 www.linuxmi.com'
file_count = ~'ls -1 | wc -l'
print("file count is:", file_count)
总结
Shell脚本的概念始于20世纪70年代左右的Unix环境中的历史Thompson shell。传统Shell脚本的想法是从文件中执行命令行操作,用于自动化目的。现代DevOps运动通过在自动化脚本中包含RESTful API调用、数据处理和其他与DevOps相关的操作,扩展了传统的Shell脚本概念。
在现代自动化中,使用Bash作为Shell脚本选项并不过时,因为它允许您以本地方式执行命令,无需单独的子进程API(它已经内置)。如果程序员在自动化中需要执行的操作超出了本地命令行操作,他们通常会使用Python作为现代的Bash替代方案。