Escaping single quotes in shell for postgresql - linux

I'm trying to execute SQK through psql under postgres account. I'm able run SQL
that doesn't contain quotes
root#server:/home/rosta/SCRIPTS# su postgres -c "psql -c 'SELECT NOW()'"
now
-------------------------------
2014-06-07 09:38:17.120368+02
(1 row)
The problem appears with an SQL query that contains quotes like SELECT 'hi'. I'm testing with simple 'hi', but I would like to execute something like this from a shell script.
su postgres -c "psql -c 'create database $DB_NAME template=template0 encoding='utf8' owner=aaa lc_collate='cs_CZ.utf8''"
Can anyone advise me how to escape quotes around encoding and collate in the command above
Some of my tests:
root#server:/home/rosta/SCRIPTS# su postgres -c "psql -c 'SELECT \'hi\''"
bash: -c: line 0: unexpected EOF while looking for matching `''
bash: -c: line 1: syntax error: unexpected end of file
root#server:/home/rosta/SCRIPTS# su postgres -c "psql -c 'SELECT \\'hi\\''"
bash: -c: line 0: unexpected EOF while looking for matching `''
bash: -c: line 1: syntax error: unexpected end of file
root#server:/home/rosta/SCRIPTS# su postgres -c 'psql -c \'SELECT \\'hi\\'\''

