What is the purpose of "echo exit |" in "echo exit | sqlplus user/pass@ora_instance @file.sql"?

Viewed 1336

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!

2 Answers

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.

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.)

Related