如何在 Python 中实现常见的 bash 习语? [关闭]

Posted

技术标签:

【中文标题】如何在 Python 中实现常见的 bash 习语? [关闭]【英文标题】:How to implement common bash idioms in Python? [closed] 【发布时间】:2010-09-17 14:11:45 【问题描述】:

我目前通过一堆记不太清的 AWK、sed、Bash 和一点点 Perl 来处理我的文本文件。

我已经看到一些地方提到 python 对这种事情有好处。如何使用 Python 替代 shell 脚本、AWK、sed 和朋友?

【问题讨论】:

pythonpy 是使用 python 语法的 awk 和 sed 的一个很好的竞争对手:github.com/Russell91/pythonpy 您可以使用设计时考虑到将 bash/sh 替换为 python github.com/lamerman/shellpy 的想法的 shellpy 这是我的问题,我不明白为什么它是基于意见的。最佳答案列出了 shell 所做的每一项主要工作,并告诉您如何在 python 中完成它们。在我看来,这以一种非主流的方式回答了这个问题。 这个问题,它的结束,正在讨论元here 【参考方案1】:

截至 2015 年和 Python 3.4 版本,现在有一个相当完整的用户交互 shell 可用:http://xon.sh/ 或 https://github.com/scopatz/xonsh

demonstration video 不显示正在使用的管道,但在默认 shell 模式下它们是受支持的。

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

env | uniq | sort -r | grep PATH

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

仍然可以正常工作。

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

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

【讨论】:

但为什么所有这些答案似乎只是为不了解 bash 的人重新发明***?我已经对 bash 感到适度舒适,并且这些答案中的每一个看起来最终都会成为更多的工作而没有什么好处。这些答案都是针对那些害怕(或者不想花时间学习)bash的python人,对吗? 似乎它有一些缺点,例如要求对具有 xonsh 代码的文件使用 .xsh 扩展名:github.com/xonsh/xonsh/issues/2478。否则你必须使用evalx 直接从.py 文件中调用它。【参考方案2】:

我推荐这本很棒的在线书籍Dive Into Python。这就是我最初学习语言的方式。

除了教你语言的基本结构和大量有用的数据结构之外,它还有一个很好的章节 file handling 和后续章节 regular expressions 等等。

【讨论】:

... 仅链接答案的主要问题。【参考方案3】:

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

#!/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 ;)

在system shell commands 上查看 IPython 文档并使用它as a system shell。

【讨论】:

赞成,因为出于某种奇怪的原因,没有人提到!-IPython 中的命令,这绝对是关键;特别是因为您还可以将它们的输出分配给变量(行列表),如filelines = ! cat myfile 你可以在shell命令中使用python变量作为$var吗?哇。这应该是公认的答案。 你也可以在 jupyter notebooks 中使用它【参考方案4】:

我在 PyPI 上发布了一个包:ez。 使用pip install ez进行安装。

它在 shell 中打包了常用命令,而且我的 lib 使用与 shell 基本相同的语法。例如,cp(source, destination) 可以同时处理文件和文件夹! (shutil.copy shutil.copytree 的包装器,它决定何时使用哪一个)。更棒的是,它可以像 R 一样支持矢量化!

另一个例子:没有 os.walk,使用 fls(path, regex) 递归查找文件并使用正则表达式进行过滤,它返回一个有或没有完整路径的文件列表

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

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

【讨论】:

看起来很有趣,但我无法突破 pypi.python.org/pypi/ez 处的未格式化文档,抱歉...【参考方案5】:

您可以在 ShellPy 库中使用 python 而不是 bash。

下面是一个从 Github 下载 Python 用户头像的例子:

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 代码中,您可以捕获此执行的结果并对其执行操作。例如:

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

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

stdout执行过程的标准输出的整个文本

stderr来自已执行进程的stderr的整个文本

returncode 执行的返回码

这是该库的总体概述,更详细的示例说明可以在here找到。

