How to add path with space in Bash variable - bash

How can I add a path with a space in a Bash variable in .bashrc? I want to store some variables in .bashrc for paths and I encountered a path with a space in it.
I tried to add it between ' ' or use the escape character \, but it didn't help:
games=/run/media/mohamedRadwan/games\ moves # this doesn't work
games='/run/media/mohamedRadwan/games moves' # or this
games="/run/media/mohamedRadwan/games moves" # or this
... when I run:
mount $games
... it throws an error indicating that it's only trying to mount /run/media/mohamedRadwan/games.
But when I run echo $games, it shows the full value, /run/media/mohamedRadwan/games moves.
How can I solve this?

mount /dev/sda9 "$games"
As mentioned, always quote variable dereferences. Otherwise, the shell confuses the spaces in the variable's value as spaces separating multiple values.

When variable contains spaces, variable expansion and then word splitting will result to many arguments, echo command will display all arguments but other program or function may handle arguments another way.
Surrounding variable with double quotes will prevent arguments to be splitted
printf "'%s'\n" $games
printf "'%s'\n" "$games"

Related

How to use double quotes when assigning variables?

There's a bash file with something like this:
FOO=${BAR:-"/some/path/with/$VAR/in/it"}
Are those double quotes necessary? Based on the following test, I'd say no, and that no quote at all is needed in the above assignment. In fact, it's the user of that variable that needs to expand it within double quotes to avoid wrong splitting.
touch 'some file' # create a file
VAR='some file' # create a variable for that file name
FOO=${BAR:-$VAR} # use it with the syntax above, but no quotes
ls -l "$FOO" # the file does exist (here we do need double quotes)
ls -l $FOO # without quotes it fails searching for files `some` and `file`
rm 'some file' # remove temporary file
Am I correct? Or there's something more?
Are those double quotes necessary?
Not in this case, no.
Am I correct?
Yes. And it's always the user of the variable that has to quote it - field splitting is run when expanding the variable, so when using it it has to be quoted.
There are exceptions, like case $var in and somevar1=$somevar2 - contexts which do not run field splitting, so like do not require quoting. But anyway, quotes do not hurt in such cases and can be used anyway.
Or there's something more?
From POSIX shell:
2.6.2 Parameter Expansion
In addition, a parameter expansion can be modified by using one of the following formats. In each case that a value of word is needed (based on the state of parameter, as described below), word shall be subjected to tilde expansion, parameter expansion, command substitution, and arithmetic expansion.
${parameter:-word}
Because field splitting expansion is not run over word inside ${parameter:-word}, indeed, quoting doesn't do much.

How to use custom variables in gitlab ci/cd?

