bash: variable not being expanded as expected [duplicate] - bash

This question already has answers here:
Bash syntax error: unexpected end of file
(21 answers)
Closed 8 years ago.
If I set a variable in a shell script and then try to use it to create another variable, it doesn't seem to get substituted correctly. Example:
#!/bin/bash
X=/software/xxx
echo variable X = $X
echo path using variable: $X/yyy
echo path without variable: /software/xxx/yyy
This outputs:
variable X = /software/xxx
/yyy using variable: /software/xxx
path without variable: /software/xxx/yyy
I had expected the second output line to be:
path using variable: /software/xxx/yyy
I have tried various combinations of quotes and using ${X}, but all to no avail.
I'm new to shell scripting (coming from a Windows background), so I'm sure there is something really simple that I'm missing here.
In case anyone wonders why I want to do this, the background to this is that I need to write a shell script that takes a relative pathname parameter, determines its absolute pathname, then sets CLASSPATH with a number of jar files in that directory before invoking a Java program:
#!/bin/bash
DIR=`readlink -fn $1`
export CLASSPATH=$DIR/x.jar:$DIR/y.jar
java progname

You have carriage return (CR) character at the end of your X= variable declaration:
#!/bin/bash
X=/software/xxx^M
echo variable X = $X
echo path using variable: $X/yyy
(where ^M represents ONE special character - CR). I assume your editor doesn't show it. Try to open your script with vim. Windows and Linux marks newline in a different way (check wiki) . I suppose you're using some Windows editor.
Please read Bash Pitfalls webpage. I'm sure you can learn a lot from there.
btw. one way to enter ^M at vim: go to insert-mode i, than press: CTRL+k, M, ENTER

Related

Sourcing a .sh file under zsh : addvar:1: bad substitution error message

