s#!/bin/ksh
usrid=`sql_login.sh`
if [ "$?" -ne "0" ]; then
echo "sql login failed-Username/Password not available in control file"
exit -1
fi
a=`sqlplus -s ${usrid} <<EOF
set pause off
set heading off
set feedback off
set serveroutput off;
select 10 from dual;
exit;
EOF`
b=`sqlplus -s ${usrid} <<EOF
set pause off
set heading off
set feedback off
select 11 from dual;
exit;
EOF`
echo "Out of sqlplus session";
echo $a$b;
hi its giving output like 10 11? i need it 1011 how can i achive this?
solution:
a1=$(echo ${a#}) ;
b1=$(echo ${b#}) ;
c1=$a1$b1;
echo $c1;
There must be spaces included in the value of a (and probably b too)
You can get rid of the space by modify the value of the variable.
assuming you have bash, ksh or other POSIX shell
echo ${a% }${b% }
will probably work.
${var% } says, for ${var} remove from the left of the variable's value a space char (if there is one there.
If for some reason, you find that the space is in the front, like ' a', then use
${a# }, which means remove from the right of the variable's value a space char.
EDIT : kurumi's solution (assuming bash and POSIX shell is probably better)
because then it doesn't matter where in the line that space value occurs.
BUT why don't you concatenate the two values and have just 1 sql query?
$ab=...
select 10 + 11 from dual;
You may have to consult with you oracle friends to get this exactly right, but in the SQL Sybase DB (and probably MS SQL), this wouldn't be a problem.d
ALSO, Stop using backquotes, they are deprecate since 1992 (at least)
ab=$( cmd ) is so much nicer ;-)
I hope this helps.
P.S. as you appear to be a new user, if you get an answer that helps you please remember to mark it as accepted, or give it a + (or -) as a useful answer
you can try
c="$a$b"
echo ${c// }
or remove spaces at each individual variables themselves
a=${a// }
b=${b// }
or you can call externals
echo $a | sed -e 's/^[ \t]*//' -e 's/[ \t]*$//'
Related
I have a strange problem - possibly I'm just going blind. I have this short script, which replaces the string #qry# in the here-document with a select statement in a file and then pipes it to mysql:
#!/bin/bash
if [[ "$1" == "-h" ]]
then
echo "sqljob [sqlfile] [procnm] [host] [database] [config file]"
echo " sqlfile: text file containing an SQL statement"
echo " procnm: name that will given to the new, stored procedure"
echo " host: hostname of IP address of the database server"
echo " database: the procedure will be created here"
echo " config file: default configuration file with username and password"
exit
fi
infile=$1
procnm=$2
hn=$3
pn=$4
db=$5
mycfg=$6
{
set -o noglob
sed -e "s/#qry#/$(echo $(cat $infile))/g" <<!
drop procedure if exists $procnm;
delete from jobs where jobname="$procnm";
insert into jobs
set
notes="SQL job $procnm",
jobname="$procnm",
parm_tmpl='int';
delimiter //
create procedure $procnm(vqid int)
begin
call joblogmsg(vqid,0,"$procnm","","Executing #qry#");
drop table if exists ${procnm}_res;
create table ${procnm}_res as
#qry#
end//
delimiter ;
!
} | mysql --defaults-file=$mycfg -h $hn -P $pn $db
However, when the select contains *, it expands to whatever is in the directory even though I use noglob. However, it works from the command line:
$ set -o noglob
$ ls *
What am I doing wrong?
Edit
Block Comments in a Shell Script has been suggested as a duplicate, but as you will notice, I need to expand ${procnm} in the here-doc; I just need to avoid the same happening to select *.
I suspect it is because the construct echo (cat). The echo command gets the * from the cat command and the shell in which it runs expands it. In that shell set noglob is not active.
Try leaving the echo away: /$(cat $infile)/, in the end that is the data you need; then there is no extra glob expansion by a shell.
Due to the fact that Bash, when running in set -o nounset mode (aka set -u), may consider empty arrays as unset regardless of whether they have actually been assigned an empty value, care must be taken when attempting to expand an array — one of the workarounds is to check whether the array length is zero. Not to mention that getting the number of elements in an array is a common operation by itself.
While developing with Bash 4.2.47(1)-release in openSUSE 42.1, I accustomed to that getting array size with ${#ARRAY_NAME[#]} succeeds when array is either empty or unset. However, while checking my script with Bash 4.3.46(1)-release in FreeBSD 10.3, it turned out that this operation may fail with generic “unbound variable” error message. Providing default value for expansion does not seem to work for array length. Providing alternative command chains seems to work, but not inside a function called through a subshell expansion — functions just exits after the first failure. What else can be of any help here?
Consider the following example:
function Size ()
{
declare VAR="$1"
declare REF="\${#${VAR}[#]}"
eval "echo \"${REF}\" || echo 0" 2>/dev/null || echo 0
}
set -u
declare -a MYARRAY
echo "size: ${#MYARRAY[#]}"
echo "size: ${#MYARRAY[#]-0}"
echo "Size: $(Size 'MYARRAY')"
echo -n "Size: "; Size 'MYARRAY'
In openSUSE environment, all echo lines output 0, as expected. In FreeBSD, the same outcome is only possible when the array is explicitly assigned an empty value: MYARRAY=(); otherwise, both inline queries in the first two lines fail, the third line just outputs Size: (meaning that the expansion result is empty), and only the last line succeeds completely thanks to the outer || echo 0 — however passing the result through to the screen is not what is usually intended when trying to obtain array length.
Here is the summary of my observations:
Bash 4.2 Bash 4.3
openSUSE FreeBSD
counting elements of unset array OK FAILED
counting elements of empty array OK OK
content expansion of unset array FAILED FAILED
content expansion of unset array(*) OK OK
content expansion of empty array FAILED FAILED
content expansion of empty array(*) OK OK
(* with fallback value supplied)
To me, that looks pretty inconsistent. Is there any real future-proof and cross-platform solution for that?
There are known (documented) differences between the Linux and BSD flavors of bash. I would suggest writing your code as per the POSIX standard. You can start here for more information -> www2.opengroup.org.
With that in mind, you can start bash with the --posix command-line option or you can execute the command set -o posix while bash is running. Either will cause bash to conform to the POSIX standard.
The above suggestion will increase the probability of cross-platform consistency.
As a temporary solution, I followed the route suggested by #william-pursell and just unset the nounset option during the query:
function GetArrayLength ()
{
declare ARRAY_NAME="$1"
declare INDIRECT_REFERENCE="\${#${ARRAY_NAME}[#]}"
case "$-" in
*'u'*)
set +u
eval "echo \"${INDIRECT_REFERENCE}\""
set -u
;;
*)
eval "echo \"${INDIRECT_REFERENCE}\""
;;
esac
}
(Using if instead of case leads to negligibly slower execution on my test machines. Moreover, case allows matching additional options easily if that would become necessary sometime.)
I also tried exploiting the fact that content expansion (with fallback or replacement value) usually succeeds even for unset arrays:
function GetArrayLength ()
{
declare ARRAY_NAME="$1"
declare INDIRECT_REFERENCE="${ARRAY_NAME}[#]"
if [[ -z "${!INDIRECT_REFERENCE+isset}" ]]; then
echo 0
else
INDIRECT_REFERENCE="\${#${ARRAY_NAME}[#]}"
eval "echo \"${INDIRECT_REFERENCE}\""
fi
}
However, it turns out that Bash does not optimize ${a[#]+b} expansion, as execution time clearly increases for larger arrays — although being the smallest one for empty or unset arrays.
Nevertheless, if anyone has a better solution, fell free to post other answers.
I'm writing a simple graphing script that uses gnuplot, and I use a helper function to construct a .gscript file.
add_gscript() {
echo "->>"
echo $1
echo $1 >> plot.gscript
cat plot.gscript
}
However after passing the following argument into the function
echo "--"
echo 'set xrange [0:$RANGE]'
echo "--"
add_gscript "set xrange [0:100]"
where $RANGE has been defined beforehand, I get the following output
--
set xrange [0:$RANGE]
--
->>
set xrange 1
set datafile separator ","
set term qt size 800,640
set size ratio .618
set xrange 1
Is bash evaluating [0:100] to 1 somehow?
A fix was accurately described in comments on the question:
Always double-quote variable references to have their values treated as literals; without quoting, the values are (in most contexts) subject to shell expansions, including word splitting and pathname expansion. [0:100] happens to be a valid globbing pattern that matches any file in the current dir. named either 0 or : or 1. – mklement0
so echo "$1"; echo "$1" >> plot.gscript and any other unquoted vars. Good luck. – shellter
Double quoting the variables did indeed fix my issue. Thanks!
Consider this PS1
PS1='\n${_:+$? }$ '
Here is the result of a few commands
$ [ 2 = 2 ]
0 $ [ 2 = 3 ]
1 $
1 $
The first line shows no status as expected, and the next two lines show the
correct exit code. However on line 3 only Enter was pressed, so I would like the
status to go away, like line 1. How can I do this?
Here's a funny, very simple possibility: it uses the \# escape sequence of PS1 together with parameter expansions (and the way Bash expands its prompt).
The escape sequence \# expands to the command number of the command to be executed. This is incremented each time a command has actually been executed. Try it:
$ PS1='\# $ '
2 $ echo hello
hello
3 $ # this is a comment
3 $
3 $ echo hello
hello
4 $
Now, each time a prompt is to be displayed, Bash first expands the escape sequences found in PS1, then (provided the shell option promptvars is set, which is the default), this string is expanded via parameter expansion, command substitution, arithmetic expansion, and quote removal.
The trick is then to have an array that will have the k-th field set (to the empty string) whenever the (k-1)-th command is executed. Then, using appropriate parameter expansions, we'll be able to detect when these fields are set and to display the return code of the previous command if the field isn't set. If you want to call this array __cmdnbary, just do:
PS1='\n${__cmdnbary[\#]-$? }${__cmdnbary[\#]=}\$ '
Look:
$ PS1='\n${__cmdnbary[\#]-$? }${__cmdnbary[\#]=}\$ '
0 $ [ 2 = 3 ]
1 $
$ # it seems that it works
$ echo "it works"
it works
0 $
To qualify for the shortest answer challenge:
PS1='\n${a[\#]-$? }${a[\#]=}$ '
that's 31 characters.
Don't use this, of course, as a is a too trivial name; also, \$ might be better than $.
Seems you don't like that the initial prompt is 0 $; you can very easily modify this by initializing the array __cmdnbary appropriately: you'll put this somewhere in your configuration file:
__cmdnbary=( '' '' ) # Initialize the field 1!
PS1='\n${__cmdnbary[\#]-$? }${__cmdnbary[\#]=}\$ '
Got some time to play around this weekend. Looking at my earlier answer (not-good) and other answers I think this may be probably the smallest answer.
Place these lines at the end of your ~/.bash_profile:
PS1='$_ret$ '
trapDbg() {
local c="$BASH_COMMAND"
[[ "$c" != "pc" ]] && export _cmd="$c"
}
pc() {
local r=$?
trap "" DEBUG
[[ -n "$_cmd" ]] && _ret="$r " || _ret=""
export _ret
export _cmd=
trap 'trapDbg' DEBUG
}
export PROMPT_COMMAND=pc
trap 'trapDbg' DEBUG
Then open a new terminal and note this desired behavior on BASH prompt:
$ uname
Darwin
0 $
$
$
$ date
Sun Dec 14 05:59:03 EST 2014
0 $
$
$ [ 1 = 2 ]
1 $
$
$ ls 123
ls: cannot access 123: No such file or directory
2 $
$
Explanation:
This is based on trap 'handler' DEBUG and PROMPT_COMMAND hooks.
PS1 is using a variable _ret i.e. PS1='$_ret$ '.
trap command runs only when a command is executed but PROMPT_COMMAND is run even when an empty enter is pressed.
trap command sets a variable _cmd to the actually executed command using BASH internal var BASH_COMMAND.
PROMPT_COMMAND hook sets _ret to "$? " if _cmd is non-empty otherwise sets _ret to "". Finally it resets _cmd var to empty state.
The variable HISTCMD is updated every time a new command is executed. Unfortunately, the value is masked during the execution of PROMPT_COMMAND (I suppose for reasons related to not having history messed up with things which happen in the prompt command). The workaround I came up with is kind of messy, but it seems to work in my limited testing.
# This only works if the prompt has a prefix
# which is displayed before the status code field.
# Fortunately, in this case, there is one.
# Maybe use a no-op prefix in the worst case (!)
PS1_base=$'\n'
# Functions for PROMPT_COMMAND
PS1_update_HISTCMD () {
# If HISTCONTROL contains "ignoredups" or "ignoreboth", this breaks.
# We should not change it programmatically
# (think principle of least astonishment etc)
# but we can always gripe.
case :$HISTCONTROL: in
*:ignoredups:* | *:ignoreboth:* )
echo "PS1_update_HISTCMD(): HISTCONTROL contains 'ignoredups' or 'ignoreboth'" >&2
echo "PS1_update_HISTCMD(): Warning: Please remove this setting." >&2 ;;
esac
# PS1_HISTCMD needs to contain the old value of PS1_HISTCMD2 (a copy of HISTCMD)
PS1_HISTCMD=${PS1_HISTCMD2:-$PS1_HISTCMD}
# PS1_HISTCMD2 needs to be unset for the next prompt to trigger properly
unset PS1_HISTCMD2
}
PROMPT_COMMAND=PS1_update_HISTCMD
# Finally, the actual prompt:
PS1='${PS1_base#foo${PS1_HISTCMD2:=${HISTCMD%$PS1_HISTCMD}}}${_:+${PS1_HISTCMD2:+$? }}$ '
The logic in the prompt is roughly as follows:
${PS1_base#foo...}
This displays the prefix. The stuff in #... is useful only for its side effects. We want to do some variable manipulation without having the values of the variables display, so we hide them in a string substitution. (This will display odd and possibly spectacular things if the value of PS1_base ever happens to begin with foo followed by the current command history index.)
${PS1_HISTCMD2:=...}
This assigns a value to PS1_HISTCMD2 (if it is unset, which we have made sure it is). The substitution would nominally also expand to the new value, but we have hidden it in a ${var#subst} as explained above.
${HISTCMD%$PS1_HISTCMD}
We assign either the value of HISTCMD (when a new entry in the command history is being made, i.e. we are executing a new command) or an empty string (when the command is empty) to PS1_HISTCMD2. This works by trimming off the value HISTCMD any match on PS1_HISTCMD (using the ${var%subst} suffix replacement syntax).
${_:+...}
This is from the question. It will expand to ... something if the value of $_ is set and nonempty (which it is when a command is being executed, but not e.g. if we are performing a variable assignment). The "something" should be the status code (and a space, for legibility) if PS1_HISTCMD2 is nonempty.
${PS1_HISTCMD2:+$? }
There.
'$ '
This is just the actual prompt suffix, as in the original question.
So the key parts are the variables PS1_HISTCMD which remembers the previous value of HISTCMD, and the variable PS1_HISTCMD2 which captures the value of HISTCMD so it can be accessed from within PROMPT_COMMAND, but needs to be unset in the PROMPT_COMMAND so that the ${PS1_HISTCMD2:=...} assignment will fire again the next time the prompt is displayed.
I fiddled for a bit with trying to hide the output from ${PS1_HISTCMD2:=...} but then realized that there is in fact something we want to display anyhow, so just piggyback on that. You can't have a completely empty PS1_base because the shell apparently notices, and does not even attempt to perform a substitution when there is no value; but perhaps you can come up with a dummy value (a no-op escape sequence, perhaps?) if you have nothing else you want to display. Or maybe this could be refactored to run with a suffix instead; but that is probably going to be trickier still.
In response to Anubhava's "smallest answer" challenge, here is the code without comments or error checking.
PS1_base=$'\n'
PS1_update_HISTCMD () { PS1_HISTCMD=${PS1_HISTCMD2:-$PS1_HISTCMD}; unset PS1_HISTCMD2; }
PROMPT_COMMAND=PS1_update_HISTCMD
PS1='${PS1_base#foo${PS1_HISTCMD2:=${HISTCMD%$PS1_HISTCMD}}}${_:+${PS1_HISTCMD2:+$? }}$ '
This is probably not the best way to do this, but it seems to be working
function pc {
foo=$_
fc -l > /tmp/new
if cmp -s /tmp/{new,old} || test -z "$foo"
then
PS1='\n$ '
else
PS1='\n$? $ '
fi
cp /tmp/{new,old}
}
PROMPT_COMMAND=pc
Result
$ [ 2 = 2 ]
0 $ [ 2 = 3 ]
1 $
$
I need to use great script bash-preexec.sh.
Although I don't like external dependencies, this was the only thing to help me avoid to have 1 in $? after just pressing enter without running any command.
This goes to your ~/.bashrc:
__prompt_command() {
local exit="$?"
PS1='\u#\h: \w \$ '
[ -n "$LASTCMD" -a "$exit" != "0" ] && PS1='['${red}$exit$clear"] $PS1"
}
PROMPT_COMMAND=__prompt_command
[-f ~/.bash-preexec.sh ] && . ~/.bash-preexec.sh
preexec() { LASTCMD="$1"; }
UPDATE: later I was able to find a solution without dependency on .bash-preexec.sh.
i have a script & it goes as below,
instant_client="/root/ora_client/instantclient_11_2"
output=`$instant_client/sqlplus -s HRUSER/HRUSER#TOMLWF <<EOF
set heading off
set feedback off
set lines 10000
set pagesize 10000
select count (1) from onboardingcandidates o, candidatedetails c where o.candidateid=c.candidateid and o.JOININGSTATUS='0091' and to_date(o.joiningdate)=to_date(sysdate+5);
EOF
exit
`
query=(`$instant_client/sqlplus -s HRUSER/HRUSER#TOMLWF <<EOF
set heading off
set feedback off
set lines 10000
set pagesize 10000
select o.candidateid from onboardingcandidates o, candidatedetails c where o.candidateid=c.candidateid and o.JOININGSTATUS='0091' and to_date(o.joiningdate)=to_date(sysdate+5);
EOF`)
i=0
echo "Throwing individual arrays:"
while [ $i -lt $output ]
do
a=${query[$i]}
echo Candidate[$i]=$a
i=$(($i+1))
done
OUTPUT:
Throwing individual arrays:
Candidate[0]=cand1
Candidate[1]=cand2
Candidate[2]=cand3
Candidate[3]=cand62
REQUIRED OUTPUT
Everything is working fine.
All i need is, i need 1 output at a time.
i.e. if i run the above script then the output should be controlled.
It should throw 1 output at a time on the prompt.
Is this possible ??
IF YOU NEED ANYTHING MORE THEN PLZ ASK. I HOPE I AM CLEAR WITH MY DOUBT
So you're running two queries, one to get the count of the number of results, the second to get the results.
If you want to only have one query, you can iterate through the count of the number of results. as the variable query is an array, you can use:
${#query[*]}
as the number of result rows, then use:
while [ $i -lt ${#query[*]} ]
as the loop condition.
If you want to display one result at a time, and require an enter between them, then you can add a read after the echo.
If you want to display a specific return row, then, assuming that the routine is called as-is, then the row number to display is passed in as the first parameter $1, then you can use:
a=${query[$1]}
echo Candidate[$1]=$a
if you just want to display the result at that line, without the Candidate[] text, then you can just echo:
echo ${query[$1]}
If I have understood your question correctly, before your echo statement to print the output,put this line:
read dummy
This will prompt you to enter some key, when entered, will show the next line output.