【问题标题】:Should a program that consists of shell commands be written in java?由shell命令组成的程序应该用java编写吗?
【发布时间】:2012-02-05 08:35:07
【问题描述】:

我有一个 shell 脚本,它执行各种命令,例如杀死进程、通过 scp 复制文件、通过 ssh 执行远程命令等...

问题是这个脚本很难维护和单元测试。 此外,我希望将来对其进行更改,以便它可以与 xml 配置文件一起使用,并且我认为它不能用 shell 脚本轻松完成。 所以,我想把它转换成一个java应用程序,但是只是用ProcessBuilder运行很多命令感觉不对。

另一方面,为今天在 shell 命令中很容易解决的每个“问题”(如 java ssh 客户端、用于 linux 进程的 java API 等)寻找 java 解决方案也感觉不对。

编辑: 我确信我的程序将在 linux 环境中运行,因此跨平台在这里不是问题。

有什么建议吗?

【问题讨论】:

  • 它难以维护的原因是它是一个围绕基本功能的“包罗万象”的包装器。在我看来,你最好围绕特定用例编写完整的应用程序(带有异常处理和junit测试),并可能为特定的维护任务保留一组有限的shell脚本。
  • /bin/sh 可以做很多很多。如果您可以将配置保留为简单的变量列表,则可以调用“source”/“。”将其读入。如果您有一个 XML 文件,请编写一个 XSLT 脚本来创建变量列表。

标签: java linux shell scripting


【解决方案1】:

我在 shell 脚本中使用了多种语言;从 Python、PHP 到 Java - 我不断返回使用正确的工具完成工作

在 linux 世界中,bash 脚本通常足够强大,而 perl 有很多良好的操作系统支持。

过去让我们的一些开发人员感到惊讶的是,您实际上可以在 bash 脚本中构建函数、传递状态并管理您通常期望的许多内容。它只是另一种语言,但以命令行为核心。

更新:

我要补充的另一件事是遵循最小惊讶原则,在这种情况下,这意味着您应该按照管理系统的人员所期望的方式编写代码。我经常看到 Java 程序员像 Java 程序员一样编写他们的部署,而不是系统管理员。如果您要将这些脚本交给系统管理员/操作员角色,那么他们可能更熟悉 shell 脚本,而不是他们必须编译的 Java 程序。

另外一点 - 将您的 shell 脚本视为正确的代码。把它放在源代码控制中(我的整个 /etc 都在 Git 管理下),有一个错误跟踪系统等。它使维护非常更容易。

【讨论】:

  • 感谢您的回复。您将如何对 bash 脚本执行单元测试?假设脚本今天执行的任务之一是调用另一个运行给定 java 程序的脚本,您将如何捕获错误?
  • 在 unix 中如何处理错误 - 通过退出代码。 slac.stanford.edu/BFROOT/www/Computing/Environment/Tools/Batch/…
  • TDD 和 Bash 之前已经回答过很多次了,这里有一个:stackoverflow.com/questions/1315624/…——值得注意的是,在测试 shell 脚本时,通常是与您调用的进程的交互是最难测试,无论是 bash / 还是任何其他语言。
  • 这个答案中有很多好的建议。 Python 将是这项特定工作的正确工具(恕我直言)
【解决方案2】:

Java 不太适合 shell 脚本,但 Groovy(基于 Java)可能更易于编写和维护,并且与 Java 完全兼容

http://groovy.codehaus.org/Running

【讨论】:

  • 如何从 groovy 调用 sqlplus $USER@$INSTANCE @$file | awk '{print $2}'
【解决方案3】:

在我看来,您需要简单的 shell 脚本编写以及维护和测试代码的能力,同时仍然能够在该语言中执行一些更高级别的任务。

幸运的是,这正是动态语言(也称为脚本语言)大放异彩的地方。有(按我个人的偏好顺序)PythonRubyPerlGroovya few others

【讨论】:

  • 你认为哪一个学习曲线最短?
  • @Antti:你有没有发现除了 Perl 之外的任何其他工具都有很好的命令行支持,你不必到处走动?我已经尝试了其中的大部分,但没有发现任何像编写 shell 脚本那样简单。
  • 在我看来,Python 的学习曲线是最小的。确实有些情况下 shell 脚本更简单,但另一方面我发现例如在编写任何超过几百行的脚本时,Python 会更舒服。
【解决方案4】:

“单元测试”shell 脚本的一个稍微有点草率的想法是有一个包装脚本,它在受控环境中执行您的脚本 - 即它定义了“模拟”您不想执行的真实命令的函数(例如ssh() { })。

这将允许您测试您感兴趣的交互,而无需担心您调用的其他进程,正如 Brainzzy 所描述的那样。这仍然非常依赖于精心设计的 bash 代码,但我认为至少在理论上是可能的。

演示:

$ cat /tmp/grep.sh
#!/bin/bash

# Simple program that relies on grep
echo -e "This is a test\nThis line doesn't match." | grep test

单元测试员:

$ cat /tmp/unittest.sh
#!/bin/bash

grep() {
  echo "Mock GREP result"
}

. "$@"

现在如果我们直接运行grep.sh,它会按预期进行搜索:

$ /tmp/grep.sh
This is a test

但如果从 unittest 脚本中运行,grep 会被函数模拟:

$ /tmp/unittest.sh /tmp/grep.sh
Mock GREP result

允许我们测试我们试图验证的任何行为。

这有几个限制因素,比如需要从同一个 shell(. 命令)运行,这意味着如果脚本依次调用其他脚本,它们将再次调用真正的命令。

另一种方法是在单元测试目录中定义一组脚本,例如

$ ls /usr/local/unitbin
grep
ssh
svn

然后让单元测试脚本更改脚本运行的路径,例如:

$ cat /tmp/unittest.sh
#!/bin/bash

PATH=/usr/local/unitbin:$PATH "$@"

这应该适用于依次调用其他脚本的脚本。


就像我说的那样,这两个例子都有些荒谬,而且可能带来的麻烦多于它们的价值。在考虑这条道路之前,我肯定会考虑这个问题的其他答案。但是,如果您想要对 bash 代码进行单元测试,但无法在沙盒中安全运行,则这些选项之一可能适合您。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-06-22
    • 1970-01-01
    • 2011-03-29
    • 2013-07-18
    • 2010-09-17
    • 2012-05-30
    • 2012-03-01
    相关资源
    最近更新 更多