Can't set environment variable with semicolon on linux [duplicate] - linux

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.

Related

Bashscript throws command error when populating variable [duplicate]

This question already has answers here:
How do I set a variable to the output of a command in Bash?
(15 answers)
Bash variable from command with pipes, quotes, etc
(2 answers)
Variable variable assignment error -"command not found"
(1 answer)
Closed 1 year ago.
i have the following two lines in a batch script
iperf_options=" -O 10 -V -i 10 --get-server-output -P " $streams
$iperf_options=$iperf_options $proto
and
$streams = 2
$proto = -u
but when i run this i get the following error.
./bandwidth: line 116: -O: command not found
I am simply trying to wrote a string and then append it to a variable so why does it throw the error on the -O?
I have looked about the web but i jsut seem to find stuff about spaces around the "="
any help greatfully recived.
Thankyou
code block to show error
proto=-u
streams=2
iperf_options=" -O 10 -V -i 10 --get-server-output -P " $streams
$iperf_options=$iperf_options $proto
running this will give this out put
./test
./test: line 3: 2: command not found
./test: line 4: =: command not found
There are two main mistakes here, in a variety of combinations.
Use $ to get the value of a variable, never when setting the variable (or changing its properties):
$var=value # Bad
var=value # Good
var=$othervar # Also good
Spaces are critical delimiters in shell syntax; adding (or removing) them can change the meaning of a command in unexpected ways:
var = value # Runs `var` as a command, passing "=" and "value" as arguments
var=val1 val2 # Runs `val2` as a command, with var=val1 set in its environment
var="val1 val2" # Sets `var1` to `val1 val2`
So, in this command:
iperf_options=" -O 10 -V -i 10 --get-server-output -P " $streams
The space between iperf_options="..." and $streams means that it'll expand $streams and try to run it as a command (with iperf_options set in its environment). You want something like:
iperf_options=" -O 10 -V -i 10 --get-server-output -P $streams"
Here, since $streams is part of the double-quoted string, it'll be expanded (variable expand inside double-quotes, but not in single-quoted), and its value included in the value assigned to iperf_options.
There's actually a third mistake (or at least dubious scripting practice): building lists of options as simple string variables. This works in simple cases, but fails when things get complex. If you're using a shell that supports arrays (e.g. bash, ksh, zsh, etc, but not dash), it's better to use those instead, and store each option/argument as a separate array element, and then expand the array with "${arrayname[#]}" to get all of the elements out intact (yes, all those quotes, braces, brackets, etc are actually needed).
proto="-u" # If this'll always have exactly one value, plain string is ok
streams=2 # Same here
iperf_options=(-O 10 -V -i 10 --get-server-output -P "$streams")
iperf_options=("${iperf_options[#]}" "$proto")
# ...
iperf "${iperf_options[#]}"
Finally, I recommend shellcheck.net to sanity-check your scripts for common mistakes. A warning, though: it won't catch all errors, since it doesn't know your intent. For instance, if it sees var=val1 val2 it'll assume you meant to run val2 as a command and won't flag it as a mistake.

Extra quotes in a variable read from dialog in bash

