0

How do I do this in a shell script:

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;}
}

I'm running Ubuntu

Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255

2 Answers2

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

If you can't litter the current directory with temp files, you could do:

#! /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

Whatever you do, you'll need to store that output somewhere as you can't get the exit status of cmdB until it has terminated.

You could store it in memory instead. If cmdB's output is text, you could do:

#! /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

If printf is not built in your /bin/sh (for instance if you've installed mksh or yash and made it sh), that will fail for output larger than 128KiB.

Or you could use perl instead:

#! /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 $?;
}
  • Thanks. If an exception is thrown by any of the applications (for example out_of_range in a vector) will the loop stop, or do I have to take care of that myself? – Bwawhwmopoloin Apr 21 '16 at 13:27
  • @Bwawhwmopoloin, what the shell sees is the exit status of the process. Exception is a paradigm of some programming languages. If those exceptions cause the process running the application compiled from the source in that programming language to die with a non-zero exit status, then yes, the shell (the || operator above) or perl (when we check for $?) will take it into account. – Stéphane Chazelas Apr 21 '16 at 13:31
0

I would add that if your shell is bash, then $? is also available. From the man page: "Expands to the status of the most recently executed foreground pipeline" which is a way of saying that it holds the exit status of the last executed process.

    #!/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;}
    }

The code above doesn't capture the exit status of applicationC, but it would be something like:

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

That works because the last process to exit would be applicationC. If you're using a different shell, check the man/info page. There are other ways to do it with the && and || operators as well.

signal7
  • 71