I would like to pass a multi-line command into a Puppet (4.10.12) exec resource. The following fails with "syntax error at 'sudo'":
exec { 'create databases':
command => $("EOT")
sudo -u postgres psql -c
"CREATE DATABASE db1 ENCODING 'utf8' LC_COLLATE 'en_US.UTF-8' LC_CTYPE 'en_US.UTF-8';
CREATE DATABASE db2 ENCODING 'utf8' LC_COLLATE 'en_US.UTF-8' LC_CTYPE 'en_US.UTF-8';
CREATE DATABASE db3 ENCODING 'utf8' LC_COLLATE 'en_US.UTF-8' LC_CTYPE 'en_US.UTF-8'"
|-EOT,
}
I assume what is challenging about this case is that the two double-quotes appear on different lines. So what is the right heredoc syntax for a case like this?
I believe you need to add the L switch to your heredoc, and add a \ to the end of each line to escape the new line.
$command = $("EOT"/L)
sudo -u postgres psql -c\
"CREATE DATABASE db1 ENCODING 'utf8' LC_COLLATE 'en_US.UTF-8' LC_CTYPE 'en_US.UTF-8';\
CREATE DATABASE db2 ENCODING 'utf8' LC_COLLATE 'en_US.UTF-8' LC_CTYPE 'en_US.UTF-8';\
CREATE DATABASE db3 ENCODING 'utf8' LC_COLLATE 'en_US.UTF-8' LC_CTYPE 'en_US.UTF-8'"
|-EOT
exec { 'create databases':
command => $command,
}
You can view documentation here under "suppressing literal line breaks".
The following now works:
exec { 'create databases':
command => #("EOT"/L)
sudo -u postgres psql \
-c "CREATE DATABASE db1 ENCODING 'utf8' LC_COLLATE 'en_US.UTF-8' LC_CTYPE 'en_US.UTF-8'" \
-c "CREATE DATABASE db2 ENCODING 'utf8' LC_COLLATE 'en_US.UTF-8' LC_CTYPE 'en_US.UTF-8'" \
-c "CREATE DATABASE db3 ENCODING 'utf8' LC_COLLATE 'en_US.UTF-8' LC_CTYPE 'en_US.UTF-8'"
|-EOT
}
The following changes were necessary:
use `#' instead of '$' to refer to heredoc (typo)
use three -c options instead of one (in order to avoid error CREATE DATABASE cannot be executed from a function or multi-command string)
use heredoc switch L (as suggested by #mardotio)
I'll accept the other answer since it contains an important element (and is by a new contributor :-)
Related
This question already has answers here:
When to wrap quotes around a shell variable?
(5 answers)
Closed 1 year ago.
I am trying to set this environment variable with semicolons on ubuntu :
BS_DATABASE_CONNECTION=connection;Data Source=source;Initial Catalog=catalog;Persist Security Info=info;User ID=userid;Password=password;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;
But i get these errors:
Data: command not found
Initial: command not found
Persist: command not found
User: command not found
How do i set this correctly?
The problem is that ; is treated as a control operator, and the string BS_DATABASE_CONNECTION=connection;Data Source=source;... is interpreted as multiple commands. The first is the command BS_DATABASE_CONNECTION=connection, the second is the command Data Source=source, etc. One solution is to use quotes:
BS_DATABASE_CONNECTION='connection;Data Source=source;Initial Catalog=catalog;Persist Security Info=info;User ID=userid;Password=password;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;'
But with a value this long, it would probably be more readable to do something like:
BS_DATABASE_CONNECTION="\
connection;\
Data Source=source;\
Initial Catalog=catalog;\
Persist Security Info=info;\
User ID=userid;\
Password=password;\
MultipleActiveResultSets=False;\
Encrypt=True;\
TrustServerCertificate=False;\
"
or
BS_DATABASE_CONNECTION=''
for x in 'connection' \
'Data Source=source' \
'Initial Catalog=catalog' \
'Persist Security Info=info' \
'User ID=userid' \
'Password=password' \
'MultipleActiveResultSets=False' \
'Encrypt=True' \
'TrustServerCertificate=False' \
; do
BS_DATABASE_CONNECTION="${BS_DATABASE_CONNECTION}${x};"
done
or
read BS_DATABASE_CONNECTION << EOF
connection;\
Data Source=source;\
Initial Catalog=catalog;\
Persist Security Info=info;\
User ID=userid;\
Password=password;\
MultipleActiveResultSets=False;\
Encrypt=True;\
TrustServerCertificate=False;
EOF
or
BS_DATABASE_CONNECTION=$( tr \\n \; << EOF
connection
Data Source=source
Initial Catalog=catalog
Persist Security Info=info
User ID=userid
Password=password
MultipleActiveResultSets=False
Encrypt=True
TrustServerCertificate=False
EOF
)
Note that this is not an environment variable. It is merely a shell variable. If you want it to be in the environment of subshells, you should export it. Whether it is in the environment of the shell or not should be completely irrelevant, and there is no functional difference between an environment variable and an exported shell variable.
Case: I wanna insert some data from a file to specific position of the string.
Example:
cat users.log | mysql -h localhost -u mysql -e 'SELECT id FROM users WHERE ${USERS_IDS}'
I want to replace ${USERS_IDS} string to the data from the file
I'm sure this case is very popular, but I did not find a suitable solution
To insert the contents of a file in a specific position of a string you use the facilities of your shell.
For example, Bash has the $(< filename) construction:
mysql -h localhost -u mysql -e 'SELECT id FROM users WHERE '"$(< users.log)"
If the data to be inserted needs to be editted a little, you have the $(command) construction:
mysql -h localhost -u mysql -e 'SELECT id FROM users WHERE '"$(< users.log sed -e 's/.../.../')"
Whether the file substitution or the command substitution are to be enclosed in doublequotes or not depends on the specific use case.
And, if the intended use is really to feed values in a MySQL command, beware of Bobby Tables.
I am using below command to get result for my SQL query.
su - postgres -c 'psql -d dbname' with stdin "COPY ( my SQL query ) TO STDOUT WITH CSV HEADER"
This works fine on my server but on different machine it is printing bash warning with output of SQL query.
For example -
/etc/profile: line 46: HISTSIZE: readonly variable
/etc/profile: line 50: HISTCONTROL: readonly variable
/etc/profile.d/20-tmout.sh: line 1: TMOUT: readonly variable
/etc/profile.d/history.sh: line 6: hcmnt_tty: readonly variable
name
abc
Please let me know anyway so that I can skip above warning messages and only get data.
If I would like to use /dev/null in this case how to modify above command to get data only.
if what you mean is "how to discard only error output?", the way to go is to redirect the standard error stream to oblivion (/dev/null), like so:
your-command 2>/dev/null
that way, if the command outputs data to standard out, it passes through, but any output to the standard error socket is discarded, so you won't see these error messages.
by the way, 2 here is a shorthand file descriptor for the standard error.
Sorry this is untested, but I hit this same error, your db session isn't read/write. You can echo the statements to psql to force a proper session as follows. I'm unsure as to how stdin may be effected
echo 'SET TRANSACTION READ WRITE; SET SESSION CHARACTERISTICS AS TRANSACTION READ WRITE ; COPY ( my SQL query ) TO STDOUT WITH CSV HEADER' | su - postgres -c 'psql -d dbname' with stdin
caution - bash hack
su - postgres -c 'psql -d dbname' with stdin "COPY ( my SQL query ) TO STDOUT WITH CSV HEADER" | grep -v "readonly"
Can you please help me regarding
How to select below query in Oracle.
I am trying to spool a special character from SQL*plus. But it is showing like ????
select 'ยง' from dual;
Unless your database character set is defined to US7ASCII this should be no problem.
You local character set has to match setting of NLS_LANG.
Example:
$ locale charmap
UTF-8
$ echo $LANG
en_US.UTF-8
Then NLS_LANG environment variable should be set to
NLS_LANG={your_language}_{your_country}.AL32UTF8
Then SQL*Plus should work fine.
I am trying to automate a VI edit for a command similar to crontab editing via Shell script but not working for me so far.
Here is the final json with admin as true:
'{"name":"SQLSRVR","admin":"true","json_class":"Chef::ApiClient","chef_type":"client"}'
As you can see the EDITOR environment variable has to be set or passed as command line option -e
[root#vrhost user]# knife client edit SQLSRVR
ERROR: RuntimeError: Please set EDITOR environment variable
[root#vrhost user]# knife client edit
USAGE: knife client edit CLIENT (options)
-s, --server-url URL Chef Server URL
-k, --key KEY API Client Key
--[no-]color Use colored output, defaults to enabled
-c, --config CONFIG The configuration file to use
--defaults Accept default values for all questions
-d, --disable-editing Do not open EDITOR, just accept the data as is
-e, --editor EDITOR Set the editor to use for interactive commands
-E, --environment ENVIRONMENT Set the Chef environment
-F, --format FORMAT Which format to use for output
-u, --user USER API Client Username
--print-after Show the data after a destructive operation
-V, --verbose More verbose output. Use twice for max verbosity
-v, --version Show chef version
-y, --yes Say yes to all prompts for confirmation
-h, --help Show this message
FATAL: You must specify a client name
The below command opens a vim editor for editing to make the change from ["admin": "false"] to ["admin": "true"]:
[root#vrhost user]# knife client edit SQLSRVR -e vim
{
"name": "SQLSRVR",
"admin": false,
"json_class": "Chef::ApiClient",
"chef_type": "client",
}
I am trying to do this through a shell script and would like to automate it and tried many options but had no luck so far.
[root#vrhost ~]# (echo ^[:g/false/s/false/true/^[:wq!^M) | knife client edit SQLSRVR -e vim
Vim: Warning: Input is not from a terminal
Object unchanged, not saving
or
[root#vrhost user]# echo (^[echo '{"name":"SQLSRVR","admin":"true","json_class":"Chef::ApiClient","chef_type":"client"}'^[:w q!^M) | knife client edit SQLSRVR -e
[root#vrhost ~]# knife client show SQLSRVR
admin: false
chef_type: client
json_class: Chef::ApiClient
name: SQLSRVR
this is very similar to automating crontab editing via shell script but this has not been working for me.
Unless you really need special Vim capabilities, you're probably better off using non-interactive tools like sed, awk, or Perl / Python / Ruby / your favorite scripting language here.
That said, you can use Vim non-interactively, using silent batch mode.
vim -T dumb --noplugin -n -es -S "commands.ex" "filespec"
Instead of the external script to read the commands from via -S "commands.ex", you can also give a few commands directly via -c cmd1 -c cmd2. See :help -s-ex for more information.
Check out
$ knife client edit --help
[...]
-d, --disable-editing Do not open EDITOR, just accept the data as is
So I guess you can change the values without editing in vim. Just:
get the client data in json format.
replace needed values with sed.
upload the data from file.
Code:
$ knife client show -Fj SQLSRVR > SQLSRVR.json
$ sed -i.old "s/\"admin\": true,/\"admin\": false,/" SQLSRVR.json
$ knife client edit -d SQLSRVR < SQLSRVR.json
Something like that.
Here are some links to references:
i) http://mirror.hep.wisc.edu/stable/chef/chef-server-webui/app/controllers/clients_controller.rb
ii) http://www.rubydoc.info/github/opscode/chef/master/Shell/Extensions - tried but unable to get it to work
Finally did the following (it does give 409 the 2nd time on call and I did not need to do it a 2nd time):
# call to below rb, CLIENTNAME is the name of the client and STATE is true/false
$ knife exec clienttransform.rb CLIENTNAME STATE
$ cat clienttransform.rb
Chef::Config[:solo] = false
class Company
class TransformClient
attr_accessor :clientname
attr_accessor :isclientadmin
def initialize(client_name, is_client_admin)
#clientname = client_name
#isclientadmin = is_client_admin
end
def transform
client=Chef::ApiClient.load(#clientname)
# puts "client.name : " + client.name
# puts "client.admin : " + client.admin.to_s
# puts "XX - clientname : " + #clientname
# puts "XX - isclientadmin : " + #isclientadmin.to_s
boolisclientadmin = !!#isclientadmin
client.admin(boolisclientadmin)
client.save()
end
end
end
client_name = ARGV[2].to_s()
is_client_admin = ARGV[3].to_s()
# puts "YY - client_name : " + client_name
# puts "YY - is_client_admin : " + is_client_admin
trc = Company::TransformClient.new(client_name, is_client_admin)
trc.transform
exit 0
Just set your editor and it will work. In my case I use vim editor that's why my command was as follows:
export EDITOR=vim