如何在Python中实现常见的bash习语?

我目前通过一堆不好记的AWK、sed、Bash和一小部分Perl来做我的文本文件操作。

我已经看到提到的一些地方,python很适合做这种事情。我如何使用Python来代替shell脚本,AWK, sed和朋友?

115430 次浏览

我推荐这本很棒的网上书Dive Into Python。这就是我最初学习这门语言的方式。

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

任何shell都有几组特性。

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

    还有——额外的奖励!——快点。shell中的每个单独的Linux命令(少数例外)派生一个子进程。通过使用Python shutilos模块,你不会派生子进程。

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

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

  • < p >交互功能。这包括命令历史记录等。编写shell脚本不需要这个。这仅适用于人类交互,而不适用于脚本编写。

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

特定的程序(awk、sed、grep等)通常可以被重写为Python模块。不要走极端。替换你所需要的,发展你的“人格”;模块。不要一开始就编写一个替换“grep"”的Python模块。

最好的事情是你可以一步一步来做。

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

如果你的文本文件操作通常是一次性的,可能在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模块,它们是您首先需要的。

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

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

  • 如果你想使用Python作为shell,为什么不看看IPython呢?用互动的方式学习语言也很好。
  • 如果需要进行大量的文本操作,并且使用Vim作为文本编辑器,那么还可以直接用python为Vim编写插件。只需在Vim中键入“:help python”,并按照说明进行操作,或者看看这个演讲。它是如此简单和强大的编写函数,你将直接在你的编辑器中使用!

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

进入Python、Ruby等。这些都是非常好的通用语言。它们支持文本处理,并且做得很好(尽管可能与语言的基本核心没有那么紧密地交织在一起)。但它们也可以很好地扩展,并且在一天结束时仍然有漂亮的代码。他们还发展了相当庞大的社区,有大量的图书馆,几乎可以提供任何东西。

现在,对Perl的很多负面意见是一个意见问题,当然有些人可以编写非常干净的Perl,但是有这么多人抱怨它太容易创建混淆的代码,您知道一些事实是存在的。真正的问题是,除了简单的bash脚本替换之外,您还会将这种语言用于其他用途吗?如果不是,学习更多的Perl..这真是太棒了。另一方面,如果你想要一种随你一起成长的语言,我建议你使用Python或Ruby。

不管怎样,祝你好运!

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

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

在研究这个主题时,我发现这个概念验证代码(通过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)

是的,当然。

看看这些帮助你再也不写shell脚本了 (Plumbum的座右铭)的库。

  • < a href = " https://bitbucket.org/vinay.sajip/sarge/ " >军士< / >
  • < a href = " http://amoffat.github.com/sh/ " > sh < / >

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

“The Pyed Piper”,或pyp,是linux命令行文本操作 工具类似于awk或sed,但使用标准的python字符串和 列表方法以及自定义函数进化为快速生成

我刚刚发现如何结合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 ;)

请参阅系统shell命令上的IPython docs并使用它作为一个系统外壳

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

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

以下是我的一些经验之谈:

外壳:

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

python:

  • 如果你想要Windows的可移植性,请使用python。
  • 当您必须处理的不仅仅是文本,比如数字的集合时,Python可能会更好。为此,我推荐python。

我通常选择bash来处理大多数事情,但当我有一些必须跨越窗口边界的东西时,我就使用python。

pythonpy是一个工具,可以方便地访问awk和sed的许多特性,但使用python语法:

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

我已经在PyPI上发布了一个包:易之 使用pip install ez来安装它

它在shell中打包了通用命令,我的库使用了与shell基本相同的语法。例如,cp(源,目标)可以同时处理文件和文件夹!(书纸的包装。shutil副本。Copytree,它决定什么时候使用哪个)。更妙的是,它可以支持像R!

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

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

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

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

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

Xonsh(“conch”)非常努力地模仿bash,因此您已经获得了肌肉记忆,例如

env | uniq | sort -r | grep PATH

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

仍然可以正常工作。

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

  • 编译,计算,&执行!
  • 命令历史记录和制表符完成
  • 帮助,Superhelp with ? &??
  • 别名,定制的提示
  • 执行命令和/或*.xsh脚本,也可以导入
  • 环境变量包括使用${}查找
  • 输入/输出重定向和组合
  • 背景工作作业控制
  • 嵌套子进程、管道和协进程
  • 当命令存在时使用Subprocess-mode,否则使用Python-mode
  • 已捕获的子进程带有$(),未捕获的子进程带有$[], Python计算带有@()
  • 文件名Globbing with *或正则表达式文件名Globbing with backtick

你可以在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')

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

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

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

stdout从被执行进程的标准输出的整个文本

stderr所执行进程的stderr的整个文本

returncode执行的返回码

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