Skip to Main Content
  • Questions
  • Assign return value to Unix Variable

Breadcrumb

Question and Answer

Connor McDonald

Thanks for the question, Bhaskara.

Asked: July 14, 2000 - 10:07 am UTC

Last updated: October 27, 2021 - 2:16 am UTC

Version: 8.1.5

Viewed 100K+ times! This question is

You Asked

Hi Tom,
How to assign value from SQL Plus to Unix Shell Variable?
Ex: $ SAL=`sqlplus scott/tiger -s << select max(sal) from emp; exit; EOF
Thanks,
Bhaskara


and Tom said...

It'll vary by shell, here is a ksh example:

#!/bin/ksh

x=`sqlplus / <<endl | grep KEEP | sed 's/KEEP//;s/[ ]//g'
select 'KEEP' , max(sal) from emp;
exit
endl`

echo the answer is $x


the SED's are all on the same line and in the [ ] is a SPACE and a TAB. When I run this, I get:

$ ./test
the answer is 5000





Rating

  (37 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

A reader, December 23, 2003 - 2:22 pm UTC

Tom,

I have a similar need but i am querying v$session to see the number of sessions and this is what i get.

$ cat t2.sh
#!/bin/ksh

x=`sqlplus "/ as sysdba" <<endl | grep KEEP | sed 's/KEEP//;s/[ ]//g'
select 'KEEP' , count(*) from v$session;
exit
endl`
echo the answer is $x

$./t2.sh
the answer is sys@ORA9I>select'',count(*)fromv


I tried using "\" before the $ in the tablename, didn't work either.

Thanks

Tom Kyte
December 23, 2003 - 5:23 pm UTC

well, you got '*' in there, $'s (that need to be doubly escaped....)


try this:

#!/bin/ksh

x=`sqlplus "/ as sysdba" <<endl | grep KEEP | sed 's/KEEP//;s/[ ]//g'
select 'KEEP' , count(1) from "V\\\$SESSION";
exit
endl`
echo the answer is $x


if I rememeber right

A reader, December 23, 2003 - 5:54 pm UTC

code=`sqlplus -s / << EOF
select max(sal)
from emp
where empno=934;
EOF`

echo $code

How to assign value from SQL Plus to Unix Shell Variable

D. Sasi kumar, June 21, 2005 - 12:31 am UTC

Very nice. But i want to know how to assign multiple values from the query to the linux variables.

Tom Kyte
June 21, 2005 - 8:19 am UTC

just an exercise in shell scripting at this point.

you might, instead of assigning the output of sqlplus to a variable, have sqlplus create a shell script with set commands in it and run that after running sqlplus itself.

A reader, June 21, 2005 - 8:32 am UTC

Tom,
This is not an Oracle question, but since your knowledge goes much beyond Oracle, I am asking. I have seen a lot of shell scripts like:

sqlplus / << EOF
...
EOF

My question is what is the purpose of << EOF? The scripts just run fine even without << EOF.

Thanks


Tom Kyte
June 21, 2005 - 4:58 pm UTC

what do you mean they run just fine?


but the EOF is an arbitrary string, EOF stands for End of File.. It is a convention used.

when you use the <<STRING you are telling the shell to pipe the following data into the program (sqlplus in this case) until it sees that string in column 1 again


sqlplus / <<X
...
...
X

would work too

EOF=END OF FILE

Paul, June 21, 2005 - 10:25 am UTC

Basically that just tells sqlplus to treat all the text until it hits EOF as a script. It is inlining a script into a shell script.  You do not have to EOF, it is just a convention.

Of course the '/' indicates they are using OS authentication and the script is logging into the DB as itself.

here is a sample with EOF and another terminator, except I do not have an OS authenticated user.


oracle@lnxdev:~$ sqlplus scott/tiger <<EOF
> select sysdate from dual;
> EOF

SQL*Plus: Release 9.2.0.4.0 - Production on Tue Jun 21 10:15:26 2005

Copyright (c) 1982, 2002, Oracle Corporation.  All rights reserved.


Connected to:
Oracle9i Enterprise Edition Release 9.2.0.4.0 - Production
With the Partitioning and Oracle Data Mining options
JServer Release 9.2.0.4.0 - Production

SQL>
SYSDATE
---------
21-JUN-05

SQL> Disconnected from Oracle9i Enterprise Edition Release 9.2.0.4.0 - Production
With the Partitioning and Oracle Data Mining options
JServer Release 9.2.0.4.0 - Production
oracle@lnxdev:~$ sqlplus scott/tiger <<XXX
> select sysdate from dual;
> XXX

SQL*Plus: Release 9.2.0.4.0 - Production on Tue Jun 21 10:15:45 2005

Copyright (c) 1982, 2002, Oracle Corporation.  All rights reserved.


Connected to:
Oracle9i Enterprise Edition Release 9.2.0.4.0 - Production
With the Partitioning and Oracle Data Mining options
JServer Release 9.2.0.4.0 - Production

SQL>
SYSDATE
---------
21-JUN-05

SQL> Disconnected from Oracle9i Enterprise Edition Release 9.2.0.4.0 - Productio
  

Getting more than one value

John, June 21, 2005 - 10:51 am UTC

The answer shown above works fine if you are trying to retrieve a single value from sqlplus. If you have a sqlplus script that returns multiple columns, you could read them into shell variables like this:

sqlplus / @myscript.sql | read var1 var2 var3

This will read 3 columns into var1, var2, and var3. Make sure that if you do this, you don't have blank or null values coming back, otherwise the "read" command will skip over the blanks/nulls and get the variable assignments out of sync.

Another variation: if you are retrieving multiple rows as well as columns in your sqlplus script, and want to loop over the rows:

sqlplus / @myscript.sql | while read var1 var2 var3
do
<more shell stuff here>
done

A specific example:

in emps.sql:

set head off
set verify off
set feedback off
set head off
set pages 0

select empno, empname
from scott.emp;

exit;

In test.sh:

sqlplus / @emps.sql | while read eno ename
do
echo "Employee number is $eno Name is $ename"
done

Hope this helps

Tom Kyte
June 21, 2005 - 5:08 pm UTC

thanks, appreciate that.

calling functions; procs (in out params) in packages

cosmin, June 21, 2005 - 11:32 am UTC

hi all,
thanks for the great examples;
if someone could expand upon this by providing some simple examples on calling functions, procedures (with in/out params), global variables, that would be great. Perhaps an intro (or a web reference or book) into Ora to Unix communication/interaction might be of great value for those of us migrating from Windoze ;-) to Unix/Linux.

thanks a big bunch

Using arrays (KSH)

andrew, June 21, 2005 - 1:26 pm UTC

#!/bin/ksh
echo "------------------------------"
echo "using an array..."
echo "------------------------------"
## Max 4095 in Sun OS 5.6!
set -A my_arr `sqlplus -s scott/tiger@dev <<EOF
set pagesize 0 feedback off verify off heading off echo off
SELECT table_name from user_tables where rownum < 4;
exit;
EOF`

echo "there are ${#my_arr[*]} elements in the array"
element=0
while [ $element -lt ${#my_arr[*]} ]
do
echo "==>"${my_arr[$element]}
let element=$element+1;
done

echo "Echo all in one command now!"
echo ${my_arr[*]}

echo "------------------------------"
echo "using while read..."
echo "------------------------------"
sqlplus -s scott/tiger@dev <<EOF > tmp.txt
set pagesize 0 feedback off verify off heading off echo off
SELECT table_name from user_tables where rownum < 4;
exit;
EOF

while read reslt_line
do
echo "==>"$reslt_line
done < tmp.txt




The output:
------------------------------
using an array...
------------------------------
there are 3 elements in the array
==>TAB1
==>TAB2
==>TAB3
Echo all in one command now!
TAB1 TAB2 TAB3
------------------------------
using while read...
------------------------------
==>TAB1
==>TAB2
==>TAB3


Playing around with arrays, stored procs and host variables

andrew, June 21, 2005 - 1:30 pm UTC

#!/bin/ksh
#======================================================
# stored proc with parms
#======================================================
## CREATE OR REPLACE PROCEDURE p1 (i_parm IN NUMBER, o_parm OUT NUMBER)
## IS
## BEGIN
## o_parm := 5 * i_parm;
## END;
## /
my_in_parm=5
echo =============================
echo FIRST
echo =============================
RETVAL=`sqlplus -s scott/tiger@dev <<EOF
set serveroutput on
WHENEVER SQLERROR EXIT 1
declare
x number := $my_in_parm;
y number;
begin
p1(x, y);
dbms_output.put_line('o_parm from p1 is '||y);
end;
/
exit;
EOF`

echo $RETVAL
X=`echo $RETVAL | awk '{print $5}'`
echo $X

## CREATE OR REPLACE PROCEDURE p2 (i_parm IN NUMBER, o_parm OUT NUMBER)
## IS
## BEGIN
## o_parm := 5 * i_parm;
## DBMS_OUTPUT.put_line ('Line one');
## DBMS_OUTPUT.put_line ('Line two');
## END;
## /
my_in_parm=5
echo =============================
echo SECOND
echo =============================
set -A my_arr `sqlplus -s scott/tiger@dev <<EOF
set serveroutput on
WHENEVER SQLERROR EXIT 1
declare
x number := $my_in_parm;
y number;
begin
p2(x, y);
dbms_output.put_line('o_parm from p1 is '||y);
end;
/
exit;
EOF`

echo "there are ${#my_arr[*]} elements in the array"
element=0
while [ $element -lt ${#my_arr[*]} ]
do
echo "==>"${my_arr[$element]}
let element=$element+1;
done


>t.ksh

=============================
FIRST
=============================
o_parm from p1 is 25 PL/SQL procedure successfully completed.
25
=============================
SECOND
=============================
there are 13 elements in the array
==>Line
==>one
==>Line
==>two
==>o_parm
==>from
==>p1
==>is
==>25
==>PL/SQL
==>procedure
==>successfully
==>completed.

To "A reader" and Tom...

Dan Kefford, June 21, 2005 - 8:52 pm UTC

Just wanted to add that the following construction:

some_command <<ARBITRARY-TOKEN
other_command_returning_a_value
ARBITRARY-TOKEN

uses what is known as a "here document". Zip to section 2.3 of the following document for a more detailed description:

</code> http://www.ceri.memphis.edu/computer/docs/unix/bshell.htm <code>

Apparently the Bourne shell was the first environment to possess this feature, and it was carried over into the Korn and Bourne-again shells, as well as Perl apparently.


thanks

cosmin, June 23, 2005 - 11:23 am UTC

just a quick word of thanks to everyone contributing to this forum. You are all great and making this into a very valuable knowledge source.

Keep up the awesome job, everyone!!!

Tom Kyte
June 23, 2005 - 6:52 pm UTC

absolutely, thanks, everyone has something to contribute.

Being a SYBASE guy needing to know how to do it with ORACLE

Damian, July 14, 2005 - 10:50 am UTC

Thanks chaps.

This is most useful. I have done lots of this sort of stuff using SQSH and ISQL with SYBASE but my ORACLE is very rusty.

This will be invaluable.

Cheers

Damian

Shell Programing

Reader, April 06, 2006 - 10:26 am UTC

Hi Tom.
The example above are very useful.
Could you please recommend on a book or any other
documentation that deal with shell progrmaning for
oracle dba
Regards.


Alexander the ok, February 23, 2007 - 12:24 pm UTC

Hi Tom,

I am thinking of writing a shell script to tkprof trace files for me. I'm struggling with how to get the udump directory programmatically though because not everyone here uses the default location. I'd like to query the data dictionary and return that into a variable but I can't find anywhere that is stored?

All my other ideas are hack like, eg greping the spfile, or using sho parameter. That would involve chopping up string that could vary in length. Any suggestions?
Tom Kyte
February 26, 2007 - 10:52 am UTC

I am sure there are more elegant solutions to this, but hey - it works:

[tkyte@tkyte-pc ~]$ cat test.sh
#!/bin/bash

X=`sqlplus / <<EOF | grep '^UDD ' | awk '{print $2}'

