何时使用Bash以及何时使用Perl / Python / Ruby?[关闭]


78

到目前为止,我们正在使用Bash进行所有脚本编写,但是我对此感到有点傻。虽然我们当然可以使用Bash来完成我们想要的一切(功能非常强大),但我开始怀疑我们是否应该使用适当的脚本语言(在我们的情况下,很可能是Ruby)代替。

您如何决定何时在Bash上使用Perl / Python / Ruby来编写脚本?我认为使用Ruby的初始化脚本没有道理,但是添加电子邮件帐户的稍长的脚本又如何呢?


1
如果您可以使用其中任何一种,真的有关系吗?仅当生成的脚本存在任何差异时,该选择才有意义。例如,执行时间可能会大不相同(电子邮件帐户不是问题)。
丹尼斯

Answers:


44

鉴于两者都可以解决的问题,您将需要使用最适应的问题。最终,有很多小细节,只有经验可以教您看它们。

Bash是通用的脚本语言,就像Python,Ruby,Perl一样,但是每种语言在其他方面都有不同的优势。Perl擅长进行文本分析,Python声称是同类中最优雅的,Bash脚本非常擅长“四处传播”,如果您知道我的意思的话,那么Ruby ...好吧,Ruby在很多方面都与众不同的方式。

但是,只有当您拥有足够的脚本编写经验后,它们之间的差异才真正重要。我建议您选择一种语言并将其推到极限,然后再使用另一种语言。在shell脚本中,您可以做很多事情,这比大多数人所承认的要多。任何一种语言都像您想做的一样难。在其中编写了几本书之后,每种语言对您来说都是“轻松”的。

如果您生活在Linux中,那么对Shell的熟悉会很快获得回报,因此也许您想从此开始。如果您发现在Shell脚本中无法解决或不切实际的任务,请使用其他方法。

另外,请记住,学习shell脚本非常简单。它的真正功能在于其他程序,例如awk,sed,tr等。


与Ruby一样,我在bash脚本编写方面有相当的经验,但有时我仍然不知道该使用什么。当时根据个人喜好进行选择似乎很愚蠢。但是您是对的,我会问自己我想做什么,然后选择最适合工作的工具。
futlib

就个人而言,我将以复杂程度和功能从高到低的顺序使用我所熟知的语言,并使用最适合的语言。但是,实际上,唯一可以确定的方法就是用所有语言编写脚本并比较结果。这更多是一种直觉而不是确定性。在编写脚本几年后,您将遇到大多数“问题类型”,并且知道哪种语言可以很好地解决它们。
mkaito 2012年

只是想补充一点,使用GNU coreutils包中的小程序(如tr,sort,uniq)并对其进行管道传输就可以完成很多任务。
GMaster

58

TL; DR- 将bash 用于安装更好的语言(如果尚不可用),否则您将浪费无法恢复的宝贵时间。如果您不能在命令行上手工完成此操作,请不要使用bash / shell编写脚本。

