如何在Python中实现常见的bash习惯用法?

How to implement common bash idioms in Python?

我现在通过一堆记忆不清的awk、sed、bash和一点点perl来操作文本文件。

我看到过一些地方提到了python对这种东西很好。如何使用python替换shell脚本、awk、sed和朋友?


任何shell都有几个特性集。

  • 基本的linux/unix命令。所有这些都可以通过子流程库获得。这并不总是执行所有外部命令的最佳首选。也可以在shutil中查找一些单独的Linux命令,但您可能可以直接在Python脚本中实现这些命令。另一大批Linux命令在OS库中;您可以在Python中更简单地执行这些命令。

    还有——奖金!--更快。shell中的每个单独的Linux命令(除了少数例外)都会分叉子进程。通过使用python shutilos模块,您不会分叉子进程。

  • 外壳环境特性。这包括设置命令环境的内容(当前目录和环境变量以及其他变量)。您可以从python直接轻松地管理它。

  • shell编程特性。这是所有进程状态代码检查、各种逻辑命令(if、while、for等)、测试命令及其所有相关命令。函数定义的东西。这在Python中非常简单。这是摆脱bash并在python中进行bash的巨大胜利之一。

  • 交互功能。这包括命令历史记录和其他内容。编写shell脚本不需要这个。这只是为了人类的互动,而不是为了写剧本。

  • shell文件管理功能。这包括重定向和管道。这更棘手。其中大部分可以通过子流程完成。但在Python中,一些容易在shell中出现的东西是不愉快的。特别是像(a | b; c ) | something >result这样的东西。它并行运行两个进程(输出a作为b的输入),然后是第三个进程。该序列的输出与something并行运行,并将输出收集到名为result的文件中。用任何其他语言表达都很复杂。

特定的程序(awk、sed、grep等)通常可以重写为python模块。不要过火。替换你需要的,并发展你的"grep"模块。不要一开始就写一个替换"grep"的python模块。