I need to configure user.email for git in bash script, and my problem is that I don't know how to get this line to run: git config --global user.email "user#example.com"
right now my code run this this command without double quotes - user#example.com
and I tried to escape " " in every way that I found and almost every time the code run '"user#example.com"'
a fragment of my code in bash:
function get_email(){
e_mail=/tmp/tmp.sh.$$
dialog --clear \
--title "EMAIL" \
--inputbox "Enter your email" 8 40 2>"${e_mail}"
email=$(<"${e_mail}")
git config --global user.email "$email"
}
Can someone help me solve this problem?
dialog can under some circumstances (man page goes into detail) put literal literal double quotes in its output (which can be replaced with literal single-quotes using --single-quoted).
To strip them back out, use parameter expansion -- as shown in the below:
get_email() {
local email
email=$(dialog --stdout --clear \
--title "EMAIL" \
--inputbox "Enter your email" 8 40
)
git config --global user.email "${email//'"'/}"
}
Some notes:
"${email//'"'/}" expands $email, replacing all instances of " with an empty string. This is the solution to your immediate problem. The syntax involved is parameter expansion, documented at http://wiki.bash-hackers.org/syntax/pe
Don't use the function keyword. It makes your code incompatible with POSIX shells for absolutely no benefit.
Declare your locals with local (this isn't POSIX-defined, but even ash and dash support it) to prevent leaking into the surrounding scope.
Use --stdout on dialog to allow capture of output with command substitution.

Passing multiple variables from local bash to remote bash script without gobbling

I'm having trouble sending multiple variables to a remote bash script without gobbling occurring.
For the sake of this question the variable $timestamp contains 12-12-15 19:45:21
ssh user#serverip "/usr/path/to/script.sh http://www.web.com/$1 http://web.com/$2 $timestamp";
I am sending 3 variables to script.sh
Two URLs with an amended file name in the form of a variable on the end and then my $timestamp variable
But on myscript.sh, when I try to insert $timestamp into a mysql database it only see's the first part of the date before the white space :
12-12-15
So my quotes around the command aren't preventing gobbling. Do I need to quote each variable separately?
ssh user#serverip "/usr/path/to/script.sh http://www.web.com/$1 http://web.com/$2 $timestamp";
This is equivalent to this locally calling
/usr/path/to/script.sh http://www.web.com/$1 http://web.com/$2 $timestamp
Try to quote each individual argument passed
ssh user#serverip "/usr/path/to/script.sh 'http://www.web.com/$1' 'http://web.com/$2' '$timestamp'";
You can also print each argument in the script to see what's being passed... e.g. echo $1, etc.
You can try something like
ssh localhost "printf \"%s %s %s\n\" a b \"last parameter\""
You need to escape the values for the remote host. The correct way of doing this is with printf %q:
ssh user#serverip "/usr/path/to/script.sh \
$(printf "%q " "http://www.web.com/$1" "http://web.com/$2" "$timestamp")"
This works for all variable values. Wrapping them in single quotes would instead result in syntax error and command injection when the variables themselves contain single quotes.

How to use right the dialog command in the sh script? [duplicate]

This question already has answers here:
Why does shell ignore quoting characters in arguments passed to it through variables? [duplicate]
(3 answers)
Closed 5 years ago.
I wrote some script:
#!/bin/sh
dialog --menu \
"Please select a partition from the following list to use for your \
root (/) Linux partition." 13 70 3 \
"/dev/hda2" "Linux native 30724312K" "/dev/hda4" "Linux native 506047K"
DISKS='"disk1" "50 Gb" "disk2" "100 Gb"'
dialog --menu \
"Please select a partition from the following list to use for your \
root (/) Linux partition." 13 70 3 \
$DISKS
The first call looks good.
The second call looks bad.
I need to transmit information about the drives through the variable. Please tell me why the second version of the call does not work as expected?
Let's ask shellcheck:
$ shellcheck myscript
In myscript line 9:
DISKS='"disk1" "50 Gb" "disk2" "100 Gb"'
^-- SC2089: Quotes/backslashes will be treated literally. Use an array.
In myscript line 14:
$DISKS
^-- SC2090: Quotes/backslashes in this variable will not be respected.
The detailed error page offers an explanation:
Bash does not interpret data as code. Consider almost any other languages, such as Python:
print 1+1 # prints 2
a="1+1"
print a # prints 1+1, not 2
Here, 1+1 is Python syntax for adding numbers. However, passing a literal string containing this expression does not cause Python to interpret it, see the + and produce the calculated result.
Similarly, "My File.txt" is Bash syntax for a single word with a space in it. However, passing a literal string containing this expression does not cause Bash to interpret it, see the quotes and produce the tokenized result.
The solution is to use an array instead, whenever possible.
Ok, let's try that:
#!/bin/bash
DISKS=("disk1" "50 Gb" "disk2" "100 Gb")
dialog --menu \
"Please select a partition from the following list to use for your \
root (/) Linux partition." 13 70 3 \
"${DISKS[#]}"
This works.
However, this is a bash specific solution. If you want it to work for sh, in this case, you can pick a delimiter other than whitespace by setting the Internal Field Separator:
#!/bin/sh
IFS=":" # Split on colons
set -f # Prevent globbing
DISKS='disk1:50 Gb:disk2:100 Gb'
dialog --menu \
"Please select a partition from the following list to use for your \
root (/) Linux partition." 13 70 3 \
$DISKS
This also works as expected. If your script is longer than this, you'd want to set IFS back to its original value.

Setting environment variable with leading digit in bash

I need to set an environment variable called "64bit" (i.e. with a leading digit) in bash. However, bash variable names disallow a variable with a leading digit. I know a way to set it when invoking bash:
env 64bit=1 /usr/bin/bash
However, I'm looking for a way to change it in the currently running shell i.e. not by starting a new shell. I also know that csh allows variables to start with a digit, but I need to use bash.
Is there any way to achieve this?
You can also bypass the bash interpreter and define the variable directly with the bash internal functions:
$ gdb --batch-silent -ex "attach $$" \
-ex 'set bind_variable("64bit", "1", 0)' \
-ex 'set *(int*)(find_variable("64bit")+sizeof(char*)*5) = 1' \
-ex 'set array_needs_making = 1'
$ env | grep 64
64bit=1
As people point out, Bash does not allow variables starting with digits. It does however pass on unrecognized environment string to external programs, which is why the variable shows up in env but not in set.
As a workaround, you can work with a valid name like _64bit and then automatically inject your invalid variable name into commands you run:
#!/bin/bash
# Setup for injection hack
original=$PATH
PATH="/"
command_not_found_handle() {
PATH="$original" env "64bit=$_64bit" "$#"
}
# Your script and logic
_64bit="some dynamic value"
# This verifies that '64bit' is automatically set
env | grep ^64bit
Note that this particular method only works if you invoke through $PATH, not if you use relative or absolute path names.
If you do invoke by pathname, consider modifying PATH and invoking by name instead.

Resources