Shell脚本替换?

时间:2011-06-15 06:37:01

标签: python shell

我开始厌倦了shell脚本来执行自动化并在各个东西之间粘合代码。我喜欢将它用于快速和脏的数据处理,但即使对于生成进程并记住其进程ID的简单3行代码,我也需要很长时间才能正确编程。

  • 对于每个命令,如果我没有明确检查返回代码,即使我不想,脚本也可能以退出代码0终止。所以每个shell命令后跟if语句,以查看程序是否正确终止..
  • 传递变量,编写健壮的命令行参数解析器很难(类似于Python中的optparse)。
  • 调试非常困难。

我在我的大多数工作中使用python,但是,如果我开始使用subprocess模块,当我尝试将它用于shell脚本时,感觉有点冗长。

我在想是否在这之间有一个良好的中间立场。比如,编写健壮的shell脚本而不是那么冗长,或者用更高级的语言(如Python)编写更简洁的自动化脚本。

5 个答案:

答案 0 :(得分:2)

如果您可以依赖正在运行的程序的退出状态,您是否考虑过使用“set -e”?

答案 1 :(得分:2)

你看过使用红宝石吗?它有几个合成糖,使编写shell像脚本容易。在特定的返回刻度中,引用的字符串以相同的方式工作,%x{..}也是如此。事实上,在ruby中运行外部命令有five ways

答案 2 :(得分:1)

问题是什么?我不认为很多人会认为Python'详细'。经常提出它来表明,与Java相比,语言不会冗长。

顺便说一下,我认为Perl在语法和历史上可以放在shell脚本和Python之间。

答案 3 :(得分:1)

上面提到的所有好建议,尤其是set -e,这对您的异议#1来说是一个很好的基本解决方案。

捕获shell子进程错误的另一种方法是用if语句包围,即

if true ; then
    printf "success\n"
else
    printf "failure\n"
fi

将是这个想法的最基本的例证。

修改

这是一个更高级的示例,在S.O。

上的另一个帖子中进行了修改
if ls /path/to/files*  /dev/null 2>&1 ; then
    echo "files do exist"
else
    echo "files do not exist"
fi

最后,可以使用if cmd ; then语法嵌入完整的管道命令,但管道中的最后一次调用是返回整个管道的真或假的内容。

编辑结束

不幸的是,一些Unix实用程序并不完美(为此目的)带有返回码,但这是非常特定于平台的(也许我正在考虑Sun4 sed,绝对是很多ftp客户端)。可能是一个好的Linux发行版没有这个问题,但是当你开始使用它时,你需要检查(并且可能是文档)每个实用程序。

对于异议#2,论证解析,我可以提供该问题的完整的一步,其中负面的代码可能一开始很难理解。

不是依赖于带有getargs和case语句的while循环来处理参数,而是查看预先考虑子进程的前置环境变量是否会对你有帮助,即

带有标志的

代码

 cat myProgram.sh
 #! /bin/bash
 set -e
 if ${testingMode:-false} ; then
     printf "${0##*/}:TestingMode:Starting:args=${@}"
 fi

 # more code

现在,不是嵌入任何内部处理来处理testingMode,而是将变量预先挂起到脚本命令行,然后暂时“打开”,即。::

 testingMode=true ./myProgram.sh otherargs that makes sense as args

您可以根据需要在命令前面添加尽可能多的变量,因此可以设想构建一个没有任何参数处理的脚本。有时它是有道理的,有时却没有。 (顺便提一下,我从阅读Kernighan和Pike的'Unix编程环境'中获得了这种技术)

同样,如果您在转移到同一组织中的另一个工作时不得不担心传递此代码,那么您可能需要有一个培训课程来使用这些少量使用的shell。

您的最终反对意见“难以调试”更难以防御,尤其是与错误的{},(),“和”相关的错误。有许多ksh调试器与早期的C语言一致调试器,dbx和gdbx。

祝你好运,当你找到一种可以“做我的意思”的编程语言时告诉我们: - )!!

我希望这会有所帮助。

答案 4 :(得分:1)

这感觉就像一个主观的,开放式的问题,但我会加上我的两分钱。

错误处理

set -e不可靠;不同的实现以不同的方式解释POSIX对-e的定义。

以下是我捕捉错误的方法:

log() { printf '%s\n' "$*"; }
error() { log "ERROR: $*" >&2; }
fatal() { error "$*"; exit 1; }
try() { "$@" || fatal "command '$@' failed"; }

try echo "before the false"
try false
try echo "after the false"

输出:

before the false
ERROR: command 'false' failed

参数解析

我可以在this answer中找到用于参数解析的模板。