What I usually do is use double quotes (") for postgres -c's argument and escaped double quotes (\") for psql -c's argument. That way, I can use single quotes (') inside the SQL string with no problem:
[root#mycomputer ~]# su postgres -c "psql -c \"SELECT 'hi' \" "
?column?
----------
hi
(1 row)

Simplest way is to use a 'here document' , which ignores all quoting:
#!/bin/sh
DB_NAME=my_data_base
psql -U postgres postgres <<STOP_IT
create database $DB_NAME template=template0
encoding='utf8'
owner=aaa
lc_collate='cs_CZ.utf8'
;
STOP_IT

Related

SSH remote execution - How to declare a variable inside EOF block (Bash script)

I have the following code in a bash script:
remote_home=/home/folder
dump_file=$remote_home/my_database_`date +%F_%X`.sql
aws_pem=$HOME/my_key.pem
aws_host=user#host
local_folder=$HOME/db_bk
pwd_stg=xxxxxxxxxxxxxxxx
pwd_prod=xxxxxxxxxxxxxxx
ssh -i $aws_pem $aws_host << EOF
mysqldump --column-statistics=0 --result-file=$dump_file -u user -p$pwd_prod -h $db_to_bk my_database
mysql -u user -p$pwd_prod -h $db_to_bk -N -e 'SHOW TABLES from my_database' > $remote_home/test.txt
sh -c 'cat test.txt | while read i ; do mysql -u user -p$pwd_prod -h $db_to_bk -D my_database --tee=$remote_home/rows.txt -e "SELECT COUNT(*) as $i FROM $i" ; done'
EOF
My loop while is not working because "i" variable is becoming empty. May anyone give me a hand, please? I would like to understand how to handle data in such cases.
The local shell is "expanding" all of the $variable references in the here-document, but AIUI you want $i to be passed through to the remote shell and expanded there. To do this, escape (with a backslash) the $ characters you don't want the local shell to expand. I think it'll look like this:
ssh -i $aws_pem $aws_host << EOF
mysqldump --column-statistics=0 --result-file=$dump_file -u user -p$pwd_prod -h $db_to_bk my_database
mysql -u user -p$pwd_prod -h $db_to_bk -N -e 'SHOW TABLES from my_database' > $remote_home/test.txt
sh -c 'cat test.txt | while read i ; do mysql -u user -p$pwd_prod -h $db_to_bk -D my_database --tee=$remote_home/rows.txt -e "SELECT COUNT(*) as \$i FROM \$i" ; done'
EOF
You can test this by replacing the ssh -i $aws_pem $aws_host command with just cat, so it prints the here-document as it'll be passed to the ssh command (i.e. after the local shell has done its parsing and expansions, but before the remote shell has done its). You should see most of the variables replaced by their values (because those have to happen locally, where those variables are defined) but $i passed literally so the remote shell can expand it.
BTW, you should double-quote almost all of your variable references (e.g. ssh -i "$aws_pem" "$aws_host") to prevent weird parsing problems; shellcheck.net will point this out for the local commands (along with some other potential problems), but you should fix it for the remote commands as well (except $i, since that's already double-quoted as part of the SELECT command).

Ubuntu pass Password containing '"' to sudo

I am trying to pass the password that contains " character as part of my password in a bash script to sudo -S su. I am running the bash script but I get prompt as bash error: line1 EOF as end to " not found.
Suggest some method to pass the password containing quotes successfully.
echo "pass\"word" | sudo -S su
prompt:
bash error: line1 EOF as end to '"' not found
I want to run the bash script without errors
This error is not caused by the quote in your password, but by the fact that both sudo and the shell spawned by su are trying to read from stdin:
$ bash -c 'pass"word'
bash: -c: line 1: unexpected EOF while looking for matching `"'
bash: -c: line 2: syntax error: unexpected end of file
$ echo 'totallynotmypassword' | sudo -S su
bash: line 1: totallynotmypassword: command not found
As suggested by user KamilCuk, it is better to create a NOPASSWD entry in your sudoers file.

Sql in bash script (postgres)

i have a command in bash script for rename base.
It's work, example
psql -U $User -t -A -q -c 'ALTER DATABASE "Old_Name" RENAME TO "New_Name"'
But if i do this -
O_Name='Old_Name'
N_Name='New_Name'
psql -U $User -t -A -q -c 'ALTER DATABASE "$O_Name" RENAME TO "$N_Name"'
It's not work, i think sql get $O_Name not Old_Name.
How to pass the value of a variable bash to sql?
Single quotes don't allow for environment variable expansion. Use double quotes instead (and escape the nested quotes). Like,
psql -U $User -t -A -q -c "ALTER DATABASE \"$O_Name\" RENAME TO \"$N_Name\""

missing file operand cp after su

I run this command on ubuntu:
su - test -c cp /home/test/toto.txt /home/test/dir
But I have this error!
cp: missing file operand
anyone has an idea about the problem?
thank you
Option -c is understood by command su, taking the next argument (not the remaining) to be the command. That next command is just cp.
Try putting the command into quotes:
su - test -c 'cp /home/test/toto.txt /home/test/dir'
If this is problematic because you want to have quotes inside the command, try using escape instead of the inner quotes:
su - test -c 'echo hello\ \ there'

How to run a SQL script in tsql

I'm using tsql (installed with FreeTDS) and I'm wondering if there's a way to run a SQL script in tsql from the command line and get the result in a text file.
For example, in psql I can do:
psql -U username -C "COPY 'SELECT * FROM some_table' to 'out.csv' with csv header"
Or:
psql -U username -C "\i script.sql"
And in script.sql do:
\o out.csv
SELECT * FROM some_table;
Is there a way for doing this in tsql? I have read the linux man page and search everywhere but I just don't find a way.
I think, you can try "bsqldb", see http://linux.die.net/man/1/bsqldb
I really didn't find how to do this and I'm starting to thinks it just can't be done in tsql. However I solved for my specific problem redirecting the stdin and stdout. I use a bash script like this:
tsql connection parameters < tsql_input.sql > tsql_output.csv
lines=`cat tsql_output.csv | wc -l`
# The output includes the header info of tsql and the "(n number of rows)" message
# so I use a combination of head and tail to select the lines I need
headvar=$((lines-2))
tailvar=$((lines-8))
head -$headvar tsql_output.csv | tail -$tailvar tsql_output.csv > new_output_file.csv
And that saves just the query result on 'new_output_file.csv'
freebcp "select * from mytable where a=b" queryout sample.csv -U anoop -P mypassword -S hostname.com -D dbname -t , -c
This command woks like a charm. Kudos to FreeTDS...
tsql -U username -P password -p 1433 > out.csv <<EOS SELECT * FROM some_table; go EOS

Resources