I'm struggling with gitlab ci/cd variables. I see so many conflicting examples. Anyhow, what I would like to know is how to use variables outside and within scripts.
For example, in a job config, can I assign a variable in the script section with a bash command?
some-job:
variables:
SOME_VAR: ''
script:
- SOME_VAR = $(<file_with_a_line_of_text.txt)
In the above case, I'm not sure if I can do this. But I need to populate a variable with the file contents (i.e. artifact). Also, when do I use '$' in front of the variable? Some examples I see using these formats:
"SOME_VAR" #in quotes, no dollar sign
"${SOME_VAR}" #in quotes, with dollar sign and wrapped with curly braces
${SOME_VAR} #no quotes, with dollar sign and wrapped with curly braces
$SOME_VAR #i.e. without the double quotes or curly braces
SOME_VAR #i.e. without the double quotes, dollar sign, and curly braces
So many variations of usage that I can see in examples but don't really know when to use each style. And I can't find one example online of a custom variable being set in a script using a bash command.
When I'm setting variables in bash, I always do it without the spaces around the =:
VAR1="some string"
VAR2=23
VAR3=true
VAR4=$(cat /path/to/file.txt)
Let's go through these examples one at a time:
You can set a variable as a string by using quotes around the string.
You can set it to an int (probably a float too, but haven't personally used it)
You can set it to a bool
You can set it to the output of a command. The command is inside the command: $(#command).
Now let's use them:
echo $VAR1
# some string
echo "This is my variable $VAR1"
# This is my variable some string
echo "This is my variable ${VAR1}"
# This is my variable some string
echo ${VAR1}
# some string
echo "Error code ${VAR2}A"
# Error code 23A
echo "Error code $VAR2A"
# Error code --- Note: the variable $VAR2A dosn't exist
echo "Error code ${VAR2}${VAR1}"
# Error code 23some string
echo VAR1
# VAR1
echo "VAR1"
# VAR1
This illustrates the difference between the different forms, but in general, you reference a variable's value with $+variable-name. Doing "SOME_VAR" or SOME_VAR just prints out the string "SOME_VAR" (ie, not referencing a variable at all).
The difference between $SOME_VAR and ${SOME_VAR} is that the latter lets you use it when there is other content directly before or after the variable without erroring.
How to use custom variables in gitlab ci/cd?
Normally like in any other shell.
But note that gitlab-ci.yml is a yaml file and yaml has special parsings. Because of that in script: ex. - echo bla is the same as - 'echo bla', because in yaml the content of script: is an array of strings that are later spitted by shell.
how to use variables outside and within scripts.
Normally like in any other shell script.
when to use each style
"SOME_VAR" #in quotes, no dollar sign
SOME_VAR #i.e. without the double quotes, dollar sign, and curly braces
when you want to have a string SOME_VAR literally
"${SOME_VAR}"
is the same as "$SOME_VAR". When you want to have the content of SOME_VAR variable literally.
${SOME_VAR} #no quotes, with dollar sign and wrapped with curly braces
$SOME_VAR #i.e. without the double quotes or curly braces
When you want the content of SOME_VAR variable after word splitting and filename expansion. That means that SOME_VAR='*' and then echo "$SOME_VAR" will print *, but echo $SOME_VAR will print all files in current directory. You usually always want to quote expansions.
The form ${SOME_VAR} is used if concatenated with some other string, ex. $SOME_VARbla is not ${SOME_VAR}bla.
Do not use upper case variables in your scripts - prefer lower case. Prefer using upper case variables for exported variables. Be aware of clashes - COLUMN PATH USER UID are examples of already used variables.
can I assign a variable in the script section with a bash command?
Shell is space aware. var = val will execute a command named var with two arguments = and val. var=val will assign the string val to variable named var. Do:
- SOME_VAR=$(<file_with_a_line_of_text.txt)
In gitlab-ci I would prefer to use cat in case I will want to move to alpine. $(< is a bash extension.
- SOME_VAR=$(cat file_with_a_line_of_text.txt)
There doesn't seem to be any point in setting providing SOME_VAR in environment with variables: SOME_VAR.
When do I use '$' in front of the variable?
When you want to trigger variable expansion. Variable expansion substitutes variable name for the variable value.
Check your scripts with http://shellcheck.net . Read https://mywiki.wooledge.org/BashGuide a good shell introduction and https://wiki.bash-hackers.org/scripting/obsolete .

Bashrc script does not change directory on manipulated string that contains space

I'm trying to develop a fast solution to navigate on folders between Windows and Cygwin.
On windows the path looks like this:
C:\Users\foo\my folder\
When I need to get to the same folder on Cygwin I need to use the following format
/cygdrive/c/Users/foo/my\ folder/
Every time I'm on explorer I need to copy the link and edit it.
So I made a simple script for my .bashrc file
It works fine for nonspace containing paths, but when I try to replace the space with '\ ', the link does not find the directory.
I tried to echo the path, copied and pasted to the terminal and it works.
But this does not work:
function cdWinPath(){
if [ `expr index "$1" C:\\` == '1' ]
then
length=`expr length "$1"`
pathSubs=${1:2:$length}
cygPath="/cygdrive/c${pathSubs//\\/\/}"
cygPath="${cygPath// /\\\ }" #piece of code that replaces blank space
echo "cd $cygPath"
cd "$cygPath" # shows 'No such file or directory'
else
echo "Could not understand path $1"
fi
}
The shell parses quotes and escapes before expanding variables, so quotes and escapes in variables' values don't get treated as such, just as normal characters. So don't try to embed escapes in the variable, just put double-quotes around the variable reference.
Some other suggestions: Rather than messing around with expr, just use the shell's built-in string manipulation. When you do need to capture output from another program, use $( ) instead of backticks. Finally, the function keyword is nonstandard, just use () after the name to define a function. Something like this:
cdWinPath() {
local cygPath="${1/#[Cc]:\\//}" # Replace 'C:\' or 'C:\' prefix with just '/'
cygPath="${cygPath//\\//}" # Replace any other '\' with '/'
cd "$cygPath"
}
Note, however, that this requires the windows path to be passed correctly to the function. That means that backslashes and/or spaces in the path must be properly escaped or quoted (meaning that you must double-quote any variable references).
cdWinPath 'C:\Users\foo\my folder\' # This works
cdWinPath C:\\Users\\foo\\my\ folder\\ # So does this
cdWinPath C:\Users\foo\my folder\ # This does not work
cdWinPath "$somevar" # This works, provided `somevar` is properly set
cdWinPath $somevar # This does not work
If you want it to tolerate the path being passed incorrectly, you can make it a little more tollerant by replacing the first line with:
local cygPath="${*/#[Cc]:\\//}"
Using ${*...} instead of $[1...} will take all parameters passed to the function and mash them together with spaces between, on the assumption that they were originally one string that got split on spaces. This will sometimes work, but not always. For example, this command:
cdWinPath C:\Users\foo\my folder\
... will still not work because the shell will interpret the backslashes as escapes before the function even gets the string, and there's no way to fix that.

why doesn't bash IFS value split expansion argument?

>export FOOBAR=foobar; IFS=b echo ${FOOBAR}
I was expecting to see
foo ar
but I see
foobar
Why?
The IFS hasnt yet taken effect. add another ";":
FOOBAR=foobar IFS=b; echo ${FOOBAR}
In man bash section SIMPLE COMMAND EXPANSION
you can read (abbreviated):
When a simple command is executed
The words that the parser has marked as variable assignments (those preceding the command name) are saved for later processing.
The words that are not variable assignments or redirections are expanded.
...
The text after the = in each variable assignment ... [are] assigned to the variable.
so the IFS=b is done after expanding $FOOBAR.
[edit]I removed the technically incorrect answer.
http://tldp.org/LDP/abs/html/internalvariables.html
"This variable determines how Bash recognizes fields, or word boundaries, when it interprets character strings."

Bash path issue

I have a script which contains the following line:
propFile="${0%/*}/anteater.properties"
What does "${0%/*}" mean?
This command gives a path to the script - but there is a spaces at path and script can't find this file - how to deal with it?
The % operator in variable expansion removes the matching suffix pattern given to it. So ${0%/*} takes the variable $0, and removes all matching /* at the end. This is equivalent to the command dirname, which, when given a path, returns the parent directory of that path.
In order to deal with spaces in bash variable, whenever expanding the variable (i.e. whenever you write $var), you should quote it. In short, always use "$var" instead of just $var.
Consider reading shell parameter expansion and variable quoting in the bash manual to learn more about these two subjects.
strips the suffix matching /*, i.e. everything after last slash including the slash itself.
quote it wherever you use it (cat "$propFile").

Resources