set serveroutput on
declare
        l_status number;
        l_dummy binary_integer;
        l_user_dump_dest long;
begin
        l_status := dbms_utility.get_parameter_value( 'user_dump_dest', l_dummy, l_user_dump_dest );
        dbms_output.put_line( 'x' );
        dbms_output.put_line( 'UDD ' || l_user_dump_dest );
end;
/
exit
EOF`

echo $X
[tkyte@tkyte-pc ~]$ ./test.sh
/home/ora10gr2/admin/ora10gr2/udump


Alexander the ok, February 27, 2007 - 10:10 am UTC

Ok it's stupid question time. I can't figure out why mine just spits out a blanks line?

$ vi test.sh
"test.sh" [New file]
#!/bin/bash

X=`sqlplus / <<EOF | grep '^UDD ' | awk '{print $2}'

set serveroutput on
declare
l_status number;
l_dummy binary_integer;
l_user_dump_dest long;
begin
l_status := dbms_utility.get_parameter_value( 'user_dump_dest', l_dummy, l_user_dump_dest
);
dbms_output.put_line( 'x' );
dbms_output.put_line( 'UDD ' || l_user_dump_dest );
end;
/
exit
EOF`

echo $X

~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
"test.sh" [New file] 21 lines, 415 characters
$ chmod u+x test.sh
$ ./test.sh

$

Tom Kyte
February 27, 2007 - 11:03 am UTC


use:

#!/bin/bash -vx


so you can see "debug" output from the shell script.

Alexander the ok, February 27, 2007 - 11:45 am UTC

Does this mean anything to you:


sqlplus / <<EOF | grep '^UDD ' | awk '{print $2}'
++ sqlplus /
++ grep '^UDD '
++ awk '{print $2}'
+ X=

echo $X
+ echo

Tom Kyte
February 27, 2007 - 1:56 pm UTC

oh, does

$ sqlplus /

work for you - I used OS authentication - can you?

Here one way

Michael, February 27, 2007 - 2:18 pm UTC

[TIGGER:/home/oracle]$ ./t.sh
/ora_admin/TIGGER/udump
[TIGGER:/home/oracle]$ cat t.sh
#!/bin/bash
X=`sqlplus -SL / <<EOF
set pause off pages 0 echo off verify off feed off termout off
select value from v\\$parameter where name='user_dump_dest';
exit
EOF`
echo $X
exit
[TIGGER:/home/oracle]$

Tom Kyte
February 27, 2007 - 2:37 pm UTC

i think their problem is "sqlplus /"

sqlplus is never logging in!

Alexander the ok, February 27, 2007 - 2:37 pm UTC

Yes I can, thanks that was the issue though. I can't just use / I need / as sysdba.
Tom Kyte
February 27, 2007 - 2:40 pm UTC

best not to use / as sysdba

why not create an ops$ account so that just / works.

Arrays in Unix and Oracle

Aravind, May 28, 2007 - 4:13 am UTC

Hi Tom,

I am running some sql in unix. I am planning to transfer some array into a PL/SQL array. var_list is the collection name. I have created str_array as follows:

create or replace type str_array as table of varchar2(2000);

I have an array by name sql_string formed in my unix script. I am trying to retrieve the array into the collection. I can do that by embedding the following script in while loop. But i have to avoid it. Now i am not able to use a index on the array sql_string as it is a unix variable. If i use the SQL variable as index, it gives syntax error saying bad number. But i am able to assign value to var_list(variable1) if i use

var_list(variable1):=${sql_string[1]}; ==> This works.

var_list(variable1):=${sql_string[variable1]}; ==> Bad number as it is a sql variable and unix is not able to identify the same

var_list(variable1):=${sql_string[$k]}; ==> k is a unix variable. This works, but i cannot increment the variable inside sql block. So i cannot continue to the next record

Is there any way to use a variable in the index of the array sql_string. If i use a unix variable i won't be able to increment that variable and move to the next value. I can understand that it is achievable using a loop in unix. But that means i am connecting to Oracle every now and then.

The code is as shown below. I have not included any loop in the same as of now. But thats what i intend to do if i can assign the values correctly.


sqlplus -s <Connect-String> <<XYZ
whenever sqlerror exit failure
whenever oserror exit failure
set serveroutput on
DECLARE
var_list str_array;
variable1 NUMBER;
BEGIN
variable1:=1;
var_list := str_array('');
var_list(variable1):=${sql_string[variable1]};
dbms_output.put_line(variable1);
dbms_output.put_line(var_list(variable1));
--variable1:=variable1+1;
END;
/
EXIT;
XYZ

So i was wondering if there is any way i can achieve my purpose

Chandru, June 05, 2009 - 2:13 pm UTC

Tom,
Similar kind of problem i got, when i executing a Unix script of sqlquery with return value to variable.

Script:
SQLQUERY="select 1 from dual;"

RESULTSET=`$DB_CONNECTION <<eof 
$SQLQUERY
exit;
eof`
echo "Resultset : $Resultset"

I am getting error and also I am running through MKS tool.

SQL> Error 45 initializing SQL*Plus Internal error

Thanks,
Chandru

Tom Kyte
June 08, 2009 - 12:40 pm UTC

umm, I cannot even run this - you don't tell us what $db_connection is or does?!?!?!?


presuming db_connection resolves to something meaningful....


[tkyte@dellpe ~]$ cat test.sh
#!/bin/bash
SQLQUERY="select 1 from dual;"

DB_CONNECTION="$ORACLE_HOME/bin/sqlplus /"

RESULTSET=`$DB_CONNECTION <<eof
$SQLQUERY
exit;
eof`

echo "Resultset : " $RESULTSET
[tkyte@dellpe ~]$ ./test.sh
Resultset :  SQL*Plus: Release 10.2.0.4.0 - Production on Mon Jun 8 12:12:40 2009 Copyright (c) 1982, 2007, Oracle. All Rights Reserved. Connected to: Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - Production With the Partitioning, OLAP, Data Mining and Real Application Testing options ops$tkyte%ORA10GR2> 1 ---------- 1 ops$tkyte%ORA10GR2> Disconnected from Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - Production With the Partitioning, OLAP, Data Mining and Real Application Testing options
[tkyte@dellpe ~]$



Thanks

omv, September 06, 2010 - 8:35 am UTC

Thanks, Tom it was veru useful one :)

review

varma, September 06, 2010 - 1:05 pm UTC

#!/bin/ksh
. /home/fctntwrk/gile.properties
v_test=`sqlplus $USER/$PASS@(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TC
P)(HOST=$SCHEMA)(PORT=1521)))(CONNECT_DATA=(SERVICE_NAME=$REGION)))<<EOF | grep KEEP | sed 's/KEEP//;s/[ ]//g'
SELECT 'KEEP' , count(*) FROM DUAL;
EXIT;
EOF
echo $v_test

Please let me know if there are any errors in the above code, I executed the script at first when i got a return value of 1 . But after modifying the code to read from property file I am not getting any values . I fear of an edting mistake
Tom Kyte
September 09, 2010 - 7:57 pm UTC

I am not a debugger, sorry....

Unix using count

anima, February 21, 2012 - 9:31 am UTC

I want this output so that I can check no of reports to excute .and am going to use this value again.

#!/bin/ksh
v_count=`sqlplus -_s "/" << end1 | grep A | sed 's/A//;s/[ ]//1'
select 'A',count(1) from drg_5 where process_date is null ;
EXIT
end1`
echo $v_count

output :-

hwfin21 $ sh 123.sh

hwfin21 $


Hi I have excuted this but am not getting any output no error is there .can u please suggest as am new to unix script.
Tom Kyte
February 22, 2012 - 10:15 pm UTC

[tkyte@localhost ~]$ cat x.sh
#!/bin/ksh 
x=`echo "select '===='||count(*) from all_users;" | $ORACLE_HOME/bin/sqlplus / | grep '====' | grep -v 'COUNT' | sed 's/====//'`

echo "x = " $x
[tkyte@localhost ~]$ ./x.sh
x =  54
[tkyte@localhost ~]$ 


is one approach.

I might suggest you code your logic to run the reports in PLSQL instead ;) you'll find it to be a better programming language over ksh

Getting error while passing shell variable to utl.mail.send

Ashish, April 23, 2012 - 2:35 am UTC

Hello,

I am new in shell scripting and i am stuck , my code is producing below error:

ORACLE_BASE=/oracle; export ORACLE_BASE
ORACLE_HOME=$ORACLE_BASE/product/10.2.0.4/db_1; export ORACLE_HOME
ORACLE_SID=pindb; export ORACLE_SID
PATH=/usr/sbin:$PATH; export PATH
PATH=$ORACLE_HOME/bin:$PATH; export PATH
LD_LIBRARY_PATH=$ORACLE_HOME/lib:/lib:/usr/lib; export LD_LIBRARY_PATH
CLASSPATH=$ORACLE_HOME/JRE:$ORACLE_HOME/jlib:$ORACLE_HOME/rdbms/jlib; export CLASSPATH
login='system/manager'
code=`
sqlplus -s $login <<EOF
set heading off
set feedback off
SELECT tablespace_name,(SUM(bytes/1024/1024)) FROM dba_free_space WHERE tablespace_name IN ('PIN00','PINX00','SYSTEM','SYSAUX','UNDOTBS1','STATSPACK') GROUP BY tablespace_name;
exit`

output:

PIN00 28287.1172 PINX00 93813.1367 STATSPACK 54.1875 SYSAUX 215.125 SYSTEM .1015625 UNDOTBS1 745.8125 6 rows selected.

