![用于在循环内执行程序并检查其退出值的 Shell 脚本](https://linux22.com/image/6457/%E7%94%A8%E4%BA%8E%E5%9C%A8%E5%BE%AA%E7%8E%AF%E5%86%85%E6%89%A7%E8%A1%8C%E7%A8%8B%E5%BA%8F%E5%B9%B6%E6%A3%80%E6%9F%A5%E5%85%B6%E9%80%80%E5%87%BA%E5%80%BC%E7%9A%84%20Shell%20%E8%84%9A%E6%9C%AC.png)
如何在 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
(例如,如果您已安装mksh
或yash
制作了它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 页面。还有其他方法可以使用 && 和 || 来完成此操作运营商也是如此。