How to make read -d return true - bash

I am using the following construct to set a multiline string in bash shell. But this always returns false which does not work when I set set -e. How can I make this to return success?
#!/bin/bash
set -x
set -e
read -d '' QUERY <<EOF
UPDATE table_name SET
field1 = 'value',
field2 = 'value'
WHERE id = 1;
EOF
mysql table_name -e "$QUERY"

While not an answer to your original question, this does get your problem solved. Consider using substitution and e.g. cat
QUERY=$(cat <<EOM
test
test2
EOM
)
mysql table_name -e "$QUERY"
Please, be aware of safety issues if you're reading those values from unsanitized input.

Related

Script with multiline string and for loop

Writing a quick script for a temporary/repetitive task. Wrote a basic solution that works:
for thing in "$#";
do
/usr/mysql/bin/mysql -u xyz -p pdq <<END;
UPDATE table
SET table_atr = 'NW'
WHERE record_id = $thing
END
done
This works but forces a password check for every member of argument array (not ideal).
Tried to update it to this:
if {$# -le 1}; then
for thing in "$#";
do
/usr/mysql/bin/mysql -u xyz -p pdq <<END;
UPDATE table
SET table_atr = 'NW'
WHERE record_id = $thing
END
done
else
things = ""
for thing in "$#";
do
things += "$thing"
if {$thing == $#[$# - 1]}; then
things += "\n"
continue
else
things += ",\n"
done
/usr/mysql/bin/mysql -u xyz -p pdq <<END;
UPDATE table
SET table_atr = 'NW'
WHERE record_id IN
(
$things
)
END
TLDR: If there is more than one argument: do a for loop to fill a WHERE .. IN () statement. I realize this doesn't even need to be a multiline string and maybe that is my issue but the error I'm getting is (apparently) unrealted .
The error I get is:
line 24: syntax error near unexpected token' done'
line 24: ' done'
Neither I, nor my supervisor have much experience with shell scripts but I cannot see any syntax error with the 2nd for loop. Its exactly the same as the first which executes fine.
Any help is greatly appreciated, I may just have to go to the basic version or write this as a Perl script instead. Thanks!
Thanks everyone for all the advice. This was an edit that worked:
#!/bin/sh
if [ $# -le 1 ]; then
for thing in "$#";
do
/usr/mysql/bin/mysql -u xyz -p pdq <<END;
UPDATE table
SET table_atr = 'NW'
WHERE record_id = $thing
END
done
else
things=""
i=1
for thing in "$#";
do
things+="$thing"
if [ $i -eq $# ]; then
things+=""
else
things+=", "
fi
((i+=1))
done
/usr/mysql/bin/mysql -u xyz -p pdq <<END;
UPDATE table
SET table_atr = 'NW'
WHERE record_id IN ($things)
END
fi
There were indeed many syntax errors and changing the WHERE .. IN () string construction to a single line made this a lot easier. Luckily I didn't have to worry about inserting single quotes, mysql took the query without them.
I came out of this with a much higher respect for bash scripting. It is a serious language that requires its own study and I will approach it with much more attention to detail in the future.
Thanks again.

How can I disable * expansion in a script?

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.

echo variable result in quotes BASH

I have a bash script like this:
#!/bin/bash
pavadinimas=$1
pavadinimas2=${pavadinimas::-4}
echo "#!/bin/sh
mysql -uUSER -pPASSWORD -DDatabase -e 'UPDATE boom SET count = count + 1 WHERE Failo_vardas="$pavadinimas"';
vlc -f --play-and-exit /var/www/html/uploads/$pavadinimas" > /var/www/html/script/"$pavadinimas2.sh"
And I'm having problem with this line:
mysql -uUSER -pPASSWORD -DDatabase -e 'UPDATE boom SET count = count + 1 WHERE Failo_vardas="$pavadinimas"';
As you see I want to add the variable to quotes, but It comes out without It. I tried a lot of combinations to solve this out, but I failed. Lack of experience :/
Script result:
#!/bin/sh
mysql -uUSER -pPASSWORD -DDatabase -e 'UPDATE boom SET count = parodymai + 1 WHERE Failo_vardas=name.mp4';
vlc -f --play-and-exit /var/www/html/uploads/gaidys.mp4
I want to echo the variable in quotes like this:
mysql -uUSER -pPASSWORD -DDatabase -e 'UPDATE boom SET count = count + 1 WHERE Failo_vardas="name.mp4"';
You are really close. You just have to escape the quotes that you want to use.
e.g. WHERE Failo_vardas=\"$pavadinimas\"
You have to leave the single quoting or your variable won't be evaluated.
So insert a single quote after the double quote, put your variable to evaluate, and re-insert a quote after your variable. Where the single-quoting ends, your env. variable will be evaluated instead of being treated literally.
Demo:
$ pavadinimas=name.mp4
$ echo 'UPDATE boom SET count = count + 1 WHERE Failo_vardas="'$pavadinimas'"';
result:
UPDATE boom SET count = count + 1 WHERE Failo_vardas="name.mp4"

How to fetch more than one column value from oracle select query to shell variable

I am trying to fetch a row with more than one column value to different shell variables. Infact I found that at a time all the column values can be stored to single shell variable. But how can I put those column values to seperate shell variables. Below is an example I am trying for time being
function sqlQuery {
sqlplus -S shiyas/********* <<'EOF'
set heading OFF termout ON trimout ON feedback OFF
set pagesize 0
SELECT name,open_mode from v$database;
EOF
}
OUTPUT="$( sqlQuery )"
echo $OUTPUT
Here I am getting the output as
ORCL READ WRITE
But my requirement is column values ORCL, READ WRITE should get assigned to different shell variable.
I tried the below of parsing.
echo "$OUTPUT" | while read name open_mode
but it was throwing unexpected end of file error.
-bash-3.2$ sh call_sql_col_val_1.sh
ORCL READ WRITE
call_sql_col_val_1.sh: line 18: syntax error: unexpected end of file
Please let me know what concept I can use to fetch a single row column values to different shell variables.
I do this via eval myself:
oracle#******:/*****> cat test.sh
#!/bin/bash
function sqlQuery {
sqlplus -S / as sysdba <<'EOF'
set heading OFF termout ON trimout ON feedback OFF
set pagesize 0
SELECT name,open_mode from v$database;
EOF
}
eval x=(`sqlQuery`)
NAME=${x[0]}
OPEN_MODE="${x[1]} ${x[2]}"
echo NAME IS $NAME
echo OPEN_MODE IS $OPEN_MODE
So we are running the same function you have above, passing it into x and running it through eval to handle the delimitation. Then you have an array and call call is as such: x[0] for the first item, for example.
Output is:
oracle#******:/******> sh test.sh
NAME IS ******
OPEN_MODE IS READ WRITE

pass a variable into a string ksh

how do you pass a global variable into a string inside a function?
I have the following code that works for the most part:
td_query () { bteq << EOF |grep '^>' |sed -e "s/^>/;/g"
$(cat $HOME/.tdlogon)
DATABASE $schemaName;
.set width 10000;
.set titledashes off;
$1
.LOGOFF;
.QUIT;
.EXIT
EOF
}
rqstID="1357"
echo $(td_query "select '>'||'UPDATE schema.SEGN_$rqstID_PRCSS_TBL SET POPN_LVL_EXCLN ='||a.CODE_ID||' WHERE ' || b.SQL_FILE_NM ||' AND POPN_LVL_EXCLN IS NULL'
FROM SE_POPN_EXCLSN a
INNER JOIN SE_CODE_LIB b
ON
a.CODE_ID = b.CODE_ID;")
but the results come back:
UPDATE schema.SEGN_ SET POPN_LVL_EXCLN = 1002 WHERE MR_IND = 'Y'
missing this:
$rqstID_PRCSS_TBL
it should be:
UPDATE schema.SEGN_1357_PRCSS_TBL SET POPN_LVL_EXCLN = 1002 WHERE MR_IND = 'Y'
_ is a legal character in a shell variable. The shell is trying to find a variable by the name of $rqstID_PRCSS_TBL and getting an empty string. (That's why _PRCSS_TBL is disappearing from your output.)
You need to tell the shell where the variable name ends: schema.SEGN_${rqstID}_PRCSS_TBL

Resources