Here its working very fine but when i am passing code variable to utl_mail.send procedure, its giving error same as i mentioned previous. I have put all the environment variable as well. But when i put utl_mail.send and pass CODE variable into it it gives error.

ORACLE_BASE=/oracle; export ORACLE_BASE
ORACLE_HOME=$ORACLE_BASE/product/10.2.0.4/db_1; export ORACLE_HOME
ORACLE_SID=pindb; export ORACLE_SID
PATH=/usr/sbin:$PATH; export PATH
PATH=$ORACLE_HOME/bin:$PATH; export PATH
LD_LIBRARY_PATH=$ORACLE_HOME/lib:/lib:/usr/lib; export LD_LIBRARY_PATH
CLASSPATH=$ORACLE_HOME/JRE:$ORACLE_HOME/jlib:$ORACLE_HOME/rdbms/jlib; export CLASSPATH
login='system/manager'
code=`
sqlplus -s $login <<EOF
set heading off
set feedback off
SELECT tablespace_name,(SUM(bytes/1024/1024)) FROM dba_free_space WHERE tablespace_name IN ('PIN00','PINX00','SYSTEM','SYSAUX','UNDOTBS1','STATSPACK') GROUP BY tablespace_name;
exit`
$ORACLE_HOME/bin/sqlplus -s /nolog << EOF
connect / as sysdba
exec UTL_MAIL.SEND(sender=>'ashish.kumar1@mycp.com', recipients=>'ashish.kumar1@mycp.com', cc =>'ashish.kumar1@mycp.com' , subject=>'$ORACLE_SID BACKUP', message =>'$code')
exit;
EOF
echo "sqlplus exited"

ERROR:
ORA-01756: quoted string not properly terminated

SP2-0734: unknown command beginning "PIN00 ..." - rest of line ignored.
SP2-0734: unknown command beginning "PINX00 ..." - rest of line ignored.
SP2-0734: unknown command beginning "STATSPACK ..." - rest of line ignored.
SP2-0734: unknown command beginning "SYSAUX ..." - rest of line ignored.
SP2-0044: For a list of known commands enter HELP
and to leave enter EXIT.
SP2-0734: unknown command beginning "SYSTEM ..." - rest of line ignored.
SP2-0734: unknown command beginning "UNDOTBS1 ..." - rest of line ignored.
sqlplus exited

Thanks,
Ashish
Tom Kyte
April 23, 2012 - 1:23 pm UTC

use

begin
utl_mail.send( .... );
end;
/

the EXECute statement must be contained on a single line - an anonymous block does not.

Getting error while passing shell variable to utl.mail.send

Ashish, April 23, 2012 - 3:32 am UTC

Hello,

when code varibale is getting more than one record its throwing error.

How to pass multiline shell variable into my code.

Thanks,
Ashish


Tom Kyte
April 23, 2012 - 1:23 pm UTC

see above

Ashish, April 23, 2012 - 11:53 pm UTC

Hello,

now i am getting error like
ERROR at line 1:
ORA-29278: SMTP transient error: 451 See http://pobox.com/~djb/docs/smtplf.html
ORA-06512: at "SYS.UTL_SMTP", line 20
ORA-06512: at "SYS.UTL_SMTP", line 96
ORA-06512: at "SYS.UTL_SMTP", line 345
ORA-06512: at "SYS.UTL_MAIL", line 591
ORA-06512: at "SYS.UTL_MAIL", line 608

but i am able to run it on sqlplus, only problem i am getting while running it through shell script.

Thanks
Ashish



Tom Kyte
April 24, 2012 - 7:44 am UTC

seems like a windoze (they do \r\n for end of lines) versus unix (they do a \n for end of lines)

when you do it from sqlplus, your sqlplus is running on windows - when you do it from unix, it is not. the end of line markers are different


if you were to have read the referenced URL, it would have explained that.


it (the referenced URL) also contains the proper fixes

but in the meantime, you can write code that ensures end of lines are \r\n when it is run from unix

Shell variable is not working

ashish, April 30, 2012 - 2:32 am UTC

Hello,

Below is my shell script
#!/bin/ksh
ORACLE_BASE=/oracle; export ORACLE_BASE
ORACLE_HOME=$ORACLE_BASE/product/10.2.0.1/db_1; export ORACLE_HOME
ORACLE_SID=rman; export ORACLE_SID
PATH=/usr/sbin:$PATH; export PATH
PATH=$ORACLE_HOME/bin:$PATH; export PATH
LD_LIBRARY_PATH=$ORACLE_HOME/lib:/lib:/usr/lib; export LD_LIBRARY_PATH
CLASSPATH=$ORACLE_HOME/JRE:$ORACLE_HOME/jlib:$ORACLE_HOME/rdbms/jlib; export CLASSPATH
cd /oralogs/catp/rman_db_bkp
DTIME="`date +%d%m%y`_`date +%H%M%S`"
rman target / catalog rman/cat@catp log=/oralogs/catp/rman_db_bkp/${ORACLE_SID}_${DTIME}.log<<EOF
run { execute script level_0; }
EOF

when i run above script from crontab it runs fine and making log file same as i wanted(rman_300412_125900.log).

but problem is the same script i run using dba_scheduler it works fine but creating log file like this(rman__.log).

Please help

Thanks,
Ashish


Tom Kyte
April 30, 2012 - 8:35 am UTC

well, when you run this from the database - you inherit the database environment. You inherit the PATH that the database decides you should have (which is pretty much "empty" for security reasons)

So, since date is a program - and you are not being explicit - you are just running date and not /bin/date or where ever date is on your system - you are probably "failing" right there and you don't have any sort of error handling so you don't even know that is happening.... :(

suggestion - when writing a script NEVER rely on the PATH for *ANYTHING*. Always explictly invoke ALL PROGRAMS (security! correctness!)

reader, July 10, 2012 - 12:06 pm UTC

Tom,

I want to pass an IN OUT parameter to a pl/sql procedure and call that from a shell script. I want the return value from procedure to capture in a shell variable. can you advise?

create or replace procedure p1(i_id in number, io_step_id in out number)
is
v_step_id number := io_step_id + 1;
begin

dbms_output.put_line('io_step_id =>'|| io_step_id);
io_step_id := v_step_id + 1;
dbms_output.put_line('io_step_id =>'|| io_step_id);


end;

exec p1(1, 1);
Tom Kyte
July 11, 2012 - 5:16 pm UTC

shell doesn't really support "programming" like that.

You would have to do something like print out the return value with some tag you can grep out and sed the answer out.

something like this, it is NOT BIND FRIENDLY and you cannot make it bind friendly - sqlplus is a simple command line tool - nothing more, nothing less.

I suggest you use perl or something with real programming capabilities.

this has no error handling, you need to figure all that stuff out


#!/bin/bash

x=1
y=1

z=`sqlplus / <<EOF | grep ^answer | sed "s/^answer: //"
set serveroutput on
declare
    l_tmp number := $y;
begin
   p1( $x, l_tmp );
   dbms_output.put_line( 'answer: ' || l_tmp );
end;
/
exit
EOF`

echo I got $z

reader, July 13, 2012 - 9:08 am UTC

Tom,

I have a shell script which does the following -
1) downloads file using wget command
2) Loads to database using SQL*LOADER
3) Calls pl/sql package to load data into staging and after
cleaning up data in staging moves to business area achema