是2015年,所以我考虑以下几点:

  1. 内存开销

    • 与bash相比,Ruby / Python运行时的内存开销很小(由于共享库),而一个人可能仍然无法维护一个非平凡的bash脚本(即,行数大于100的脚本)-因此内存使用率不是一个因素
  2. 启动时间

    • Ruby / Python的启动可能会稍微慢一点,但是您可能不会在每秒100次的紧密循环中运行很多完整的Ruby / Python进程(如果您有这些需求,bash / shell是无论如何,开销太大,您可能需要使用C / C ++)
  3. 性能

    • 几乎所有典型的数据处理在Ruby / Python中都会更快-或至少具有可比性(或者,无论如何,您都需要C / C ++ / Haskel / OCaml /)
    • 真正的性能/执行瓶颈(甚至生产力)几乎永远不会是“缺乏使用bash / shell”(甚至Ubuntu的启动破折号也显示了bash实际上是问题所在-繁忙的盒子可能是唯一的用例) ,因为那里没有什么比“庆典”和“六”更多的编写和运行代码,而且也往往没有办法添加/下载或存储任何东西)
    • 运行其他进程来完成任务(例如sed / awk / grep)实际上比在内存中的活动对象上调用方法要慢很多
  4. 生产率

    • 与在Ruby / Python中使用“真实”方法,参数,变量和异常相比,在Bash / shell中犯错误太容易了
    • 敏捷是主流,而Bash不支持它(缺少单元测试功能,库,OO,模块化,lint,自省,日志记录,元编程;几乎不可能重构而不会破坏某些东西)
    • 由于与其他Shell的兼容性过多,次要环境变量可能会完全破坏脚本(某些重要的dev-ops工具(如Puppet)会忽略shebang行并传递或重写重要的shell变量),而Ruby / Python具有定义良好的相对平稳的迁移甚至主要版本更改的路径
    • 由于特定于外壳的问题(特别是-变量名,无布尔值,无异常等),学习一种新语言只需要花费很少的时间就可以调试外壳脚本。
    • 即使启动脚本也是一个地雷(特别是因为它们可能在系统启动期间失败),并且鉴于bash最近的安全漏洞,使用普通C(具有良好的库)可能会更好-是的,C需要编译,配置等。 ,但即使是简单的shell脚本也可能需要存储库,然后进行版本控制,然后再打包。
    • sed / awk / grep提供的所有功能都可能已内置在Ruby / Python中-而不是依赖关系,也没有跨平台的这些工具版本之间的“差异”(如果在您的安装程序中可以使用该怎么办)
  5. 就业保障
    • 找到不喜欢的工作有什么意义?(除非您喜欢花所有这些小时进行难以调试的错误,但要花费很少的时间来编写shell脚本错误)

如果您安装了Ruby / Python,我发现没有理由使用Bash / Shell。

也许首先安装Ruby / Python甚至不需要bash脚本(除了busybox之外,某些系统工具仍然依赖于Python / Perl)。

每次编写shell脚本时,您都是在“练习”做完这些事情-而不是学习更强大/更有成效的东西。

为什么人们如今使用Bash?因为这是一个可怕的,难以打破的习惯。最初几分钟后,脚本很少“永远完成”-不管人们倾向于以这种方式思考。还有“这是该脚本中的最后一个错误”谬论。

结论:仅当您绝对被迫使用bash / shell时(例如~/.bashrcbusybox),因为当今它几乎从来都不是 “正确的工作工具”。


28

我主要关注文件处理时使用bash。这可能包括移动,复制和重命名文件,以及将文件用作其他程序的输入或将其他程序的输出存储在文件中。我很少编写bash代码来实际检查文件的内容或生成输出以写入文件;我将其留给我通过bash启动的其他程序(可以用Perl或python编写)。

当我主要关注从文件中读取数据,以某种方式处理该数据并将输出写入文件时,我使用Perl和python。如果我发现自己(在Perl中)使用了system命令,反勾或在python中使用了subprocess太多模块,则考虑使用bash编写脚本。另一方面,我有时会开始向bash脚本添加太多功能,最终使它更有意义地是用Perl / python重写它,而不是处理bash对变量作用域,函数,数据结构等的有限(通过比较)支持。


2
每当需要文件读取/文本生成时,我都在bash上使用了t0保释,但是在了解了=~操作员的支持后,[[ ]]我一直爱我一些​​用于简单文件读取的Bash
Freedom_Ben 2014年

16

我喜欢此博客文章中列出的条件。

  • 如果没有任何参数要传递,则可能是shell脚本。
  • 如果控制逻辑(除了单个循环或if / else外)没有太多,则可能是Shell脚本。
  • 如果任务是命令行指令的自动化,那么几乎肯定是shell脚本。

8

我发现此Perl vs Bash分析很有用...

http://blogs.perl.org/users/buddy_burden/2012/04/perl-vs-shell-scripts.html

为了方便起见,我复制该作者的摘要:1)bash是更好的发现,2)perl是更好的结论...

当Bash更好时...

  • 工作失败
  • 退出命令
  • 处理作业输出线
  • 这里文件
  • 文件等效
  • 文件时间戳比较
  • 波浪扩展

当Perl更好时...