最好的办法是你可以分步骤完成。

  • 用python替换awk和perl。别管别的事。
  • 看看用python替换grep。这可能有点复杂,但您的grep版本可以根据您的处理需求进行定制。
  • 看看用使用os.walk的python循环替换find。这是一个巨大的胜利,因为你不会产生那么多的进程。
  • 看看用Python脚本替换通用外壳逻辑(循环、决策等)。

  • 是的,当然:)

    看看这些库,它们可以帮助您不再编写shell脚本(Plumbum的座右铭)。

    • 萨奇

    另外,如果您想用基于python的东西替换awk、sed和grep,那么我推荐pyp-

    "The Pyed Piper", or pyp, is a linux command line text manipulation
    tool similar to awk or sed, but which uses standard python string and
    list methods as well as custom functions evolved to generate fast
    results in an intense production environment.


    我刚刚发现如何将bash和ipython的最佳部分结合起来。到目前为止,这对我来说似乎比使用子流程等更舒服。您可以很容易地复制现有bash脚本的大部分,例如,以python的方式添加错误处理:)我的结果是:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    #!/usr/bin/env ipython3

    # *** How to have the most comfort scripting experience of your life ***
    # ######################################################################
    #
    # … by using ipython for scripting combined with subcommands from bash!
    #
    # 1. echo"#!/usr/bin/env ipython3"> scriptname.ipy    # creates new ipy-file
    #
    # 2. chmod +x scriptname.ipy                            # make in executable
    #
    # 3. starting with line 2, write normal python or do some of
    #    the ! magic of ipython, so that you can use unix commands
    #    within python and even assign their output to a variable via
    #    var = !cmd1 | cmd2 | cmd3                          # enjoy ;)
    #
    # 4. run via ./scriptname.ipy - if it fails with recognizing % and !
    #    but parses raw python fine, please check again for the .ipy suffix

    # ugly example, please go and find more in the wild
    files = !ls *.* | grep"y"
    for file in files:
      !echo $file | grep"p"
    # sorry for this nonsense example ;)

    请参阅ipython docs on system shell命令并将其用作系统shell。


    截至2015年和python 3.4版本,现在有一个相当完整的用户交互shell,网址为:http://xon.sh/或http s://github.com/scopatz/xon sh

    演示视频不显示正在使用的管道,但在默认shell模式下支持这些管道。

    Xonsh("conch")非常努力地模仿bash,所以你已经获得肌肉记忆的东西,比如

    1
    env | uniq | sort -r | grep PATH

    1
    my-web-server 2>&1 | my-log-sorter

    仍然可以正常工作。

    本教程相当冗长,似乎涵盖了人们在ash或bash提示下通常期望的大量功能:

    • 编译、评估和执行!
    • 命令历史记录和选项卡完成
    • 帮助和超链接???
    • 别名和自定义提示
    • 执行命令和/或*.xsh脚本,这些脚本也可以导入
    • 环境变量,包括使用${}查找
    • 输入/输出重定向和组合
    • 后台作业和作业控制
    • 嵌套子进程、管道和协同进程
    • 子进程模式如果存在命令,则为python模式
    • 使用$()捕获的子进程、使用$[]未捕获的子进程、使用@()的python评估
    • 使用*或正则表达式进行文件名全局处理使用反勾号进行文件名全局处理


    • 如果你想把python作为shell,为什么不看一下ipython呢?互动学习语言也很好。
    • 如果您做了大量的文本操作,并且使用VIM作为文本编辑器,那么您还可以直接在Python中为VIM编写插件。只需在vim中键入":help python",然后按照说明操作或查看本演示文稿。编写您将直接在编辑器中使用的函数是如此简单和强大!


    一开始有sh、sed和awk(还有find、grep和…)。很好。但是awk可能是一种奇怪的小动物,如果你不经常使用它,很难记住。然后大骆驼创造了珍珠。Perl是系统管理员的梦想。就像是在类固醇上写贝壳脚本。文本处理,包括正则表达式只是语言的一部分。然后它变丑了…人们试图用Perl开发大型应用程序。别误会了,Perl可以是一个应用程序,但它可以(可以!)如果你不小心的话,看起来就像一团糟。然后是所有的平面数据业务。这足以让程序员发疯。

    输入python、ruby等。这些是非常好的通用语言。它们支持文本处理,并且做得很好(尽管可能没有紧紧地缠绕在语言的基本核心中)。但它们也能很好地扩展,并且在一天结束时仍然有好看的代码。他们还建立了相当庞大的社区,拥有大量的图书馆。

    现在,对Perl的否定很大程度上是一个观点问题,当然有些人可以编写非常干净的Perl,但是有这么多人抱怨它太容易创建模糊的代码,你知道有些事实是存在的。问题真的变成了,你是否会使用这种语言来代替简单的bash脚本?如果没有,请再学习一些Perl。真是太棒了。另一方面,如果您希望一种语言能够随着您的需要而发展,那么我建议您使用Python或Ruby。

    不管怎样,祝你好运!


    我建议把这本很棒的在线书投入到Python中去。这就是我最初学习语言的方式。

    除了教你语言的基本结构和大量有用的数据结构之外,它还有一个关于文件处理的好章节,以及后面关于正则表达式的章节等等。


    添加到以前的答案:检查用于处理交互命令(adduser、passwd等)的pexpect模块。


    我喜欢Python的一个原因是它比POSIX工具标准化得多。我必须反复检查每一位是否与其他操作系统兼容。在Linux系统上编写的程序可能无法在OSX的BSD系统上运行。对于python,我只需要检查目标系统是否有足够现代的python版本。

    更好的是,用标准python编写的程序甚至可以在Windows上运行!


    我将根据经验提出我的意见:

    壳牌:

    • shell可以非常容易地生成只读代码。写下它,当你回到它,你将永远不会知道你又做了什么。这很容易做到。
    • shell可以用管道在一行中进行大量的文本处理、拆分等。
    • 在集成不同编程语言中的程序调用时,它是最好的粘合语言。

    Python:

    • 如果您希望包括可移植到Windows,请使用python。
    • 当您必须操作的不仅仅是文本(如数字集合)时,python可能更好。为此,我推荐python。

    我通常为大多数事情选择bash,但是当我有一些必须跨越Windows边界的事情时,我只使用python。


    pythonpy是一个工具,它提供了从awk和sed轻松访问许多特性的功能,但使用了python语法:

    1
    2
    $ echo me2 | py -x 're.sub("me","you", x)'
    you2


    我已经构建了半长的shell脚本(300-500行)和具有类似功能的python代码。当执行许多外部命令时,我发现shell更容易使用。当有很多文本操作时,Perl也是一个很好的选择。


    在研究这个主题时,我发现了这个概念验证代码(通过http://jlebar.com/2010/2/1/replacing_bsh.html上的注释),它允许您"使用简洁的语法在python中编写类似shell的管道,并在有意义的地方利用现有的系统工具":

    1
    2
    for line in sh("cat /tmp/junk2") | cut(d=',',f=1) | 'sort' | uniq:
        sys.stdout.write(line)

    您可以将python而不是bash与shellpy库一起使用。

    下面是一个从Github下载python用户头像的示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    import json
    import os
    import tempfile

    # get the api answer with curl
    answer = `curl https://api.github.com/users/python
    # syntactic sugar for checking returncode of executed process for zero
    if answer:
        answer_json = json.loads(answer.stdout)
        avatar_url = answer_json['avatar_url']

        destination = os.path.join(tempfile.gettempdir(), 'python.png')

        # execute curl once again, this time to get the image
        result = `curl {avatar_url} > {destination}
        if result:
            # if there were no problems show the file
            p`ls -l {destination}
        else:
            print('Failed to download avatar')

        print('Avatar downloaded')
    else:
        print('Failed to access github api')

    正如您所看到的,重音符(`)符号内的所有表达式都在shell中执行。在Python代码中,您可以捕获执行的结果并对其执行操作。例如:

    1
    log = `git log --pretty=oneline --grep='Create'

    此行首先在shell中执行git log --pretty=oneline --grep='Create',然后将结果赋给日志变量。结果具有以下属性:

    stdout已执行进程的stdout中的整个文本

    stderr已执行进程的stderr中的整个文本

    返回代码执行的返回代码

    这是该库的概述,在这里可以找到更详细的描述和示例。


    你最好的选择是一个专门针对你的问题的工具。如果它在处理文本文件,那么SED、AWK和Perl是最有力的竞争者。Python是一种通用的动态语言。与任何通用语言一样,支持文件操作,但这不是它的核心目的。如果我特别需要一种动态语言,我会考虑使用Python或Ruby。

    简而言之,学习SED和AWK非常好,加上所有其他的好东西,伴随着你的*NIX的味道(所有的bash内置,grep,tr等等)。如果是你感兴趣的文本文件处理,你已经在使用正确的东西了。


    如果您的textfile操作通常是一次性的,可能在shell提示下完成,那么您将无法从python中获得更好的效果。

    另一方面,如果您经常需要反复执行相同(或类似)的任务,并且必须为此编写脚本,那么python非常棒——而且您可以轻松地创建自己的库(您也可以使用shell脚本来完成此任务,但这更麻烦)。

    一个很简单的例子来获得一种感觉。

    1
    2
    3
    4
    5
    6
    7
    8
    import popen2
    stdout_text, stdin_text=popen2.popen2("your-shell-command-here")
    for line in stdout_text:
      if line.startswith("#"):
        pass
      else
        jobID=int(line.split(",")[0].split()[1].lstrip("<").rstrip(">"))
        # do something with jobID

    同时检查sys和getopt模块,它们是您首先需要的。


    我已经在pypi:ez上发布了一个包。用pip install ez安装。

    它在shell中打包了常用命令,并且很好地使用了与shell基本相同的语法。例如,CP(源、目标)可以处理文件和文件夹!(shutil.copy shutil.copytree的包装器,它决定何时使用哪个)。更漂亮的是,它可以像R一样支持矢量化!

    另一个示例:no os.walk,使用fls(path,regex)递归查找文件并使用正则表达式进行筛选,它返回包含或不包含fullpath的文件列表

    最后一个示例:您可以将它们组合起来编写非常简单的脚本:files = fls('.','py$'); cp(files, myDir)

    一定要看看!我花了几百个小时来写/改进它!