用于在循环内执行程序并检查其退出值的 Shell 脚本

用于在循环内执行程序并检查其退出值的 Shell 脚本

如何在 shell 脚本中执行此操作:

for (int i=0;i<1000;i++) {

   run applicationA
   run applicationB
   if (retvalFromApplicationB!=0) {continue;}
   else {pipe ouptut (stdout) from applicationB to (stdin of) (and start) applicationC}
   if (retvalFromApplicationC!=0) {break;}
}

我正在运行Ubuntu

答案1

#! /bin/sh -
i=0; while [ "$i" -lt 1000 ]; do
  cmdA
  cmdB > tempfile || continue
  cmdC < tempfile || break
  i=$((i + 1))
done
rm -f tempfile

如果你不能用临时文件乱扔当前目录,你可以这样做:

#! /bin/sh -
i=0; while [ "$i" -lt 1000 ]; do
  cmdA 3>&- 4<&-
  tmp=$(mktemp) || exit
  exec 3> "$tmp" 4< "$tmp"
  rm -f "$tmp"
  cmdB >&3 3>&- 4<&- || continue
  cmdC <&4 3>&- 4<&- < tempfile || break
  i=$((i + 1))
done
exec 3>&- 4<&-
rm -f tempfile

cmdB无论你做什么,你都需要将该输出存储在某个地方,因为在它终止之前你无法获得退出状态。

您可以将其存储在内存中。如果cmdB的输出是文本,你可以这样做:

#! /bin/sh -
i=0; while [ "$i" -lt 1000 ]; do
  cmdA
  output=$(cmdB > tempfile && echo .) || continue
  output=${output%.}
  printf %s "$output" | cmdC || break
  i=$((i + 1))
done

如果printf未内置/bin/sh(例如,如果您已安装mkshyash制作了它sh),则输出大于 128KiB 时将会失败。

或者你可以使用perl

#! /usr/bin/perl
for ($i = 0; $i < 1000; $i++) {
  system "cmdA";
  $output = `cmdB`;
  next if $?;
  open TO_C, "|-", "cmdC" or last;
  print TO_C $output;
  close TO_C;
  last if $?;
}

答案2

我想补充一点,如果你的 shell 是 bash,那么 $?也可用。从手册页来看:“扩展到最近执行的前台管道的状态”,这是一种表示它保存最后执行的进程的退出状态的方式。

    #!/bin/bash
    for (int i=0;i<1000;i++) 
    {
       run applicationA
       retvalFromApplicationA = $?

       run applicationB
       retvalFromApplicationB = $?

       if (retvalFromApplicationB!=0) {continue;}
       else {pipe ouptut (stdout) from applicationB to (stdin of) (and start) applicationC}
       if (retvalFromApplicationC!=0) {break;}
    }

上面的代码没有捕获 applicationC 的退出状态,但它会是这样的:

applicationB | applicationC
if [ $? -eq 0 ]; then ...

这是可行的,因为最后退出的进程是 applicationC。如果您使用不同的 shell,请检查 man/info 页面。还有其他方法可以使用 && 和 || 来完成此操作运营商也是如此。

相关内容