简体   繁体   中英

How a function should exit when it called with here-document from shell script?

I have a COBOL program which should be run thru shell script and should accept the values from the here document. in the here document, i should call a function that should let control to be exit abnormally with exit code.

I have tried as below but it is not working for me.

This is my COBOL program:

   01  WW-ANS              PIC X value space. 

IRS-200.
      display "ARE THE ABOVE ANSWERS CORRECT? Y/N/E".
      Accept ws-ans.
      display "entered value is " ws-ans "<".

      IF WW-ANS  =  "E"  or "e"
         PERFORM STOP-RUN-CA.

      IF WW-ANS  NOT =  "Y" AND "N" AND "E"      
                    and "y" and "n" and "e"      
          PERFORM DISPLAY-01 THRU DISPLAY-01-EXIT
          GO  TO  IRS-200.

      IF WW-ANS  =  "Y" or "y"                   
          display "Program executed successfully"
          PERFORM STOP-RUN-CA. 
      ELSE                                       
          GO  TO  IRS-200.

DISPLAY-01.                       
      DISPLAY "value is >" WW-ANS "<".
      DISPLAY "INVALID RESPONSE".

This is my shell script:

#!/bin/bash
funexit ()
{
echo "calling funexit"
exit 1
}

/caplus/pub/test123<<:EOD:
1
g
$(funexit)
Y
:EOD:

Output is:

[Linux Dev:adminusr ~]$ ./test123.sh
ARE THE ABOVE ANSWERS CORRECT? Y/N/E
entered value is 1<
value is >1<
INVALID RESPONSE
ARE THE ABOVE ANSWERS CORRECT? Y/N/E
entered value is g<
value is >G<
INVALID RESPONSE
ARE THE ABOVE ANSWERS CORRECT? Y/N/E
entered value is  c<
value is >C<
INVALID RESPONSE
ARE THE ABOVE ANSWERS CORRECT? Y/N/E
entered value is Y<
Program executed successfully

When ever function gets called from here document the COBOL program accept the value as "C", since at function: it invoke the echo command and considering the first character from the "calling funexit" string, instead of getting exit.

From the function, I have removed echo statement like below:

#!/bin/bash
funexit ()
{
exit 1
}

/caplus/pub/test123<<:EOD:
1
g
$(funexit)
Y
:EOD:

Output is:

[Linux Dev:adminusr ~]$ ./test123.sh
ARE THE ABOVE ANSWERS CORRECT? Y/N/E
entered value is 1<
value is >1<
INVALID RESPONSE
ARE THE ABOVE ANSWERS CORRECT? Y/N/E
entered value is g<
value is >G<
INVALID RESPONSE
ARE THE ABOVE ANSWERS CORRECT? Y/N/E
entered value is   <
value is > <
INVALID RESPONSE
ARE THE ABOVE ANSWERS CORRECT? Y/N/E
entered value is Y<
Program executed successfully.

When ever function gets called from here document the COBOL program accept the value as spaces instead of getting exit.

The script should get exit abnormally with some exit code.

This example looks contrived because you are giving it both static input. However, that is probably because this is just a simplified example.

I guess is that you want funexit to return the E so that the input would mean that there is no more input, and nothing if there is more input. To be clear, the funexit script is called (and finishes) before COBOL is called.

I think you would want to code your shell script like this:

#!/bin/bash
funexit ()
{
  echo calling funexit 1>&2
  echo E
}

/caplus/pub/test123<<:EOD:
1
g
$(funexit)Y
:EOD:

Notice that the call to funexit and the following Y are on the same line. That way, if funexit did not return anything, the cobol program would not see a blank line. If funexit returns an E (actually an E followed by a new line) it would see the E.

Also notice that your debugging output of "Calling funexit" is redirected to standard error; before it was being sent to the cobol program and it ACCEPTed the letter C (from "Calling").

And lastly, the funexit script does not need to exit, as that is what will happen at the end of the script anyway.

@ANR;

Use ACCEPT ... ON EXCEPTION

Ala

   identification division.
   program-id. sample.

   data division.
   working-storage section.
   01 the-fields.
      05 field-one         pic x(8).
      05 field-two         pic x(8).
      05 field-three       pic x(8).
      05 field-four        pic x(8).

  *> ***************************************************************
   procedure division.

   accept field-one end-accept
   display field-one end-display

   accept field-two end-accept
   display field-two end-display

   accept field-three
       on exception
           display "no field three entered" end-display
       not on exception
          display field-three end-display
   end-accept

   accept field-four
       on exception
           display "no field four entered" end-display
       not on exception
           display field-four end-display
   end-accept

   goback.
   end program sample.

So a run with four lines of input looks like

./sample <fourdatums.txt
one
two
three
four

and with only three

./sample <threedatums.txt
one
two
three
no field four entered

Since funexit is executed in a subshell created by the command substitution, you'll need to check its exit status outside the here document to determine if the parent shell should exit.

#!/bin/bash
funexit () {
  echo "calling funexit"
  exit 1
}

output=$(funexit) || exit

/caplus/pub/test123<<:EOD:
1
g
$output
Y
:EOD:

Assign the output of your function to a variable outside the heredoc and check for failure there:

#!/bin/bash
funexit ()
{
    exit 1
}

if ! funexitvalue=$(funexit) ; then
    echo "Failure!"
    exit 1
fi


/caplus/pub/test123<<:EOD:
1
g
$funexitvalue
Y
:EOD:

This will prevent the COBOL program to be run if funexit does not exit successfully.

Explanation :

Command substitutions ( $(...) ) in bash always "work", as in, the substitution is replaced by the output of the command. Even if the command exits with an error:

$ echo "$(echo foobar; exit 1)"
foobar
$ echo $?
0

As you can see, the first echo exits successfully, even though the command in the substitution failed. The return code of the command substitution does not affect the actual command in any way.

In contrast:

$ a="$(echo foobar; exit 1)"
$ echo $?
1
$ echo $a
foobar

Here the return code of the command substitution is not shadowed by any other command, so you can actually check, if it returned successfully. Anyway, the assignment of the output to a was still successful.


Note: If you intended the COBOL program to be run up to the point where the faulty input would happen, than heredocs are not the way to go, as they are completely evaluated before they are even passed to the program. So with heredocs it is an all or nothing deal.

The heredoc is going to be parsed by the shell and passed as input in its entirety, and your approach is not going to work. However, you can certainly break up the input:

{ cat << EOF
This text will always be entered to the test123 executable;
EOF
funexit  # exit or return, as needed
cat << EOF
If funexit returned, this will go to test123.
If funexit exited, it will not
EOF
} | caplus/pub/test123

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM