Running Linux Functions inside Sqlplus - linux

Can I call user-created shell functions from inside Oracle SQLPLUS using the HOST command? If not, what's the best way to approach the problem?
Essentially, I want to run a shell file:
Shell commands
sqlplus
#file.sql
HOST mylinuxfunction...
#file2.sql
HOST anotherlinuxfunction..
exit
Shell commands
Thank you!

You can surely invoke HOST commands from SQLPlus scripts, but I imagine you are really asking whether you can use the return values from your linux functions in the rest of your SQLPlus scripts. And you also might be wanting to use results from the SQL queries in your linux functions.
If you do not need to pass SQL information to your linux functions, and do not need to access the results from the linux functions in the remainder of your SQL, then what you have will almost work. This would
date
sqlplus / << xxENDxx \
#file.sql
HOST mylinuxfunction...
#file2.sql
HOST anotherlinuxfunction..
exit
xxENDxx
date
Now if you want to get information from your linux function into SQL, you will have to use external tables; a lot of setup, but look here: https://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:439619916584 and search for "but here is another interesting approach, available in 10.2.0.5 and up:"
If you want to pass information from Linux commands that are done before invoking SQLPlus into your SQL commands, that would be something like this, that inserts a row into the uptimes table with output from the uptime command that is stored in the BASH variable $UPTIMES:
#!/bin/bash
if [ "$1" = "" ]
then
echo Missing User ID parm
exit 1
else
USER_ID=$1
fi
read -p "Enter Your password for Oracle instance $ORACLE_SID for user $USER_ID: " PW
UPTIMES=`uptime | awk -F, '{print $3, $4, $5}' | awk '{printf "%2.2f,%2.2f,%2.2f\n", $3, $4, $5}'`
sqlplus /nolog << xxENDxx \
connect $USER_ID/$PW
insert into uptimes (date_stamp, one_min, five_min, fifteen_min) values (sysdate, $UPTIMES);
HOST ls -o uptimes.sh
--#file2.sql
select * from uptimes;
HOST du -sh .
exit
xxENDxx
date
Invoking the above gives this:
oracle. (/home/oracle/sql)
Linux> ./uptimes.sh mark.stewart
Enter Your password for Oracle instance ecs03 for user mark.stewart: xxxx
SQL*Plus: Release 12.1.0.2.0 Production on Thu Mar 17 20:09:36 2016
Dev:#> Connected.
Dev:MARK.STEWART#ecs03> Dev:MARK.STEWART#ecs03>
1 row created.
Dev:MARK.STEWART#ecs03> -rwxr-xr-x. 1 oracle 548 Mar 17 20:09 uptimes.sh
Dev:MARK.STEWART#ecs03> Dev:MARK.STEWART#ecs03>
DATE_STAM ONE_MIN FIVE_MIN FIFTEEN_MIN
--------- ---------- ---------- -----------
17-MAR-16 0 .01 .05
17-MAR-16 0 .01 .05
17-MAR-16 0 .01 .05
Dev:MARK.STEWART#ecs03> 146M .
Dev:MARK.STEWART#ecs03> Disconnected from Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
With the Partitioning, OLAP, Advanced Analytics and Real Application Testing options
Thu Mar 17 20:09:36 CET 2016
oracle. (/home/oracle/sql)
Linux>

Related

How to get the time when I last used the computer

In GNU/Linux on xorg session, what I want to do is to get how many seconds have passed since I stopped working with the computer (i.e. no keys pressed and/or cursor moved).
Running in the background, the script below will display secs in the status bar.
But the question is what THE_COMMAND will be.
While true; do
last_touched="$(THE_COMMAND)"
now="$(date +%s)"
secs=$((now - last_touched))
echo "${secs} seconds ago"
sleep 3
done
I remember asking the same question a while back.
Here is what I found,
last -aiF -n 1 userName
command can give you the current session.
When combined with awk you can get the result as follows
$ last -aiF -n2 username
username :1 Wed Apr 21 13:09:00 2021 still logged in 0.0.0.0
username :1 Wed Apr 21 07:28:47 2021 - down (05:39) 0.0.0.0
$ last -aiF -n 2 ogulcan | awk '{print $10}'
in
(05:39)
the lines here are the session times.
These times are counted as now - first boot login
But I believe these does not work best for you.
So here is the 8 year old question that may be helpful to you.
User Idle time in Linux
Using python you can calculate the idle time passed. Maybe this way, you can simply get what you want with python.

Not to display SQLPLUS prompt

I am trying to connect with sqlplus using a bash script. When I execute the script below SQLPLUS banner displayed.
Below the script:
$ORACLE_HOME/bin/sqlplus "/ as sysdba" <<EOF
set echo off
set heading off
spool bind.txt
select * from DBMS_LOCK_ALLOCATED where name = '$uservar';
spool off
exit
EOF
Output of the script
oracle#DMOTA01:~/script> ./before_bind.sh
SQL*Plus: Release 11.2.0.3.0 Production on Wed Nov 27 11:54:01 2019
Copyright (c) 1982, 2011, Oracle. All rights reserved.
Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
SQL> SQL> 2 3 4 Disconnected from Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
oracle#DMOTA01:~/script>
I don't want to display "SQL*Plus: Release 11............. Real Application Testing options" lines. How i can do it?
You need to add -S to sqlplus to switch it in silence mode:
$ORACLE_HOME/bin/sqlplus -S "/ as sysdba" <<EOF
set echo off
set heading off
spool bind.txt
select * from DBMS_LOCK_ALLOCATED where name = '$uservar';
spool off
exit
EOF

Access SSH client IP address, within a screen session

Accessing the IP address of a connecting SSH client is possible via environment variables (such as SSH_CONNECTION), as described in
Find the IP address of the client in an SSH session
In a GNU screen session though, those environment variables are defined by whoever started the screen to begin with. Is there any way to also get hold of the SSH connection information, for someone who enters an already-existing screen session later, like from another host?
I can't think of a way to determine this, but this can be useful in cases where screen sessions are shared between different people, for example.
If the screen session is launched as root, you can but it won't be perfectly reliable
If two users type in the same screen window, they will both interact within the same shell. One can write a command. The other can press the <enter> key.
You have to get access to the environment variable SSH_CONNECTION (or better SSH_CLIENT) which is only possible if you are root, or if you use the same user inside the screen session.
Supposing you are root inside the screen session, you can know the last user active in a screen session by using the ps command and finding the last active session.
ps h -C screen katime -o pid,user
By using the pid, and accessing the /proc/<pid>/environ file, you can get the SSH_CLIENT variable.
sed -z '/SSH_CLIENT/p;d' /proc/`ps h -C screen katime -o pid |head -1`/environ
--> SSH_CLIENT=257.31.120.12
All of this suppose that your screen is executed as root
You can also chose to log all the active connections.
For such need, I would suggest you to store both the full list of connections and their last activity.
ps eh -C screen kstime -o pid,atime | while read pid stime; do echo -n "$stime: ";\
gawk -v 'RS=\0' -F= '$1=="SSH_CLIENT" {print $2}' /proc/$pid/environ; done
Result:
00:00:00: 257.31.120.12 61608 22
00:07:11: 258.1.2.3.4 49947 22
Note that you can also parse the result of the ps eh -C screen kstime -o args command if you find it easier.
EDIT:
This is a working Debian command to get all users currently connected to the same screen session:
find /var/run/screen/
-name $(pstree -sp $$ |sed 's/.*screen(\([0-9]*\)).*/\1/;q').*
-printf "%h\n"
| cut -f2 -d-
You can check the output of the last command that would list of all IP addresses or hostnames of all connection made if sshd is the only way to connect to server.
ec2-user]# last
ec2-user pts/0 115.250.185.183 Sun May 29 13:49 still logged in
ec2-user pts/0 115.250.140.241 Sat May 28 07:26 - 10:15 (02:48)
root pts/4 113.21.68.105 Tue May 3 10:15 - 10:15 (00:00)
Alternatively (on Linux), you can check /var/log/secure where sshd will usually log all details of all the connections made even if they don't result in successful logins.
If you're trying to support the multi-display mode ('screen -x'), then as someone said above you are likely out of luck.
One the other hand, if you could assume single-user mode, then you could create a wrapper/alias for the screen command that carries along an environment variable into screen (see 'screen -X stuff ...'); in this case you are just passing along SSH_CLIENT that will have the appropriate value.
If you can assume a given username comes from a single location (or, if more than one location, then simply choose most recent), then you can do some grep/sed on output of 'last' command.
client_ip=`last -ai | grep "still logged in" | grep "$USER " | grep -v '0.0.0.0' | tail -n 1 | sed 's/.* //g'`
echo "Hello $client_ip"
If your screen is starting usually in detached mode, then in your .screenrc, add the the following:
shell -$SHELL
Then your screen will have all the the variables.
For currently running screens that you are stuck with, simply run.
source ~/.bash_profile
Replace the path and the file name to match your environment.

running ddl file through sh

I am having issue when running a ddl script file through sh on one of the servers but executes fine on another. The script is as below
sqlplus mgr/$1#$2 #export_all_tables_mgr.ddl
if [ $? != 0 ];
then
echo 'ERROR exporting MGR data, Refer to .CSV and .CTL files for detail.' | tee -a MGR_ExtractionLog.log
fi
It uses sqlplus to run the ddl file but one the rogue server, it would just connect to sql plus and won't do anything.
oracle#dbsdev55z2 $ export_all_tables_mgr.sh password servicename
SQL*Plus: Release 10.2.0.4.0 - Production on Thu Jan 24 08:39:18 2013
Copyright (c) 1982, 2007, Oracle. All Rights Reserved.
Connected to:
Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bit Production With the Partitioning, Data Mining and Real Application Testing options
SQL>
To mention here, I am using Oracle 10g here. export_all_tables_mgr.ddl file is as below
alter session set nls_date_format = 'DDMMYYYYHH24MISS';
#drop_table_temp_extraction_counts.ddl
#create_table_temp_extraction_counts.ddl
WHENEVER SQLERROR EXIT -1
WHENEVER OSERROR EXIT -1
SET HEADING OFF
SET FEEDBACK OFF
SET VERIFY OFF
SPOOL MGR_ExtractionLog.log
SELECT TO_CHAR(SYSDATE, 'DD/MM/YYYY HH24:MI:SS'), '- Start extract process' FROM dual;
SPOOL OFF
define TableName=TABLE1
#ExportTable
define TableName=TABLE2
#ExportTable
SPOOL MGR_ExtractionLog.log append
SELECT TO_CHAR(SYSDATE, 'DD/MM/YYYY HH24:MI:SS'), '- End extract process' FROM dual;
SPOOL OFF
EXIT 0
I'm guessing that this is a shell problem, try adding the following as the first line of your shell script to tell it which interpreter to use:
#!/bin/sh

Perform action when user logs in via SSH from a particular host

I have a quesiton that puzzles me and I wonder if anyone has attempted to achieve the following:
Let's assume that this is the result of my 'last' command in a Linux environment:
root pts/1 192.168.1.10 Wed Feb 10 07:04 - 07:57 (00:52)
root pts/2 Tue Feb 9 22:00 - 00:13 (02:13)
How can I setup a particular action (say for example a modified MOTD or sending an email) if the the 'root' user has logged in from 192.168.1.10. Is there a way of capturing this information?
The second part of this question is that how can I make the above check a bit more robust - i.e. if I have the following:
mary pts/1 192.168.1.10 Wed Feb 10 07:04 - 07:57 (00:52)
bob pts/2 Tue Feb 9 22:00 - 00:13 (02:13)
Now I'd like to perform an action if the username is equal to 'mary' and the host is 192.168.1.10.
Any suggestions are welcomed.
Thank you in advance.
There's a special file /etc/ssh/sshrc where you can put some commands that will runs each time someone connect by ssh. I wrote that for you :
#!/bin/bash
mail=user#domain.tld
monitored_user=root
monitored_ip=x.x.x.x
hostname=$(hostname)
# add a welcome message:
printf >&2 "\nWelcome on $hostname $USER\n"
read -d " " ip <<< $SSH_CONNECTION
[[ $ip == $monitored_ip && $USER == $monitored_user ]] || exit 0
date=$(date "+%d.%m.%Y %Hh%M")
reverse=$(dig -x $ip +short)
mail -s "Connexion of $USER on $hostname" $mail <<EOF
IP: $ip
Reverse: $reverse
Date: $date
EOF
Put this script in a file, then put the full path of the script in /etc/ssh/sshrc
In man ssh :
/etc/ssh/sshrc :
Commands in this file are executed by ssh when the user
logs in, just before the user's shell (or command) is started. See the
sshd(8) manual page for more information.
Thanks for all your replies. Eventually I managed to find a solution which does work for the time being but it does have one flaw which I'll point out in a minute.
I have added the following to my /etc/bashrc file (or /etc/bash.bashrc whatever environment you're using):
HOST="192.168.0.1"
RHOST=`who am i | sed -n 's/.*(\([^) ]*\).*/\1/p; 1q'`
if [ "$RHOST" == "$HOST" ]; then
echo "SAY WHAT!"
#add further actions here if needed
fi
The flaw that I was talking about before may actually not be a flaw. If you're already SSH-ed into the system, and you want to SSH to a host which lives on the same IP, say ssh root#your-host who am i would then print 'your-host' but I think that's the way it should be.
Needless to say that the above sed statement can be modified so you can capture the username as well, and you can extend the if/else statement to suite your needs.
Thank you again for all your replies.
You can add something to /etc/profile or equivalent that does something depending on the value of $SSH_CLIENT.
It looks like you are using last because it reads /var/log/wtmp by default which is a record of logins. The who command also allows you to read the same file but with an interface more to your needs.
For example:
$ who --ips /var/log/wtmp | grep '^msw.*127.0.0.1'
msw pts/2 2012-10-07 15:52 127.0.0.1
msw pts/3 2012-10-07 15:55 127.0.0.1
where neither of those sessions were active, but rather historic and logged.
In ubuntu i put a script in
/etc/profile.d
and when someone(user ssh) log in, it send an email to my mail
#/etc/profile.d/run_on_loggin.sh
echo $(who i am) | mail -s 'SSH Login Notification' mymail#hotmail.com
I want to create a php file with smtp, to send email with my mail to me...
some times hotmail saved in spam...
if i have the php file i will run like this...
if i want to pass var to file php run like this...
excuse my english :3
note: i think this command run from user, be carefully if the user doen't has permission to use some command or send email.
One way would be to run a simple script periodically:
#!/bin/bash
users=$(last | sed -ne '/192\.168\.1\.10/ s/\([^ ]*\).*/\1/p')
for user in $users; do
sendmail "$user" < email.txt
done
This would pipe the last command into sed to extract a user list and save it into the variable $users. The sed command uses the -n flag so it only prints what we tell it to. First, we select lines that contain the specified IP, with the /192\.168\.1\.10/ "address". On those lines, we attempt to extract the characters before a space, and if we succeed we print the result.
Then, we can loop through the $users variable and act accordingly.
One way to call this repeatedly would be through cron, and a simpler way would be to do while true; do ./my_script.bash; sleep 60; done.

Resources