Difference between ${my_variable} and $my_variable in a Jenkins project - bash

Is there a difference when using variables in a Jenkins project between this:
node index.js ${arg}
and this:
node index.js $arg
Where arg is a parameter for the project.
Update:
Interesting to note that it's not Jenkins-specific.
I think this question should remain as others may assume it's something to do with Jenkins.

In the context of your Jenkins project, it is not needed, except as a matter of style.
The braces are useful in those cases where the shell may not be able to determine the end of a variable name. For instance, if your variable is named this, then you would need the braces if your command was
echo "${this}isatest"
Also, you need them when you want to take advantage of Bash's Shell Parameter Expansions.

It's actually a standard shell syntax.
It's easier to manipulate variables / concatenate the contents of variables into other variable names. e.g.
${foo}bar
You can also perform additional string manipulation with the {}:
STRING="This is a string"
echo ${STRING// /_}
http://www.tldp.org/LDP/abs/html/string-manipulation.html
I also find variables with {} to read better but that's a personal preference.
Generic answer here: When do we need curly braces in variables using Bash?

Related

Using a variable to change directory

I would like to extract the current path in a variable and use it later on in the script
Something like:
mypath="$pwd"
Later on:
cd "$mypath"
But I am getting a different directory when doing ls
Almost:
mypath=$PWD
This one saves a fork over mypath=$(pwd). While some consider it good practice to always double quote variable assignments, technically it is not needed here, since the shell does not perform word-splitting for variable assignments.
PS: Note that you are assigning to mypath and then use myvar... you should be consistent in your variable naming, otherwise it won't work.

How to pass multiple variables in shell script

I have a shell script that I'm trying to write to a file using multiple variables, but one of them is being ignored.
#!/bin/bash
dir=/folder
name=bob
date=`date +%Y`
command > $dir/$name_$date.ext
The $name is being ignored. How can I fix this?
Have you noticed that the _ was "ignored" as well? That's a big hint.
If you use set -u, you'll see the following:
-bash: name_: unbound variable
The way bash parses it, the underscore is part of the variable name.
There are several ways to fix the problem.
The cleanest is the ${var} construct which separate the variable name from its surroundings.
You can also use quotation in various ways to force the right parsing, e.g.: "$dir/$name""_$date.ext"
And in case your variables might contain spaces (now, or in the future) use quotation for words.
command >"$dir/${name}_$date.ext"
command >"${dir}/${name}_${date}.ext"
Both these are fine, just pick one style and stick to it.

How can I trigger brace expansion inside a script?

I'm writing a script which needs to use the shell's brace expansion, but nothing I've tried works. For (a contrived) instance, say I have a variable containing the string
thing{01..02}
and I (obviously) want to expand it to
thing01 thing02
from inside the script, how can I do that?
(For anyone who assumes this is a duplicate of this other question, please read them more carefully. That question is regarding working from the shell, not a shell script, and doesn't require the ability to expand arbitrary expressions.)
$ echo thing{01,02}
thing01 thing02
Make sure that braceexpand is turned on with set -o braceexpand.

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.

Variables that work everywhere

How can I set variables that work everywhere? My .bashrc has:
Questions='/Users/User/Stackoverflow/Questions'
Address='My address'
My file has:
$Questions
$Addres
The command "$ cat my_file" in Shell prints "$Questions" and "$Address", instead of "/Users/User/Stackoverflow/Questions" and "My address". Other places where I would like have the variables are Email and Browser. But I cannot get them working.
How can I have my variables to work in every program?
cat doesn't interpret variables. It simply prints out the contents of a file, byte-for-byte.
If you want to be able to print out the values of the variables with my_file, I would suggest changing it to read
echo "$Questions"
echo "$Address"
Then you can "source" it (kind of like running it in the current shell environment) with
$ source my_file
or
$ . my_file
You might also have to use export in .bashrc, like so:
export Questions='/Users/User/Stackoverflow/Questions'
export Address='My address'
How can I have my variables to work in every program?
You can't. Bash and cat are two separate programs. You set a bash variable, it doesn't mean that cat will behave like bash to interpret it. $VARNAME is a shell syntax, cat is a different program, that share almost nothing with the shell.
You can export the shell variable as an environment variable, but cat is not programmed to replace any text templates, it goes way beyond its purpose.
Instead, you may use sed to perform text template substitutions:
sed -e "s|#QUESTIONS#|$Questions|g; s|#ADDRESS#|$Address|g" file.txt
This will replace all instances of #QUESTIONS# and #ANSWERS# in the file with the contents of $Questions and $Address shell variables. Note that these shell variables must not contain any pipe ("|") symbols, since the suggestion uses them as delimiters.
You can get the "cat" thing to work using some nasty hackery:
eval "$(printf 'cat << END\n%s\nEND' "$(< foo)")"
Where "foo" is the file that contains your text you want the bash parameters expanded from. This solution basically just converts the text into a here document, which does expand bash parameters.
cat <<END
[your text]
END
Limitations:
You can't have a line with just "END" in the text file or the solution will break. It'll think the line with "END" in the text file ends the here document instead of the END in the printf command, and the ouput will end early.
TBH:
This is something you just shouldn't want to do. If you want to make template files, go find a templating system that's built for this. You shouldn't be raping bash into doing something that it isn't built to do. It's a scripting language, not a templating system. It's built to parse scripts with a well defined syntax, not arbitrary text files.
You can't. In order to do that, you'd need the cooperation of every email client writer, every browser writer, every utility writer.
Type env see if the variables exist.
If so, try calling them with ${VAR_NAME}.
After re-iterating I now see your problem. You just can't have a text file, cat out it's content and expect the environments variables to be parsed. You just can't.
If it was a bash script file, and you were to run it, you could echo out the variables and they would be parsed like you want.
From your comment on Paul Tomblin's answer:
Are you sure? I have heard that you can have all kind of things like RSS-reader in Emacs. Perhaps, there is a better cooperation. I am a VIM-user, so I don't know. If someone knows whether Emacs has great cooperation between programs, please do not hesitate to share your knowledge. – UnixBasics (3 mins ago)
Do you want (or would you be satisfied with) an editor that can expand your environment variables?
That is a different (i.e. simpler, and possible) problem.
On purely theoretical level, I suppose a hacked filesystem could do what you want, but it would certainly break all kinds of binary storage. So we add a filesystem flag for text (expandable) and non-text file types. And we'd need a way for the filesystem to know what set of variable to expand, and ad nauseum...
Just add to your ~/.profile or to ~/.bashrc:
export Questions='/Users/User/Stackoverflow/Questions'
export Address='My address'

Resources