对于大多数应用程序,Perl仍然不胜其烦。我可能更喜欢Perl的原因包括(但不限于):

  • 它会更快。主要是因为我实际上不需要为许多我想做的事情启动新进程(最明显的例子是基名和目录名,但通常也可以删除cut,grep,sort和wc)。
  • bash中的字符串处理充其量是最基本的,整个$ IFS东西非常笨重。
  • Shell脚本中的条件语句可能很奇怪。
  • 引用shell脚本可能是一场噩梦。
  • 除了简单案例(NPI)之外,bash的case语句还有很多需要改进的地方。
  • bash中的数组很烂。bash中的哈希(假设您的bash足够新,可以完全使用它们)更难吸。
  • 一旦处理文件或命令输出超出了我上面列出的简单情况,Perl就开始真正冒烟。
  • CPAN。

因此,bash不会很快就取代Perl。但是,这些年来,我仍然发现,有时候简单的shell脚本有时会比简单的Perl脚本简单。正如我所说,我欢迎所有试图说服我的尝试。但是,话又说回来,在您的工具箱中拥有一些不同的工具并没有错。


有趣的是,在Ruby中,所有要点(?)都不适用,因为Ruby具有at_exit(),realpath(),expand_path(),stat(),heredocs和异常(fail "error" unless system("foobar"))。
Cezary Baginski

5

以我的经验,bash与python是在开发时间和灵活性之间进行权衡的。通常,在bash脚本中建立问题的基本解决方案比在python脚本中建立起来更快。

与同等的bash脚本相比,Python会让您更多地考虑解决方案的结构。Python比bash脚本更具表达力,因此随着时间的推移,它倾向于更好地扩展和修改。一般而言,它也更具可读性。

Bash更接近文件系统,对于解决未明确定义的问题的初稿解决方案而言非常有用。出于这个原因,一旦更好地理解了问题,bash脚本可能是将某些东西原型化的一个很好的首选,并打算将其移植到python。


4

Bash是Unix shell,它包含脚本语言。它是命令处理器。您可以控制运行命令的方式,也可以实际运行它们。

Perl / Ruby / Python是通用语言。

当您需要shell脚本时,可以使用Bash

如果您想要更复杂的任务或与外壳无关。使用Python等

我绝对不会比较这些语言。Python等是可移植的。您可以在任何地方运行它们。Bash仅适用于Unix。

Python等具有大量可重用的库,可解决数百万个任务。

如果您问的话,几乎是一样的。“何时使用Paint和何时使用Photoshop”

对于电子邮件处理,我将再次使用Ruby,因为它具有许多可重用的库。

但是最好的方法是结合bash和ruby。没错。就像您在ruby中创建电子邮件处理脚本一样,bash脚本将调用该ruby脚本并运行其他命令ds。

因此,无论何时需要命令处理器,都可以使用bash。您运行unix命令并对其进行控制。

7年后更新(2019年3月)

尽管答案的主要部分没有变化,但我想指出这一点。

Bash也是一种功能强大的脚本语言。对于文本处理,这可能是绝对合法的选择。

请在下面阅读mkaito的评论。它们都是完全正确的。


1
Bash的脚本子集与任何通用脚本语言一样通用。将sed之类的常规程序添加到组合中,您将满足90%的所有脚本需求。
mkaito 2012年

1
bash是命令处理器,因此它的功能是在其脚本中运行其他unix命令和程序。就像您提到的sed等。他正在询问何时选择某种语言
bakytn 2012年

1
Shell确实是一个出色的程序启动器,但是它的脚本功能远不止这些。我建议您学习一些真正的shell脚本。
mkaito 2012年

我可以睡在地板上,但我宁愿在床上。无法比较它们具有不同目的的语言。
bakytn 2012年

2
好吧,如果Bash是地板,那么类似Haskell的东西一定是
钉子

1

与高级通用语言(如Ruby,Python或Perl)相比,像bash,ksh,zsh,sh和fish之类的Shell脚本令人惊讶地令人惊讶。尽管Shell脚本的起步时间可能比等效的通用脚本要短,但这些意外却导致了许多防御性包装代码,例如set -euo pipefail启用严格模式。

例如,即使其中一个命令失败,大多数Shell语言仍继续在Shell脚本中执行行。相比之下,通用语言在出现第一个错误时会立即失败,并且通常很繁琐,从而导致即使轻度复杂的脚本也能提供更安全,更可预测的行为。


