乐趣区

关于python:如何友好的把Python和Bash结合在一起

对于 Linux 用户而言,命令行操作咱们曾经十分相熟了。与其余风行的操作系统不同,在 Linux 社区中,应用命令行与应用图形用户界面执行相似工作相比,命令行通常能够提供更优雅,更无效的解决方案。

随着 Linux 社区对命令行的依赖一直增长,UNIX shell(如 bash 和 zsh)已倒退成为极其弱小的工具,能够补充 UNIX shell 的教训。应用 bash 和其余相似的 shell,能够应用许多弱小的性能,例如管道,文件名通配符以及从称为脚本的文件中读取命令的性能。

让咱们看一个实在的示例来演示命令行的性能。每次用户登录服务时,其用户名都会记录到一个文本文件中。对于此示例,让咱们找出有多少惟一用户应用该服务。

以下示例中的一系列命令通过将较小的构建块链接在一起,显示了更简单的实用工具的性能:

$ cat names.log | sort | uniq | wc -l

管道符号(|)用于将一个命令的规范输入传递到下一命令的规范输出。在此处的示例中,cat names.txt 的输入传递到 sort 命令中。sort 命令的输入是按字母程序重新排列文件的每一行。随后将其传递给 uniq 命令,该命令将删除所有反复的名称。最初,uniq 的输入传递到 wc 命令。wc 是计数命令,并且设置了 - l 标记,它返回行数。这使您能够将许多命令链接在一起。

然而,有时所需的内容可能会变得非常复杂,并且将命令链接在一起可能变得蠢笨。在这种状况下,shell 脚本就是答案。Shell 脚本是由 Shell 读取并按程序执行的命令列表。Shell 脚本还反对某些编程语言基础知识,例如变量,流控制和数据结构。Shell 脚本对于将常常反复运行的批处理作业十分有用。可怜的是,shell 脚本有一些毛病:

Shell 脚本很容易变得过于简单,并且对于想要改良或保护它们的开发人员来说是不可读的。

这些 shell 脚本的语法和解释器通常很蠢笨且不直观。语法越蠢笨,对于必须应用这些脚本的开发人员来说,可读性就越差。

该代码通常无奈在其余脚本中应用。脚本之间的代码重用往往很艰难,并且脚本往往十分特定于某个问题。

用于高级性能(例如 HTML 解析或 HTTP 申请)的库不像古代编程和脚本语言那样容易取得。

这些问题会使 shell 脚本难以解决,并常常导致大量开发人员工夫节约。取而代之的是,Python 编程语言能够用作十分无力的替代品。应用 Python 代替 Shell 脚本有很多益处:

默认状况下,所有次要的 Linux 发行版都装置了 Python。关上命令行并立刻键入 python,将使您进入 Python 解释器。这种普遍性使它成为大多数脚本工作的理智抉择。

Python 具备十分易于浏览和了解的语法。它的格调强调简洁和简洁的代码,同时容许开发人员以适宜 shell 脚本的准系统格调进行编写。

Python 是一种解释型语言,这意味着没有编译阶段。这使 Python 成为编写脚本的现实语言, 它容许您以解释的形式疾速尝试新代码。这使开发人员能够疾速批改,而不用将整个程序写到文件中。

Python 是一种功能齐全的编程语言。代码重用很简略,因为 Python 模块能够轻松导入并在任何 Python 脚本中应用。脚本能够轻松扩大或构建。

Python 能够应用杰出的规范库和数以千计的第三方库来解决各种高级实用程序,例如解析器和申请库。例如,Python 的规范库包含日期工夫库,该库容许将日期解析为指定的任何格局并将其与其余日期轻松比拟。

但 Python 不应替换所有 bash 命令。编写以 UNIX 形式运行的 Python 程序(即读入规范输出并写入规范输入)与为现有的 shell 命令(如 cat 和 sort)编写 Python 替代品一样弱小。

让咱们以本文后面已解决的问题为根底。除了曾经实现的工作之外,让咱们找出某个用户已登录零碎的次数。uniq 命令仅删除反复项,但不提供无关有多少反复项的信息。代替 uniq,Python 脚本能够用作链中的另一个命令。这是一个执行此操作的 Python 程序(在我的示例中,我将此文件称为 namescount.py):

#!/usr/bin/env python
import sys

if __name__ == "__main__":
    # Initialize a names dictionary as empty to start with.
    # Each key in this dictionary will be a name and the value
    # will be the number of times that name appears.
    names = {}
    # sys.stdin is a file object. All the same functions that
    # can be applied to a file object can be applied to sys.stdin.
    for name in sys.stdin.readlines():
            # Each line will have a newline on the end
            # that should be removed.
            name = name.strip()
            if name in names:
                    names[name] += 1
            else:
                    names[name] = 1

    # Iterating over the dictionary,
    # print name followed by a space followed by the
    # number of times it appeared.
    for name, count in names.iteritems():
            sys.stdout.write("%d\t%s\n" % (count, name))

让咱们看看这个 Python 脚本如何适宜命令链。首先,它从通过 sys.stdin 对象公开的规范输出中读取输出。任何输入都将写入 sys.stdout 对象,这是在 Python 中实现规范输入的形式。Python 字典(在其余语言中通常称为哈希映射)用于获取从用户名到反复计数的映射。要取得所有用户的数量,请执行以下操作:

$ cat names.log | python namescount.py

显示用户呈现的次数以及用户名的计数。接下来要做的是按程序显示最常应用该零碎的用户。这能够在 Python 级别实现,然而让咱们应用外围 UNIX 实用程序曾经提供的实用程序来实现它。以前,我应用 sort 命令对字母进行排序。如果命令提供了 -rn 标记,它将按降序对行进行数字排序。随着 Python 脚本按规范输入,只需将命令通过管道传递到 sort 并检索所需的输入:

$ cat names.log | python namescount.py | sort -rn

这是将 Python 用作命令链一部分的弱小示例。在这种状况下应用 Python 的长处如下:

  • 与 cat 和 sort 等工具链接的能力。简略的实用程序(逐行读取文件并以数字形式对文件进行排序)由久经考验的 UNIX 命令解决。这些命令也逐行读取,这意味着这些性能能够缩放到大型文件,而且速度很快。
  • 当须要在链中进行一些沉重的工作时,能够编写一个十分清晰,简洁的 Python 脚本,该脚本将执行其所需的工作,而后将责任转移给链中的下一个链接。
  • 它是一个可重用的模块,只管此示例专门针对名称,然而如果您向此输出中蕴含反复行的任何输出,它将打印出每行和反复的数量。通过将 Python 代码模块化,能够将其利用于各种场景。

为了展现以模块化和管道形式组合 Python 脚本的弱小性能,让咱们进一步把问题放大。让咱们找到该服务的前五名用户。head是一个命令,它容许您指定肯定数量的行以显示给定的规范输出。将其增加到命令链中将失去以下内容:

$ cat names.log | python namescount.py | sort -rn | head -n 5

这仅显示前五个用户,而疏忽其余用户。同样,要使五个用户起码应用该服务,能够应用 tail 命令,该命令采纳雷同的参数。将 Python 命令打印到规范输入的后果使能够构建和扩大其性能。

以上就是简略的介绍,理论中大家灵活运用就好。

退出移动版