PL/SQL package calls logs data into logging tables in addition to cleaning up data in staging and moving to business area schema. I wanted to capture all the actions that happens in the shell script like calling shell function to download file, loading data using sqlloader, shell function which calls pl/sql package, actions that happen in database. STEP_ID will be unique for all these steps. The sub_step_id shloud contain 1,2,3,4,....(sequential). This was the reason, I was trying to use a IN, OUTparameter in the above question, that I asked on July 10th. I pass these sub_Step_id back and forth from shell scrip to DB and DB to shell script. Is there any better way to handle this?

My LOG_TABLE table is as shown below -

CREATE TABLE LOG_TABLE
(
STEP_ID NUMBER NOT NULL,
SUB_STEP_ID NUMBER NOT NULL,
SCRIPT_TYPE VARCHAR2(100),
SCRIPT VARCHAR2(1000),
PROCEDURE_CALL VARCHAR2(4000),
EVENT VARCHAR2(20),
PROCESS_TABLE VARCHAR2(100),
ROW_COUNT NUMBER,
LOG_MESSAGE VARCHAR2(4000),
LOG_MESSAGE_DT DATE DEFAULT sysdate NOT NULL,
PROCESS_CODE VARCHAR2(100) NOT NULL,
FILE_DATE DATE,
COMMIT_DT DATE DEFAULT sysdate NOT NULL,
COMMIT_USR VARCHAR2(30) DEFAULT USER NOT NULL
);

Sample data:
100 1 SHELL load.sh f_get_file DOWNLOAD http://www.xyz.com/test.csv
100 2 SHELL load.sh f_truncate_load_table FUNCTION_CALL Truncate load table - Shell function
100 3 DB pkg_stg pkg_stg.sp_main( 20120709); PROCEDURE_CALL Begin sp_main procedure
100 4 DB pkg_stg pkg_stg.proc1( 100); EXCEPTION No Data Found
100 6 SHELL load.sh f_build_ctl_file SQLDR_CTL Build SQLLDR control file
100 7 SHELL load.sh f_load_file LOAD_FILE Load data using SQL*Loader
100 8 SHELL load.sh f_archive_file ARCHIVE Archive files
100 9 SHELL load.sh f_publish FUNCTION_CALL Truncate stg table - Shell function
100 10 DB load.sh pkg_stg.proc2(100) PROCEDURE_CALL
Tom Kyte
July 16, 2012 - 3:36 pm UTC

You should use a real programming language with database API's to do database stuff. Everything you do in a shell script is going to smell of "hack".

At the very least, I would have the shell script

a) wget the file
b) use sqlplus to run a script to do EVERYTHING ELSE

do not use sqlldr, use an external table. plsql will do that
do not clean up data in shell, plsql will do that

plsql is a "real" language (as is perl and many others outside of the database - shell, not so much).


My preferred approach would be to just call plsql and let it get the file (utl_http, utl_file), external table it, process it, clean up, and exit. the shell script would be about one line long.


Otherwise, it is going to look ugly like the above does.

Return Variable Replacing Comma with Space

Manas, October 18, 2012 - 7:06 am UTC

DB -->
select * from v$version;
Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - Production
PL/SQL Release 11.2.0.2.0 - Production
CORE 11.2.0.2.0 Production
TNS for Linux: Version 11.2.0.2.0 - Production
NLSRTL Version 11.2.0.2.0 - Production

Unix-->
Linux 2.6.9-55.ELsmp #1 SMP Fri Apr 20 17:03:35 EDT 2007 i686 i686 i386 GNU/Linux

Code -->
#!/bin/bash

IFS=","

echo "Please enter the Utility iD's?"
read input_details