1

高度偏见的文章。

我发现bash很难调试。Python通常过于僵化,而bash可以让您变得很有创造力。如果您是一个出色的开箱即用的思想家,那么您会喜欢bash。

我对成千上万个文件中的数百万个DNA测序读取数据运行bash脚本,这对我很有帮助。与每个人都说的相反,C ++中相同版本的脚本实际上并没有那么快地运行(在几分钟内将它们分开)。

我认为bash像perl一样,不是最用户友好/最容易阅读的。这吓跑了人们,因为大多数人都不是伟大的抽象思想家。但是更聪明,更有创造力的程序员往往喜欢它并经常使用它。如果您了解自己并且知道自己有大脑,请不要被bash吓到。如果您是一个基本的思想家,则可以坚持使用Python之类的工具。给每个人自己。


0

摘自《骆驼书》

Perl试图填补低级编程(例如C或C ++或汇编语言)和高级编程(例如“ shell”编程[例如bash])之间的空白。低级编程通常很难编写和丑陋,但快速且不受限制。在给定的机器上,很难击败编写良好的低级程序的速度。而且那里没有太多你不能做的。另一方面,高级编程往往很慢,很困难,很丑陋而且很有限。如果您的系统上没有提供所需功能的命令,那么在Shell或批处理编程中您根本无法做很多事情。Perl很容易,几乎是无限的,大多是快速的,并且有点丑陋。


0

作为经验法则,请使用性能足以胜任您手头任务的最简单的语言。而且它的特殊性仅在扩展时才真正有用。

关于可读性,如果您的编程风格很糟糕,那么Bash将会很糟糕。如果您只是在那上面扔代码,它就会变得晦涩难懂。

但是,如果将代码拆分为最短的函数,并以一种简单易懂的方式命名事物,那么它就是您可以找到的最清晰的语言。因为它非常简洁。

作为标本,这是我在Bash中最新的代码。注意它的易于理解和输入方式:

#! /bin/bash


mainFunction () {
    file="${1}"

    checkFile "${file}"
    executeFile "${file}"
}


changeToThisProgramDir () {
    cd "$( dirname "${BASH_SOURCE[0]}" )"
}


checkFile () {
    file="${1}"

    checkFileNotEmpty "${file}"
    checkFileExist "${file}"
    checkFileIsExe "${file}"
}


checkFileExist () {
    file="${1}"

    if [ ! -f "${file}" ]; then
        echo "The file doesn't exist: ${file}" >&2
        echo "If the name was correct either type: exeCute \"pathToYourExeFile\""
        echo "Or just open with exeCute from the file manager"
        exit 1
    fi
}


checkFileIsExe () {
    file="${1}"
    mime=$(fileMime "${file}")

    if [ "${mime}" != "application/x-dosexec" ]; then
        echo "Not an exe: ${file}" >&2
        exit 1
    fi
}


checkFileNotEmpty () {
    file="${1}"

    if [ "${file}" == "" ]; then
        echo "No file specified" >&2
        echo "Either type this: exeCute \"pathToYourExeFile\""
        echo "Or just open with exeCute from the file manager"
        exit 1
    fi
}


execute () {
    function="${1}"
    command="${2}"
    error=$(eval "${command}" 2>&1 >"/dev/null")

    if [ ${?} -ne 0 ]; then
        echo "${function}: ${error}" >&2
        exit 1
    fi
}


executeFile () {
    file="${1}"
    type=$(fileType "${file}")

    if [ "${type}" == "MS-DOS executable" ]; then
        execute "executeFile" "dosbox \"${file}\" -forcescaler normal2x -exit -fullscreen"
    else
        execute "executeFile" "wine \"${file}\""
    fi
}


fileMime () {
    file="${1}"

    attributes=$(file --brief --mime "${file}")
    IFS=";" read -r -a attributes <<< "${attributes}"
    echo "${attributes[0]}"
}


fileType () {
    file="${1}"

    attributes=$(file --brief "${file}")
    IFS="," read -r -a attributes <<< "${attributes}"
    echo "${attributes[0]}"
}


changeToThisProgramDir
mainFunction "${@}"
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.