bash configuration templating - bash

I am using a bash script to install and configuration an application. I am trying to use a template where I can fill in values from variables and then save it to its proper location. This works fine with just variables, but I am unable to use any conditionals. Are there any better ways of doing this?
Heres my example template:
#!/bin/bash
cat <<EOF
DEFAULTS: &DEFAULTS
adapter: $DB
host: $DB_HOST
username: $DB_USER
password: $DB_PASS
database: $DB_DATABASE
if [ ! $DB_RECONNECT = ""]; then
reconnect: $DB_RECONNECT
fi
if [ ! $DB_TIMEOUT = ""]; then
timeout: $DB_TIMEOUT
fi
EOF
And then I use source template.sh > /path/to/file to evaluate and save the file.

You don't have to enclose everything in the heredoc
cat <<EOF
...
database: $DB_DATABASE
EOF
if [ -z "$DB_RECONNECT" ]; then
echo "reconnect: $DB_RECONNECT"
fi
if [ -z "$DB_TIMEOUT" ]; then
echo "timeout: $DB_TIMEOUT"
fi

You can use the command tpage like in this simple example :
$ cat /tmp/l.tpl
DEFAULTS: [%def%]
adapter[%db%]
$ tpage --define def=foo --define db=bar --interpolate /tmp/l.tpl
DEFAULTS: foo
adapterbar
tpage is a command coming with the well known Perl module Template::Toolkit, but no need to know Perl to use it. You can do some conditional as well, see conditional
Project : http://www.template-toolkit.org/

Related

Iterating array in declared function of bash shell script

I've been working through creating a script to move some files from a local machine to a remote server. As part of that process I have a function that can either be called directly or wrapped with 'declare -fp' and sent along to an ssh command. The code I have so far looks like this:
export REMOTE_HOST=myserver
export TMP=eyerep-files
doTest()
{
echo "Test moving files from $TMP with arg $1"
declare -A files=(["abc"]="123" ["xyz"]="789")
echo "Files: ${!files[#]}"
for key in "${!files[#]}"
do
echo "$key => ${files[$key]}"
done
}
moveTest()
{
echo "attempting move with wrapped function"
ssh -t "$REMOTE_HOST" "$(declare -fp doTest|envsubst); doTest ${1#Q}"
}
moveTest $2
If I run the script with something like
./myscript.sh test dev
I get the output
attempting move with wrapped function
Test moving files from eyerep-files with arg dev
Files: abc xyz
bash: line 7: => ${files[]}: bad substitution
It seems like the string expansion for the for loop is not working correctly. Is this expected behaviour? If so, is there an alternative way to loop through an array that would avoid this issue?
If you're confident that your remote account's default shell is bash, this might look like:
moveTest() {
ssh -t "$REMOTE_HOST" "$(declare -f doTest; declare -p $(compgen -e)); doTest ${1#Q}"
}
If you aren't, it might instead be:
moveTest() {
ssh -t "$REMOTE_HOST" 'exec bash -s' <<EOF
set -- ${##Q}
$(declare -f doTest; declare -p $(compgen -e))
doTest \"\$#\"
EOF
}
I managed to find an answer here: https://unix.stackexchange.com/questions/294378/replacing-only-specific-variables-with-envsubst/294400
Since I'm exporting the global variables, I can get a list of them using compgen and use that list with envsubst to specify which variables I want to replace. My finished function ended up looking like:
moveTest()
{
echo "attempting move with wrapped function"
ssh -t "$REMOTE_HOST" "$(declare -fp doTest|envsubst "$(compgen -e | awk '$0="${"$0"}"') '${1}'"); doTest ${1#Q}"
}

transfer variables from a main script to a different shell started from the first script

Ok so I'm sorry if this is a no-brainer, if it is unclear, or if it is impossible but here is my code, I am trying to get the /usr/bin/expect line of code to inherit/get variables from the main script. Its not working because it was started with a different shell (I think) and so it's not loading the variables in. This is my first post so if I am doing anything wrong please kindly correct me ;)
Thanks in advance,
--A\\/
#!/bin/bash
red="\x1b[0;31m"
nc="\x1b[0m"
####### commented out till scipt is finished
# if [ $EUID -ne 0 ]; then
# echo -e "${red}[!]${nc} | script must be run as root"
# exit
# fi
read -p '[?] | ip address of device: ' ip
read -p '[?] | nickname to set for this config: ' name
read -p '[?] | username to generate keys for: ' usr
read -p '[?] | password for that user: ' pw
export $usr
export $pw
export $ip
export $name
/usr/bin/expect -c 'spawn ssh $usr#$ip; expect"(yes/no)? "; send "yes\r"; expect "Password:"; send "$pw"; interact'
You have to 1. export them correctly, and 2. use $env(foo) to refer to them:
#!/bin/bash
var="World"
export var # No $
expect -c 'spawn echo Hello $env(var); interact'