invalid_utility=`sqlplus -s / << END
set heading off
set pagesize 0
set linesize 9999
set tab off
set feedback off
whenever sqlerror exit 1

SELECT listagg (utility
, ',')
WITHIN GROUP (ORDER BY utility)
AS utility_list
FROM (WITH utilities
AS ( SELECT REGEXP_SUBSTR (
'$input_details'
, '[^,]+'
, 1
, ROWNUM)
utility
FROM DUAL
CONNECT BY ROWNUM <=
LENGTH (
'$input_details')
- LENGTH (
REPLACE (
'$input_details'
, ','))
+ 1)
SELECT utility
FROM utilities
WHERE UPPER (TRIM (utility)) NOT IN (SELECT UPPER(name)
FROM s_table));
exit
END`

echo $invalid_utility

#<<Code Ends>>
The issue I am facing is that the utility_list consists of comma seperated values, but when "echo $invalid_utility" is executed it replaces "," with Whitespaces.

Query is used to return values which do not exists in s_table in Db.


Say I input: Apple, Maple, Traple, Chappel
Let's assume we have Maple in the Database, so it should return: Apple, Traple, Chappel
But instead it returns:Apple Traple Chappel


Tom Kyte
October 18, 2012 - 8:40 am UTC

works fine for me

[tkyte@localhost ~]$ cat test.sh
#!/bin/bash

x=`sqlplus -s / <<END
set heading off
set pagesize 0
set linesize 9999
set tab off
set feedback off
whenever sqlerror exit 1
select 'A, B, C' from dual;
END`

echo $x
[tkyte@localhost ~]$ sh test.sh
A, B, C
[tkyte@localhost ~]$ 



perhaps your query isn't producing the output you think it is. but I cannot tell since I cannot run your script.... incomplete test case :(

Use functions

A reader, October 19, 2012 - 7:56 am UTC

Greeting thomas,

And thanks like always, I just want to suggest using shell functions instead of using (`) directly, since it will make it easier to troubleshoot, example:

get_char () {
sqlplus -s / <<!
set heading off
set feedback off
set pages 0
select * from dual;
!
}

y=`get_char`

echo $y

Datafile adding script

Mohan Gosu, November 30, 2013 - 2:04 pm UTC

I am planning to have a shell script to extend datafiles and add a datafile to the tablespace when it runs out of space. Please provide me any example script. Thanks.

Found another way to pass data to the shell

A reader, March 09, 2015 - 2:03 pm UTC

Borrowed from https://blogs.oracle.com/opal/entry/sqlplus_101_substitution_varia#3_2
SQL> var maxsal number
SQL> begin
  2    select max(sal) into :maxsal from emp;
  3  end;
  4  /

PL/SQL procedure successfully completed.

SQL> column maxsal new_value msal noprint
SQL> select :maxsal maxsal from dual;



SQL> host x='&msal' ; echo the answer is $x
the answer is 5000


Another way to get the result into unix variable

Ullas gupta, March 19, 2015 - 9:27 am UTC

sqlplus -s username/pwd@db |&
print -p -- "select sysdate from dual;"
read -p -- date_now

echo $date

print -p -- "select A from dual;"
read -p -- random_var

echo $random_var

print -p -- "exit;"

The advantage here is you need to open only one Oracle connection from the shell script and execute as many sql statements as you need. You can do any shell processing in between sql queries.
Of course,you need to be sure that the query returns results and no null values.

Can't pass the exitcode variable from sql to unix

shax, June 23, 2015 - 5:28 pm UTC

#!/bin/sh

a=`sqlplus -s /nolog <<EOF
connect DTD_TRADE/encr0achdpc@S3LNDT11

var exitCode number

-- calling the PL/SQL procudure (that can raise an exception)
begin
:exitCode :=12222;
end;
/
exit :exitCode
EOF
`
echo $exitCode
echo $a



Can't pass the exitcode variable from sql to unix

test, June 23, 2015 - 5:31 pm UTC

#!/bin/sh

a=`sqlplus -s /nolog <<EOF
connect testuser/xxxxx@testdb

var exitCode number

-- calling the PL/SQL procudure (that can raise an exception)
begin
:exitCode :=12222;
end;
/
exit :exitCode
EOF
`
echo $exitCode
echo $a



Returning exit code from sqlplus in UNIX

Ken Bonacci, October 26, 2021 - 4:44 pm UTC

Security best practice is to put the connect inside the here doc. If you are not using os authentication, and you put user/passwd before the << the password will show up in ps.

Try echo $? after you call sqlplus.
On my system that returned your exit code.

Also good to use
whenever oserror exit failure
whenever sqlerror exit failure
Connor McDonald
October 27, 2021 - 2:16 am UTC

We've made some changes to sqlplus over the years so the password will not show whenever possible, but yes, this is still valid advice regardless.

Also, look at wallets for auth

https://connor-mcdonald.com/2015/09/21/connection-shortcuts-with-a-wallet/