2

I have never seen someone pipe 'exit' literal to command execution. This is the actual code I'm trying to understand,

echo exit | sqlplus user/pass@ora_instance @file.sql

I can understand the second half without any problem, sqlplus file execution like this does not require exit command to be issued since this is not interactive session there is no need to terminate. But even if they want to feed exit via stdin, then < exit might be appropriate, I may not be thinking straight. Help me understand the purpose of echo exit |

I tried somethings like this to understand,

host:/home/user#>echo exit | grep e
exit
host:/home/user#>echo exit | cd $GROOVY_HOME
host:/home/user#>

This helped me understand exit here is treated as literal and not as command exit. echo exit | seems to prevent cd $GROOVY_HOME from getting executed but, I don't understand why!

Shiva
  • 717
  • 9
  • 22
  • 3
    Evidently the programmer believed that sqlplus needs an exit command on standard in. Whether or not sqlplus does or doesn't need an exit command is a different matter; not all code is necessary or correct. And 'cat versus <' is a well-known 'wrong way to do it'. – user14387228 Oct 06 '20 at 12:16
  • @user14387228 so you believe cat (echo in my case) is simply a way to access stdin? nothing more? that's anti-climax – Shiva Oct 06 '20 at 12:23
  • 1
    On your 2nd example, piping a command to `cd` never works (try `echo foo | cd $HOME`). [Here is why](https://stackoverflow.com/questions/3437514/bash-how-to-pipe-result-from-the-which-command-to-cd). – Aserre Oct 06 '20 at 12:28
  • Damn, I can't read. It's not 'cat', it is 'echo'. 'cat' would be a long-winded replacement for '<', but 'echo' is a reasonable way to inject text that would otherwise need to be in a file to use '<'. (IMO the here-document syntax is clunkier) Sorry for sloppy commenting! – user14387228 Oct 06 '20 at 12:28
  • 1
    `sqlplus` is almost certainly ignoring its standard input anyway, given that it has a file to read commands from. – chepner Oct 06 '20 at 12:40
  • @chepner same boat, it seems some random guy in the past planned an interesting day for me – Shiva Oct 06 '20 at 12:42
  • 1
    FYI, I found [another sqlplus question](https://stackoverflow.com/questions/54153384/make-sqlplus-script-quit) that used the same method to exit after the execution of an sql script – Aserre Oct 06 '20 at 12:47
  • @Aserre that opened flood gates, in same question this [answer](https://stackoverflow.com/a/54157561/2068802) agrees with me but a comment under said answer asserts sqlplus is interactive, which I cannot agree wtih :-/ – Shiva Oct 06 '20 at 12:55

2 Answers2

1

It turns out echo exit | in front of such command is very important. And we cannot substitute it by appending < exit the behaviour changes and SQLPLUS command fails with no file found.

The answer to this question is the question and accepted answer: Make SQL*Plus script quit

# the proper way to close sqlplus if .sql file is not terminated properly.
echo exit | sqlplus user/pass@ora_instance @file.sql 

There is no alternative with shell script, maybe we can edit the .sql file

# Using < to access standard input stream throws file not found error
sqlplus user/pass@ora_instance @file.sql < exit # Won't work

Thanks for the inputs @Aserre (see comments under question for more). Summarized for closure.

Shiva
  • 717
  • 9
  • 22
1

cd $GROOVY_HOME works fine, but you are running it in a subshell, and it is not reading its standard input, so piping anything into it is not meaningful. Once the subshell exits, you are back in the parent shell, whose working directory hasn't been changed by the child. (Children can't do that.)

Try this to verify;

$ echo exit | sh -c 'cd /tmp; pwd; read -r; echo "$REPLY"'
/tmp
exit

$ pwd
/home/you

If you take out the read, the shell will simply ignore its standard input. You can exploit this;

$ echo exit | ( sh -c 'cd /tmp; pwd'; nl )
/tmp
     1  exit

$ pwd
/home/you

Notice here how the shell simply ignored its standard input, and nl instead picked it up and processed it.

Also, to tie up another loose end, < exit says to redirect from a file whose name is exit; if you don't have a file with that name, of course you will get "File not found". The Bash shell offers an alternative called a "here string";

sqlplus user/pass@ora_instance @file.sql <<<exit

or you can just use a plain old here document, which is portable all the way back to the original Bourne shell:

sqlplus user/pass@ora_instance @file.sql <<____
exit
____

For a single line of input, echo with a pipe is probably more convenient, but for a longer snippet of input, being able to embed it into your script is convenient. (Though also remember printf which lets you easily pass in multi-line strings;

printf '%s\n' 'First line' 'Second line' 'Third' | sqlplus ...

More questions about this e.g. at Multi-line string with extra space (preserved indentation), Using variables inside a bash heredoc, How to cat <<EOF >> a file containing code? etc.)

tripleee
  • 175,061
  • 34
  • 275
  • 318