We have a script we use to promote databases from dev to QA. Currently the script has a select statement we use to print out all the available databases and then takes your selection and does the various bits to promote the db.
I want to add a parameter to bypass that select statement for scripting purposes.
Here's how the script works currently:
# GET LIST OF DATABASES
DATABASES=`echo "show databases;"|/usr/bin/mysql -u root -h $DEVHOST|grep -v "information_schema"|grep -v "Database"|grep -v "performance_schema"|grep -v "mysql"`
eval set $DATABASES
select DEVDB in "$#"
do
if [[ "$DEVDB" =~ "dev1" ]]; then
QADB=`echo $DEVDB|sed -e s/_dev1_/_qa1_/`
fi
# Does various bits after this
Here's what I'm trying to do:
arg1=$1
if [ ! -z "$arg1" ]; then
DEVDB=$arg1
else
# GET LIST OF DATABASES
DATABASES=`echo "show databases;"|/usr/bin/mysql -u root -h $DEVHOST|grep -v "information_schema"|grep -v "Database"|grep -v "performance_schema"|grep -v "mysql"`
eval set $DATABASES
select DEVDB in "$#"
do
fi
if [[ "$DEVDB" =~ "dev1" ]]; then
QADB=`echo $DEVDB|sed -e s/_dev1_/_qa1_/`
fi
I'm getting an error at fi, I assume it's related to the select... do. How do I wrap these up in my if statements?
You need to do something in the body of the select. In this case it's sufficient to check that the variable has a value:
PS3="Select a database: "
select DEVDB; do
[[ $DEVDB ]] && break
done
echo "you selected $DEVDB"
Definitely don't need eval here -- it's always a code smell.
set -- $(
/usr/bin/mysql -u root -h $DEVHOST <<< "show databases;" |
grep -v -e information_schema -e Database -e performance_schema -e mysql
)
Related
I have a small script for Mac where I'm adding printers. It works fine but I think I could make it simpler or at least it would be interesting to know a different solution.
while IFS= read -r line;
do
if [[ $line == *"Printer_E1"* ]]
then
if [[ "$FIND_PRINTERS" =~ "$PRINTER_E1_IP" ]];
then
echo "found printer e1"
else
echo "adding printer e1"
"$LPADMIN" -p "$PRINTER_E1_IP" -v "lpd://$PRINTER_E1_IP" -L "$PRINTER_E1_LOCATION" -P "$PRINTER_E1_PPD" -E -o printer-is-shared=false -D "$PRINTER_E1_NAME"
echo "adding printer e1 done"
fi
fi
done <<< "$AD_GROUPS"
The content of $AD_GROUPS is:
Printer_E0
Printer_E1
Printer_E2
Printer_E3
Printer_E4
Printer_Strasse
Printer_Wien
I have such a loop for 5 printers, so 5 times that just with different variables.
How could I do that with one loop? (or how can I make that different or simpler)?
Something like this:
while IFS= read -r printer; do
[[ "$FIND_PRINTERS" =~ "${printer}_IP" ]] && \
echo "Found ${printer}" && continue
echo "Adding ${printer}..."
"$LPADMIN" -p "${printer}_IP" \
-v "lpd://${printer}_IP" \
-L "${printer}_LOCATION" \
-P "${printer}_PPD" -E -o printer-is-shared=false \
-D "${printer}_NAME" \
&& echo "Done"
done <<< "$AD_GROUPS"
I assume your variable FIND_PRINTERS has some printers you want to skip, that you have already set the parameters (IP, LOCATION etc) related to each printer.
We use the variable inside double quotes into there, so it expands to what you want for the various commands. Also I have simplified the if condition then command to condition && command and also continue moves to next iteration.
I am a beginner and trying to write a script that takes a config file (example below) and sets the rights for the users, if that user or group doesn´t exist, they get added.
For every line in the file, I am cutting out the user or the group and check if they exist.
Right now I only check for users.
#!/bin/bash
function SetRights()
{
if [[ $# -eq 1 && -f $1 ]]
then
for line in $1
do
var1=$(cut -d: -f2 $line)
var2=$(cat /etc/passwd | grep $var1 | wc -l)
if [[ $var2 -eq 0 ]]
then
sudo useradd $var1
else
setfacl -m $line
fi
done
else
echo Enter the correct path of the configuration file.
fi
}
SetRights $1
The config file looks like this:
u:TestUser:- /home/temp
g:TestGroup:rw /home/temp/testFolder
u:TestUser2:r /home/temp/1234.txt
The output:
grep: TestGroup: No such file or directory
grep: TestUser: No such file or directory
"The useradd help menu"
If you could give me a hint what I should look for in my research, I would be very grateful.
Is it possible to reset var1 and var2? Using unset didn´t work for me and I couldn´t find variables could only be set once.
It's not clear how you are looping over the contents of the file -- if $1 contains the file name, you should not be seeing the errors you report.
But anyway, here is a refactored version which hopefully avoids your problems.
# Avoid Bash-only syntax for function definition
SetRights() {
# Indent function body
# Properly quote "$1"
if [[ $# -eq 1 && -f "$1" ]]
then
# Read lines in file
while read -r acl file
do
# Parse out user
user=${acl#*:}
user=${user%:*}
# Avoid useless use of cat
# Anchor regex correctly
if ! grep -q "^$user:" /etc/passwd
then
# Quote user
sudo useradd "$user"
else
setfacl -m "$acl" "$file"
fi
done <"$1"
else
# Error message to stderr
echo Enter the correct path of the configuration file. >&2
# Signal failure to the caller
return 1
fi
}
# Properly quote argument
SetRights "$1"
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
During the configuration of Symfony 2 project it is required to set appropriate privilages to the cache and log directories.
Documentation says to do it in two ways. One of them is calling setfacl command with -m modificator. However not every version contains this modificator. Is it possible to check if this command or any other command allows to set some modificator ?
For example with following pseudocode:
if [ checkmods --command=setfacl --modificator=-m ]
setfacl -m ....
else
chmod ...
You can parse the usage information by running setfacl --help and check if contains the modificator. For example:
if setfacl --help | grep -q -- -m,
then
echo "setfacl -m supported"
else
echo "setfacl -m not supported"
fi
If you want to do it for any command which has the --help option, take a look at the _parse_help function available in your bash-completion file.
http://anonscm.debian.org/gitweb/?p=bash-completion/bash-completion.git;a=blob;f=bash_completion
# Parse GNU style help output of the given command.
# #param $1 command; if "-", read from stdin and ignore rest of args
# #param $2 command options (default: --help)
#
_parse_help()
{
eval local cmd=$( quote "$1" )
local line
{ case $cmd in
-) cat ;;
*) LC_ALL=C "$( dequote "$cmd" )" ${2:---help} 2>&1 ;;
esac } \
| while read -r line; do
[[ $line == *([ $'\t'])-* ]] || continue
# transform "-f FOO, --foo=FOO" to "-f , --foo=FOO" etc
while [[ $line =~ \
((^|[^-])-[A-Za-z0-9?][[:space:]]+)\[?[A-Z0-9]+\]? ]]; do
line=${line/"${BASH_REMATCH[0]}"/"${BASH_REMATCH[1]}"}
done
__parse_options "${line// or /, }"
done
}
I have been busy this week trying to wrap my head around a little Bash program to migrate a CMS from one server to another. The reasopn for this is because I have more tha 40 of these to do, and need to get it done in a timely manner, thus the Bash idea.
Needless to say, I have run into a couple of problems so far, but one of them has halted my development completetly, directory checking.
No I have tried a couple of methods and none of them seem to work really. The catch is that I have to check the folder on a remote server via ssh. Here my example:
ExSshRsa=~/.ssh/id_rsa
ExSshPort=22
ExSshHost=localhost
ExRoot=/var/www/
echo -n "Verifying Root access $ExRoot..."
SSHRoot='ssh -i $ExSshRsa -p $ExSshPort $ExSshHost [ -d $ExRoot ] || exit 1 '
echo $SSHRoot
if [ "$SSHRoot" -eq 0 ]
then
echo "OK"
else
echo "FAIL"
fi
I get the Error: [: : integer expression expected
Does the [ or test not resturn a 0 which is numerical. ?
Passing strings as arguments to a remote host is not trivial; you need to use arrays. A test example:
declare -a cmd=(touch "file name with spaces")
printf -v escaped_cmd_str '%q ' "${cmd[#]}"
ssh localhost $escaped_cmd
ssh localhost ls # Should return "file name with spaces" on a separate line
So your case should be:
ExSshRsa=~/.ssh/id_rsa
ExSshPort=22
ExSshHost=localhost
ExRoot=/var/www/
echo -n "Verifying Root access $ExRoot..."
declare -a cmd=( '[' -d "$ExRoot" ']' ) # Need to quote "[" since it's a Bash-specific symbol
printf -v escaped_cmd_str '%q ' "${cmd[#]}"
if ssh -i "$ExSshRsa" -p "$ExSshPort" "$ExSshHost" $escaped_cmd
then
echo "OK"
else
echo "FAIL"
fi
This is a rare case where using unquoted variable expansion is perfectly fine.
change the shebang to #!/bin/bash -x and look at the output...
you are storing a string in variable SSHRoot using single quotes, meaning that no variables will be expanded, i.e. a $ is still a $. Use double quotes instead, i.e. "
to store the output from a command in bash, use
var=$(cmd)
the exist status of a command is stored in the variable $?. Do a check on that after the ssh-command
you are never executing the ssh-command in your code
Great link here for bash-programming
Try the following:
ExSshRsa=~/.ssh/id_rsa
ExSshPort=22
ExSshHost=localhost
ExRoot=/var/www/
echo -n "Verifying Root access $ExRoot..."
cmd="bash -c \"[ -d $ExRoot ] || exit 1\""
SSHRoot="ssh -i $ExSshRsa -p $ExSshPort $ExSshHost ${cmd}"
$SSHRoot
if [ $? -eq 0 ]
then
echo "OK"
else
echo "FAIL"
fi
The variables weren't being replaced in your SSHRoot variable as it's in single quotes. Also, you weren't passing an executable command, so that's why I use bash -c above. It will run the bash commands inside the quoted string.
$? stores the exit value of the last command, in this case the SSHRoot one.
#!/bin/bash
ExSshRsa=~/.ssh/id_rsa
ExSshPort=22
ExSshHost=localhost
ExBase='/tmp/'
ExRoot='one space/'
declare -a AExRoot
for argR in "${ExRoot[#]}"
do
ExRoot+=($(printf %q "$argR"))
done
clear
FRoot=( $ExBase${ExRoot[#]} )
echo -n "Verifying Root access $FRoot..."
SSHRootTest="bash -c \"[ -d $FRoot ] && echo 0 && exit 0 || echo 1 && exit 1\""
SSHRoot=$( ssh -i $ExSshRsa -p $ExSshPort $ExSshHost ${SSHRootTest})
if [ $? -eq 0 ]
then
echo -en "\e[1;32mOK\e[0;37;m..."
else
echo -en "\e[1;31mFAIL\e[0;37;m..."
fi
sleep 1
if [ -w $FRoot ]
then
echo -e "\e[1;32mwritable\e[0;37;m"
else
echo -e "\e[1;31mNOT writeable\e[0;37;m"
fi
echo -e "\e[0;m"
exit 0
So I have incorporated all of the suggestions so far and have one last problem, the FRoot is not getting populated by the complete array values. Other than that I think it now has the subjective approach as suggested #john-keyes, the proper expansion #frederik and the crazy space escapes #l0b0