I have the following .sh file that I would like to be able to source under zsh, which is my default shell. The beginning of the file is (after there are only export variable = path) :
function addvar () {
local tmp="${!1}" ;
tmp="${tmp//:${2}:/:}" ; tmp="${tmp/#${2}:/}" ; tmp="${tmp/%:${2}/}" ;
export $1="${2}:${tmp}" ;
}
At the execution : $ source file.sh
I get the following error message :
addvar:1: bad substitution
Could anyone see what's wrong ?
ps : I tried to put directly at the top : #!/bin/bash and execute directly by $ ./file.sh
but it doesn't do anything (none variables exported).
I have the following .sh file that I would like to be able to source under zsh, which is my default shell.
That filename extension suggests that the file is intended for a Bourne-family shell, but it says nothing about which one, and various members of the family have various incompatibilities with each other. If there is a shebang line (a line beginning with #! and appearing as the first line of the file) then it may give a more specific indication of the shell for which the file is intended, but that has functional relevance only when the file is executed directly, not when it is sourced.
I get the following error message :
addvar:1: bad substitution
Could anyone see what's wrong ?
The problem is with
local tmp="${!1}" ;
, and specifically with ${!1}. In Bash, this is an indirect variable reference, which expands to the value of the variable named by the expansion of ${1}. In Zsh, however, it is simply invalid, so you cannot use that code as-is in that shell.
It looks like the function is supposed to add the value specified as its second argument to the path-like value of the environment variable named by its first argument, removing any previous appearances of that value. Since you cannot use it as-is in Zsh, I would suggest just not. You might instead use a function that computes the appropriate updated value, and leaves the reassignment to the caller. Example:
add_path_element() {
local tmp="${1//:${2}:/:}"
tmp="${tmp/#${2}:/}"
tmp="${tmp/%:${2}/}"
echo -n "${tmp}:${2}"
}
# Instead of "addvar PATH /dir/to/add":
export PATH=$(add_path_element "$PATH" /dir/to/add)
It should also be possible to implement a version of the original addvar function that works in Zsh (and Bash) by use of the eval built-in, but I cannot recommend that approach to you because eval is very dangerous. I mention it here just in case someone else suggests it. As a basic rule, do not use eval until you are sufficiently expert at shell programming to thoroughly understand why you should not use eval.

How Can I Execute Environment Variables in Shell Script? [duplicate]

This question already has answers here:
How to get a variable value if variable name is stored as string?
(10 answers)
Closed 2 years ago.
I have 2 files.
One is list file named envlist.
Another one is shell script file named test.
In envlist(list file), there's the environment variable list as below ;
setup_top
CFG
those are already declared as the environment variable.
(So when I type cd $setup_top or cd $CFG in command, it works well)
And in test(shell script), there's the code as below ;
#!/bin/bash
dir=$(<$env/envlist) # $env is another environment variable I declared.
for i in ${dir[*]}
do
cd $i # I think this line is a matter.
echo "------------------"
sleep 2
done
When I executed this shell script, I got the error as below;
./test: line 6: cd: setup_top: No such file or directory
----------------------------
./test: line 6: cd: CFG: No such file or directory
----------------------------
reading envlist file line by line seems to work well, but cd command seems not to work.
How can I fix the shell script code to work fine?
Actually, you need to transform $i into the name of the variable, then read $varname. If the shell would support this, you should write cd $$i. Unfortunately, this will not work, because $$ gives the current PID.
As suggested by #Biffen, you should use shell variable substitution:
cd ${!i}
Previous answer, using dangerous eval instruction:
eval cd \$$i
Note: eval is a dangerous instruction. Use it only if you are sure of the content of your files (not files provided by untrusted users).

source a file containing environment variables including "dash" character in bash?

I'm using bash and have a file called x.config that contains the following:
MY_VAR=Something1
ANOTHER=Something2
To load these as environment variables I just use source:
$ source x.config
But this doesn't work if MY_VAR is called MY-VAR:
MY-VAR=Something1
ANOTHER=Something2
If I do the same thing I get:
x.config:1: command not found: MY-VAR=Something1
I've tried escaping - and a lot of other things but I'm stuck. Does anyone know a workaround for this?
A pure bash workaround that might work for you is to re-run the script using env to set the environment. Add this to the beginning of your script.
if [[ ! -v myscript_env_set ]]; then
export myscript_env_set=1
readarray -t newenv < x.config
exec env "${newenv[#]}" "$0" "$#"
fi
# rest of the script here
This assumes that x.config doesn't contain anything except variable assignments. If myscript_env_set is not in the current environment, put it there so that the next invocation skips this block. Then read the assignments into an array to pass to env. Using exec replaces the current process with another invocation of the script, but with the desired variables in the environment.
A dash (-) in an environment variable is not portable, and as you noticed, will cause a lot of problems. You can't set these from bash. Fix the application you want to invoke.
That being said, if you can't change the target app, you can do this from python:
#!/usr/bin/python
import os
with open('x.config') as f:
for line in f:
name, value = line.strip().split('=')
os.environ[name] = value
os.system('/path/to/your/app')
This is a very simplistic config reader, and for a more complex syntax you might want to use ConfigParser.

Unix Script: Appending two variables from a sourced file not working

I can't understand this...
I have .sh file with variables (varsource.sh)
var1=AppleOrange
var2=Mango
Now I am sourcing my varsource.sh in my test.sh script
#!/bin/ksh
. ./varsource.sh
appended=$var1$var2
echo $appended
varloc1=aPPLEoRANGE
varloc2=mANGO
locappended=$varloc1$varloc2
echo $locappended
The output of above script is
MangoOrange
aPPLEoRANGEmANGO
I expected similar behavior when I use variables from sourced file and variables local to my script.
In case of variables from sourced file, the second variable is replacing characters of the first variable instead of appending.
More observations:
. ./varsource.sh
appended=${var1}xx
echo $appended
Output: xxpleOrange
But appending to left end of the variable is working
. ./varsource.sh
appended=xx$var1
echo $appended
Output:xxAppleOrange
Could some one help me understand this behaviour? What should I do to perform the appending in case of sourced variables?
You're on a Windows machine, or the sourced file was created on a Windows machine.
Your line endings are CRLF, carriage return and line feed, DOS/Windows style. The shell treats the carriage return as a regular character, not as part of the 'end of line'.
Remove the carriage returns and all will go back to normal.

When to use brackets when exporting environment variables in bash?

I've been trying to figure out what is the purpose of brackets in the bash environment variables. For example, in the below actual example of code, why are some of the definitions using a {} around the PATH, for example, export ...=.../${PATH}. Note also that some of the definitions are different: some use {$ECLIPSE_DIR} with the $ within the brackets; some use ${PATH} with the $ outside of the brackets, and some omit brackets altogether. This code generally works, although sometimes errors like the one shown at the bottom are shown (they appear to be transient), and I'm not sure why such errors only show up sometimes and not others.
What are the common practices concerning ways to include bash environment variables, when should brackets be used, and what is the difference between putting the $ inside and outside of brackets? Also, why do some lines have an "export" before the variable name, and some do not? What is the difference here?
# ECLIPSE
ECLIPSE_DIR=$HOME/eclipse
PATH=${PATH}:{$ECLIPSE_DIR}
# ANT
ANT_HOME=/usr/bin/ant
PATH=${ANT_HOME}/bin:${PATH}
export ANT_HOME PATH
# GRADLE
export GRADLE_HOME=/usr/local/gradle
export PATH=$GRADLE_HOME/bin:$PATH</code>
-bash: export: `/usr/bin/ant/bin:/usr/local/bin:{/Users/me/eclipse}:/usr/bin/scala-2.9.0.1/bin:/usr/local/mysql/bin:/usr/local/bin:{/Users/me/eclipse}': not a valid identifier
The braces are usually used for clarity, but a practical use is breaking up text from variable names. Say I had the following:
$ word="ello"
$ echo "h$word"
hello
$ echo "y$wordw" # bash tries to find the var wordw, and replaces with a blank
y
$ echo "y${word}w"
yellow
Variable names are automatically separated by most punctuation (notably . or /).
echo "$word/$word.$word"
ello/ello.ello
Looking at that error you presented, {$ECLIPSE_DIR} gets the variable expanded and then surrounded with literal open and close braces. I think the solution should be changing it to ${ECLIPSE_DIR}
In response to the export question, export is used to make a variable accessible to the shell that called this script. Any variable set up in a script does not exist once the script is finished unless it is exported. Hence, if you want your PATH to change after running that script, export PATH will have to be called before the script is over.
Braces are used with bash variables to disambiguate between variables. For example, consider this:
VAR=this
echo $VAR_and_that
echo ${VAR}_and_that
The first echo prints nothing, since bash thinks you are trying to echo out the var this_and_that which of course doesn't exist. The second echo doesn't have this problem and outputs this_and_that, since bash knows to expand out the VAR variable due to the braces.

Resources