zsh shell problem specifically when I am trying to get output

read -p "Enter your name: " NAME
echo "Hello $NAME, nice to meet you".```
In terminal:
ks#USER Desktop % ./script.sh
./script.sh:read:18: -p: no coprocess
Hello , nice to meet you.
[picture of the problem ][1]
[1]: https://i.stack.imgur.com/ZpVri.png
In ZSH -p doesn't mean prompt as in Bash. See man zshbuiltins:
read [ -rszpqAclneE ] [ -t [ num ] ] [ -k [ num ] ] [ -d delim ]
(...)
-p Input is read from the coprocess.
To get a prompt with ZSH implementation of read:
$ read "?Enter your name: " NAME
Enter your name: myname
$ echo $NAME
myname

sqlcmd in bash file - store to variable

Running in a docker container, I am trying to determine if a table exits in the mssql database:
RESULT='/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P $SA_PASSWORD -d master -i "SELECT name FROM master.sys.databases WHERE name = N'MyTable'"'
if [ "$RESULT" == "MyTable" ]; then
echo YES
fi
echo "$RESULT"
echo "$RESULT" always just outputs the entire command as a string, its not getting executed. So its just assigning it as a sting...
How can I execute it and assign the result?
Bash does not execute commands defined in single quotes. Single quotes are used for string definitions.
What you try to do is called command substitution. And it can be done in two different ways:
RESULT=`command`
RESULT=$(command)
So your example should look like this:
RESULT=`/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P $SA_PASSWORD -d master -i "SELECT name FROM master.sys.databases WHERE name = 'MyTable'`
if [ "$RESULT" == "MyTable" ]; then
echo YES
fi
echo "$RESULT"
You can find more information regarding command substitution here:
https://www.gnu.org/software/bash/manual/html_node/Command-Substitution.html

how to properly create a case statement to map an alias to a value

I'm trying to figure out create this case statement. What I am trying to do is map my input parameter $1 which has to be one of the 3 options and then map to the hostname. My command is failing. How do I assign my variable to value? What is the best way to do this?
Execute:
./test.sh cluster1
Example:
#!/bin/bash
ENDPOINT="$1"
SCH="$2"
case $ENDPOINT in
"cluster1") $HOST="myhost1.abcde.us-west-1.amazonaws.com";;
"cluster2") $HOST="myhost2.abcde.us-west-1.amazonaws.com";;
"cluster3") $HOST="myhost3.abcde.us-west-1.amazonaws.com";;
esac
psql $HOST -U myuser -d $SCH -p 5439 << EOF
Getting the error:
/test.sh: line 18: =myhost1.abcde.us-west-1.amazonaws.com: command not found
It would work if you remove the $ before HOST variable while making an assignment.
#!/bin/bash
ENDPOINT="$1"
SCH="$2"
case $ENDPOINT in
"cluster1") HOST="myhost1.abcde.us-west-1.amazonaws.com";;
"cluster2") HOST="myhost2.abcde.us-west-1.amazonaws.com";;
"cluster3") HOST="myhost3.abcde.us-west-1.amazonaws.com";;
esac
psql "$HOST" -U myuser -d "$SCH" -p 5439 << EOF
Also try using getopts for better scalability.
You should change your case statement like this:
HOST=$(case $ENDPOINT in
"cluster1") echo "myhost1.abcde.us-west-1.amazonaws.com";;
"cluster2") echo "myhost2.abcde.us-west-1.amazonaws.com";;
"cluster3") echo "myhost3.abcde.us-west-1.amazonaws.com";;
esac)
Can't test right now, let me know if it works.

Resources