【讨论】:

【参考方案6】:

任何外壳都有几组功能。

基本的 Linux/Unix 命令。所有这些都可以通过subprocess 库获得。这并不总是执行 all 外部命令的最佳首选。另请查看 shutil 以了解一些单独的 Linux 命令,但您可能可以直接在 Python 脚本中实现。另外一大批 Linux 命令在 os 库中;您可以在 Python 中更简单地完成这些操作。

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

shell 环境特性。这包括设置命令环境的东西(当前目录和环境变量等等)。您可以直接从 Python 轻松管理。

shell 编程功能。这是所有进程状态代码检查、各种逻辑命令(if、while、for 等)、测试命令及其所有相关命令。函数定义的东西。这在 Python 中要容易得多。这是摆脱 bash 并在 Python 中实现的巨大胜利之一。

交互功能。这包括命令历史记录和其他内容。您不需要它来编写 shell 脚本。这仅用于人机交互,不适用于脚本编写。

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

特定程序(awk、sed、grep 等)通常可以重写为 Python 模块。不要过火。替换您需要的并改进您的“grep”模块。不要一开始就写一个 Python 模块来代替“grep”。

最好的事情是您可以分步进行。

    用 Python 替换 AWK 和 PERL。别管其他一切。 看看用 Python 替换 GREP。这可能有点复杂,但您的 GREP 版本可以根据您的处理需求进行定制。 考虑将 FIND 替换为使用 os.walk 的 Python 循环。这是一个巨大的胜利,因为您不会产生那么多进程。 看看用 Python 脚本替换常见的 shell 逻辑(循环、决策等)。

【讨论】:

写道:“交互功能。这包括命令历史记录等等。你不需要这个。”恐怕没有人能说出一个人真正需要什么或不需要什么。也许他会。此外,这些设施在交互式 shell 中也很有意义,以 Idle 和 IPython 之间的区别为例。 我真诚地希望人们完全放弃 shell 脚本。我知道黑客在 *nix 世界中实际上是一种宗教,但我真的厌倦了试图解释植入操作系统中的所有黑客变通方法。微型工具(awk、sed、top、base 等)的新颖性在每个人决定推出自己的版本的那一天消失了。当我想象浪费在糟糕的小工具上的工时,这些工具很容易被几个设计良好的 Python 模块取代时,我感到畏缩。 ::叹息:: 我不同意@EvanPlaice,因为相比之下,我拥有的几个find 脚本的python 版本丑陋、冗长且无法维护。很多东西应该是 shell 脚本,还有很多东西不应该。并非所有东西都只需要是 Python 或 BASH(或其他任何东西)之一。 @mikebabcock 理想情况下,应该有一个完整的库来实现基本 *nix 堆栈提供的所有微型工具。将包含诸如 find() 和 last() 之类的函数,而不是管道,而是使用柯里化和延迟加载的组合将它们粘合在一起。拥有一个在所有发行版中以标准方式工作的 POSIX 脚本环境不是很好吗?不存在这样的东西,但是...... 关于 shell 管道(例如 (a | b; c ) | something >result)的观点通过使用 shell=True 将 shell 管道传递给 subprocess 方法非常容易而有所缓解【参考方案7】:

pythonpy 是一个工具,可以轻松访问 awk 和 sed 的许多功能,但使用 python 语法:

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

【讨论】:

【参考方案8】:

我将根据经验在这里给出我的意见:

对于外壳:

shell 可以很容易地生成只读代码。写下来,当你回到它时,你永远不会再弄清楚你做了什么。很容易做到这一点。 shell 可以用管道在一行中进行大量的文本处理、拆分等。 在集成不同编程语言的程序调用方面,它是最好的胶水语言。

对于python:

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

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

【讨论】:

【参考方案9】:

我喜欢 Python 的一个原因是它比 POSIX 工具更标准化。我必须双重和三重检查每个位是否与其他操作系统兼容。在 Linux 系统上编写的程序在 OSX 的 BSD 系统上可能无法正常工作。使用 Python,我只需要检查目标系统是否具有足够现代的 Python 版本。

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

【讨论】:

“用标准 Python 编写的程序甚至可以在 Windows 上运行”:不是开玩笑吗?【参考方案10】:

是的,当然:)

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

Plumbum Sarge sh

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

“The Pyed Piper”,或 pyp,是一个 linux 命令行文本操作 类似于 awk 或 sed 的工具,但它使用标准 python 字符串和 列表方法以及自定义函数演变为快速生成 导致紧张的生产环境。

【讨论】:

也可以看看 Envoy,它是 sh github.com/kennethreitz/envoy的替代品【参考方案11】: 如果你想使用 Python 作为 shell,为什么不看看 IPython 呢?以交互方式学习语言也很好。 如果你做大量的文本操作,并且如果你使用Vim作为文本编辑器,你也可以直接在python中为Vim编写插件。只需在 Vim 中输入 ":help python" 并按照说明进行操作或查看presentation。编写可直接在编辑器中使用的函数非常简单且功能强大!

【讨论】:

有一个名为 'sh' 的 ipython 配置文件,它使解释器 非常 很像一个 shell。 ipython 'sh' 配置文件已经被删除了一段时间。 >>>结果 = !dmesg | grep -i 'usb' #the !操作员做这一切【参考方案12】:

在研究这个主题时,我发现this proof-of-concept code(通过http://jlebar.com/2010/2/1/Replacing_Bash.html 的评论)让您“使用简洁的语法在 Python 中编写类似 shell 的管道,并在有意义的地方利用现有的系统工具”:

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

【讨论】:

【参考方案13】:

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

【讨论】:

【参考方案14】:

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

【讨论】:

【参考方案15】:

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

输入 Python、Ruby 等。这些确实是非常好的通用语言。它们支持文本处理,并且做得很好(尽管可能没有紧密地缠绕在语言的基本核心中)。但是它们也可以很好地扩展,并且在一天结束时仍然有漂亮的代码。他们还开发了相当庞大的社区,其中包含大量的图书馆,几乎可以满足任何需求。

现在,对 Perl 的很多负面看法都是见仁见智,当然有些人可以编写非常干净的 Perl,但是有这么多人抱怨创建混淆代码太容易了,你知道一些真相是那里。那么问题就真的变成了,你是否会使用这种语言来代替简单的 bash 脚本。如果没有,请学习更多 Perl .. 这绝对是太棒了。另一方面,如果您想要一门可以随着您做更多事情而与您一起成长的语言,我建议您使用 Python 或 Ruby。

无论如何,祝你好运!

【讨论】:

【参考方案16】:

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

简而言之,学习 Sed 和 Awk 非常好,以及所有其他与您的 *nix 风格相关的好东西(所有 Bash 内置插件、grep、tr 等等)。如果您感兴趣的是文本文件处理,那么您已经在使用正确的东西了。

【讨论】:

【参考方案17】:

如果您的文本文件操作通常是一次性的,可能是在 shell 提示符下完成的,那么您不会从 python 中得到更好的结果。

另一方面,如果您通常必须一遍又一遍地执行相同(或类似)的任务,并且您必须为此编写脚本,那么 python 很棒 - 您可以轻松创建自己的库(你也可以用 shell 脚本来做,但是比较麻烦)。

一个非常简单的例子来感受一下。

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 模块,它们是您首先需要的。

【讨论】:

以上是关于如何在 Python 中实现常见的 bash 习语? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

Java中的命名参数习语

命令建议是如何在 bash shell 中实现的?

如何在bash终端中实现CTRL-R(反向搜索)?

有限自动机是如何在代码中实现的?

看OpenCV如何在python中实现图像检测!

如何在python中实现一个自定义的列表或字典