shell脚本替换?

发布于 2024-11-15 12:19:09 字数 455 浏览 0 评论 0原文

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

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

我的大部分工作都使用 python,但是,如果我开始使用 subprocess 模块,当我尝试将它用于 shell 脚本编写时,会感觉有点冗长。

我在想这之间是否有一个好的中间立场。例如,要么编写健壮的 shell 脚本而不那么冗长,要么使用 Python 等高级语言编写不太冗长的自动化脚本。

I'm starting to get sick of shell scripts to perform automations and glue codes between stuff. I love using it for quick and dirty data processing, but even for simple 3 line code that spawns a process and remembers its process id, it's taking me very long time to program it correctly.

  • For every commands, if I don't explicitly check for return codes, the script might terminate with exit code 0 even when I don't want to. so each shell command gets followed by if statement to see whether the program terminated correctly or not..
  • Passing variables, and writing robust command line argument parser is hard (something like optparse in Python).
  • It's very hard to debug.

I use python for most of my work, and yet, it feels bit verbose when I'm trying to use it for shell-scripting purposes, if I start to use the subprocess module.

I was thinking whether there's a good middle ground between this. Like, either writing robust shell script without being so verbose, or writing less verbose automation scripts in higher level language such as Python.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

鸠魁 2024-11-22 12:19:09

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

Have you thought about using "set -e" if you can depend on the exit status of the programs you're running?

﹏半生如梦愿梦如真 2024-11-22 12:19:09

你有没有看过使用 ruby​​.它有一些语法糖,可以使编写类似 shell 的脚本变得容易。特别是反引号引用的字符串的工作方式相同,%x{..} 也是如此。事实上,有五种方法在 ruby​​ 中运行外部命令。

Have you looked at using ruby. It has a couple of bits of syntaxtic sugar to make writing shell like scripts easy. In particalar back tick quoted strings work the same way and %x{..} as well. In fact there is five ways to run an external command in ruby.

醉城メ夜风 2024-11-22 12:19:09

问题是什么?我不认为很多人会认为 Python “冗长”。它经常被提及,以表明与 Java 等语言相比,一种语言如何不会显得冗长。

顺便说一句,我认为,从语法上和历史上看,Perl 可以置于 shell 脚本和 Python 之间。

What is the question? I don't think many would consider Python 'verbose'. It is brought up often to show how a language can NOT be verbose compared to, say, Java.

By the way, Perl, syntactically and historically, can be placed between shell-scripting and Python, I think.

幽梦紫曦~ 2024-11-22 12:19:09

上面所有的好建议,尤其是 set -e,这将是解决您的反对意见 #1 的一个很好的基本解决方案。

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

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

将是这个想法的最基本的说明。

编辑

这是一个更高级的示例,是根据 SO 上的另一篇文章修改的。

if ls /path/to/files*  /dev/null 2>&1 ; then
    echo "files do exist"
else
    echo "files do not exist"
fi

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

编辑结束

不幸的是,一些 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,

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

All good suggestions above, especially set -e, which would be a good basic solution to your objection #1.

Another approach to trapping shell sub-process errors is to surround with an if statement, i.e.

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

would be the most basic illustration of this idea.

Edit

Here is a more advanced example, modified from another posting here on S.O.

if ls /path/to/files*  /dev/null 2>&1 ; then
    echo "files do exist"
else
    echo "files do not exist"
fi

Finally, is is possible to embed full pipe-line commands with the if cmd ; then syntax, but the last call in the pipe line is the what returns the true or falseness of the whole pipeline.

end of edit

Unfortunately, some Unix utility programs are not perfect (for this purpose) with their return codes, but that is very platform specific (Maybe I'm thinking of Sun4 sed, and definitely many ftp clients). It could be that a good Linux distro doesn't have this issue, but you need to check (and maybe document) each utility as you start to use it.

For objection #2, argument parsing, I can offer a complete side-step of that issue, with the negative being code that other may find hard to comprehend at first.

Rather than relying on while loop with getargs and case statements to process the arguments look to see if prepending environment variables to calling the subprocess will help you, i.e.

code with flags

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

 # more code

Now, rather than having any internal processing embedded to handle testingMode, you pre-pend the variable to the script command line, and 'turn it on' temporarily, i.e.::

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

you can have as many variables pre-pended to the front of the command as you like, so its conceivable to build a script that doesn't have any argument processing. Sometimes it makes sense and sometimes it doesn't. (Incidentally, I got this technique from reading Kernighan and Pike's 'The Unix Programming Environment')

Again, if you have to worry about passing this code off as you move to another job in the same organization, you might have to have a training class on using these little used feaure of the shell.

Your final objection, 'hard to debug' is more difficult to defend, especially errors related to mismatched {}, (), ", and '. There are numerous ksh debuggers that work along the lines of the early c-language debuggers, dbx, and gdbx.

Good luck, and let us know when you find a programming language that can 'do what I mean' :-)!!

I hope this helps.

夜无邪 2024-11-22 12:19:09

这感觉像是一个主观的、开放式的问题,但我会补充我的两分钱。

错误处理

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 feels like a subjective, open-ended question, but I'll add my two cents.

Error Handling

set -e is unreliable; different implementations interpret POSIX's definition of -e differently.

Here's what I do to catch errors:

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"

outputs:

before the false
ERROR: command 'false' failed

Argument Parsing

The template I use for argument parsing can be found in this answer.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文