Bash variables with spaces - bash

I'm facing the next problem in MinGW shell under windows. I have in my /etc/profile the expression:
export GIT_SSH="/c/Program Files/TortoiseGit/bin/TortoisePlink.exe"
This doesn't work when I use git fetch on the local repository. But if I do it like this (old DOS way), it works:
export GIT_SSH="/c/Progra~1/TortoiseGit/bin/TortoisePlink.exe"
My question is:
How can I make it work using spaces in the variable?
For testing purpose you can simulate something like this (any example is good):
export VAR="/c/Program Files/TortoiseGit/bin/TortoisePlink.exe"
# and try to execute like this
$VAR
Is there a solution for this (other than the previous mentioned)?

Execute it like this: "$VAR". This is one of the most significant gotchas in shell scripting because strings are always substituted literally and any contained spaces are treated as token delimiters rather than as characters of the string. Think of substituting a variable as a kind of code pasting at runtime.
What really happens when you write $VAR is that the shell tries to execute the binary /c/Program with a first argument Files/TortoiseGit/bin/TortoisePlink.exe.
I learned this the hard way by getting a strange syntax error in a big shell script for a particular input. No other languages I can think of can complain for syntax errors if the runtime input contains special characters - but that is the nature of shell scripting since command interpreters like bash and sh interpret the code line by line.
Whenever you expect a string to contain spaces and you don't want to treat it as separate tokens, enclose it in double quotes.

For reference, I solved a similar issue on osx by encapsulating the argument with escaped quotations. This may not be the best solution, but it seems to work.
alias sub="\"/Applications/Sublime Text 2.app/Contents/SharedSupport/bin/subl\""

I've solved it by including a backslash to escape the space:
/Program Files becomes /Program\ Files
Example:
export GIT_SSH=/c/Program\ Files/TortoiseGit/bin/TortoisePlink.exe

With Git 2.23 (Q3 2019, eight years later), a GIT_SSH set to /c/Program\ Files/TortoiseGit/bin/TortoisePlink.exe will... work (for those still on Windows 7)!
See commit eb7c786 (16 Jul 2019) by Johannes Schindelin (dscho).
(Merged by Junio C Hamano -- gitster -- in commit a5194d8, 25 Jul 2019)
mingw: support spawning programs containing spaces in their names
On some older Windows versions (e.g. Windows 7), the CreateProcessW() function does not really support spaces in its first argument, lpApplicationName.
But it supports passing NULL as lpApplicationName, which makes it figure out the application from the (possibly quoted) first argument of lpCommandLine.
Let's use that trick (if we are certain that the first argument matches
the executable's path) to support launching programs whose path contains
spaces.
This fixes git-for-windows/git issue 692
Git 2.24 (Q4 2019) adds a test:
See commit 71f4960 (01 Oct 2019) by Alexandr Miloslavskiy (SyntevoAlex).
(Merged by Junio C Hamano -- gitster -- in commit 424663d, 09 Oct 2019)
t0061: fix test for argv[0] with spaces (MINGW only)
The test was originally designed for the case where user reported that setting GIT_SSH to a .bat file with spaces in path fails on Windows: git-for-windows#692

some dirty hack for commands with spaces in variables -
for i in `k get po --all-namespaces -o wide | grep 'CrashLoop\|ImagePull' | awk '{printf " -n#%s#scale#deployment/%s",$1,$2}'`; do $(echo "kubectl ${i%-*-*} --replicas=0" | sed 's/#/ /g'); done
so here i use # instead of space forming variable and use $(echo variavle | sed 's/#/ /g') to execute lines from sed with spaces
It is hackk but it is simplier than all "corect ways" and works for me

Related

What does two at (#) signs surrounding a string mean in a shell script?

For example,
# Execute the pre-hook.
export SHELL=#shell#
param1=#param1#
param2=#param2#
param3=#param3#
param4=#param4#
param5=#param5#
if test -n "#preHook#"; then
. #preHook#
fi
For context, this is from a shell script in a commit from 2004 in the Nixpkgs repo; tried to see if this maybe a reference feature but string "shell" only occurs once (in a case-sensitive search) in the entire file.
The answer by Chris Dodd is correct, insofar as there's no intrinsic meaning to the shell -- and #foo# is thus commonly used as a sigil. Insofar as you encountered this in nixpkgs, it provides some stdenv tools specifically for implementing this pattern.
As documented at https://nixos.org/manual/nixpkgs/stable/#ssec-stdenv-functions, nixpkgs stdenv provides shell functions including substitute, substituteAll, substituteInPlace &c. which will replace #foo# values with the content of corresponding variables.
In the context of the linked commit, subsitutions of that form can be seen being performed in pkgs/build-wrapper/gcc-wrapper/builder.sh:
sed \
-e "s^#gcc#^$src^g" \
-e "s^#out#^$out^g" \
-e "s^#bash#^$SHELL^g" \
-e "s^#shell#^$shell^g" \
< $gccWrapper > $dst
...is replacing #out# with the value of $out, #bash# with the value of $SHELL, etc.
The # symbol has no meaning to the shell -- it is a punctuation character that will pretty much never occur in any actual shell script.
This makes it a good choice to use for patterns in script templates -- the basic idea being that a simple search-and-replace process will be used (perhaps with a sed script as in the link you show) to rewrite the template into an actual shell script. Every string of the form #name# in the template will be replaced by some other string related to the environment in which the script is being installed.

bash: using rename to left pad filenames with a zero under when their prefix is too short

I'm using a naming convention with number prefixes to track some files. But I am running out with 2-digit prefix. So, instead of 11.abc 12.def I want to move to 011.abc 012.def. I already have some 013.xxx 014.yyy.
Trying this in an empty directory:
touch 11.abc 12.def 013.xxx 014.yyy
ls -1 gives:
013.xxx
014.yyy
11.abc
12.def
Try #1:
This should match anything that starts with 2 digits, but not 3.
rename -n 's/^\d\d[^\d]/0$1/' *
Now I was kind of hoping that $1 would hold the match, like 11, with 0$1 giving me 011.
No such luck:
Use of uninitialized value $1 in concatenation (.) or string at (eval 2) line 1.
'11.abc' would be renamed to '0abc'
Use of uninitialized value $1 in concatenation (.) or string at (eval 2) line 1.
'12.def' would be renamed to '0def'
On the positive side, it's willing to leave 013 and 014 alone.
Try #2 rename -n 's/^\d\d[^\d]/0/' *
'11.abc' would be renamed to '0abc'
'12.def' would be renamed to '0def'
Since this is regex based, can I somehow save the match group 11 and 12?
If I can't use rename I'll probably write a quick Python script. Don't want to loop with mv on it.
And, actually, my naming covention is 2-3 digits followed by a dot, so this is a good match too.
rename -n 's/^\d\d\./<whatever needs to go here>/' *
For what it's worth, I am using the Homebrew version of rename, as I am on a mac.
try this:
rename 's/^(\d{2}\..*)/0$1/' *
rename is problematic because it's not part of POSIX (so it isn't normally available on many Unix-like systems), and there are two very different forms of it in widespread use. See Why is the rename utility on Debian/Ubuntu different than the one on other distributions, like CentOS? for more information.
This Bash code does the renaming with mv (which is part of POSIX):
#! /bin/bash -p
shopt -s nullglob # Patterns that match nothing expand to nothing.
for f in [0-9][0-9].* ; do
mv "$f" "0$f"
done
shopt -s nullglob is to prevent problems if the code is run in a directory that has no files that need to be renamed. If nullglob isn't enabled the code would try to rename a file called '[0-9][0-9].*', which would have unwanted consequences whether or not such a file existed.

Why do people use grave accent instead of dollar and parentheses in g++? [duplicate]

To store the output of a command as a variable in sh/ksh/bash, you can do either
var=$(command)
or
var=`command`
What's the difference if any between the two methods?
The backticks/gravemarks have been deprecated in favor of $() for command substitution because $() can easily nest within itself as in $(echo foo$(echo bar)). There are other differences such as how backslashes are parsed in the backtick/gravemark version, etc.
See BashFAQ/082 for several reasons to always prefer the $(...) syntax.
Also see the POSIX spec for detailed information on the various differences.
They behave the same. The difference is syntactical: it's easier to nest $() than ``:
listing=$(ls -l $(cat filenames.txt))
vs.
listing=`ls -l \`cat filenames.txt\``
July 2014: The commit f25f5e6 (by Elia Pinto (devzero2000), April 2014, Git 2.0) adds to the nesting issue:
The backquoted form is the traditional method for command substitution, and is supported by POSIX.
However, all but the simplest uses become complicated quickly.
In particular, embedded command substitutions and/or the use of double quotes require
careful escaping with the backslash character.
That is why the git/Documentation/CodingGuidelines mentions:
We prefer $( ... ) for command substitution; unlike ``, it properly nests.
It should have been the way Bourne spelled it from day one, but unfortunately isn't.
thiton commented:
That is why `echo `foo`` won't work in general because of the inherent ambiguity because each ``can be opening or closing.
It might work for special cases due to luck or special features.
Update January 2016: Git 2.8 (March 2016) gets rid of backticks entirely.
See commit ec1b763, commit 9c10377, commit c7b793a, commit 80a6b3f, commit 9375dcf, commit e74ef60, commit 27fe43e, commit 2525c51, commit becd67f, commit a5c98ac, commit 8c311f9, commit 57da049, commit 1d9e86f, commit 78ba28d, commit efa639f, commit 1be2fa0, commit 38e9476, commit 8823d2f, commit 32858a0, commit cd914d8 (12 Jan 2016) by Elia Pinto (devzero2000).
(Merged by Junio C Hamano -- gitster -- in commit e572fef, 22 Jan 2016)
From Git 2.8 onwards, it is all $(...), no more `...`.
When the older back-tick form is used, backslash retains its literal meaning except when followed by $, `, or \. The first back-tick not preceded by a backslash terminates the command substitution.
When using the newer $(command) form, all characters between the parentheses make up the command; none are treated specially.
Both forms can be nested, but the back-tick variety requires the following form.
`echo \`foo\``
As opposed to:
$(echo $(foo))
There is little difference, except for what unescaped characters you can use inside of the command. You can even put `...` commands inside $(...) ones (and vice versa) for a more complicated two-level-deep command substitution.
There is a slightly different interpretation of the backslash character/operator. Among other things, when nesting `...` substitution commands, you must escape the inner ` characters with \, whereas with $() substition it understands the nesting automatically.
"What's the difference if any between the two methods?"
Make attention to this behaviour:
A="A_VARIABLE"
echo "$(echo "\$A")"
echo "`echo "\$A"`"
You will get these results:
$A
A_VARIABLE

What's difference between `which port` and $(which port) [duplicate]

To store the output of a command as a variable in sh/ksh/bash, you can do either
var=$(command)
or
var=`command`
What's the difference if any between the two methods?
The backticks/gravemarks have been deprecated in favor of $() for command substitution because $() can easily nest within itself as in $(echo foo$(echo bar)). There are other differences such as how backslashes are parsed in the backtick/gravemark version, etc.
See BashFAQ/082 for several reasons to always prefer the $(...) syntax.
Also see the POSIX spec for detailed information on the various differences.
They behave the same. The difference is syntactical: it's easier to nest $() than ``:
listing=$(ls -l $(cat filenames.txt))
vs.
listing=`ls -l \`cat filenames.txt\``
July 2014: The commit f25f5e6 (by Elia Pinto (devzero2000), April 2014, Git 2.0) adds to the nesting issue:
The backquoted form is the traditional method for command substitution, and is supported by POSIX.
However, all but the simplest uses become complicated quickly.
In particular, embedded command substitutions and/or the use of double quotes require
careful escaping with the backslash character.
That is why the git/Documentation/CodingGuidelines mentions:
We prefer $( ... ) for command substitution; unlike ``, it properly nests.
It should have been the way Bourne spelled it from day one, but unfortunately isn't.
thiton commented:
That is why `echo `foo`` won't work in general because of the inherent ambiguity because each ``can be opening or closing.
It might work for special cases due to luck or special features.
Update January 2016: Git 2.8 (March 2016) gets rid of backticks entirely.
See commit ec1b763, commit 9c10377, commit c7b793a, commit 80a6b3f, commit 9375dcf, commit e74ef60, commit 27fe43e, commit 2525c51, commit becd67f, commit a5c98ac, commit 8c311f9, commit 57da049, commit 1d9e86f, commit 78ba28d, commit efa639f, commit 1be2fa0, commit 38e9476, commit 8823d2f, commit 32858a0, commit cd914d8 (12 Jan 2016) by Elia Pinto (devzero2000).
(Merged by Junio C Hamano -- gitster -- in commit e572fef, 22 Jan 2016)
From Git 2.8 onwards, it is all $(...), no more `...`.
When the older back-tick form is used, backslash retains its literal meaning except when followed by $, `, or \. The first back-tick not preceded by a backslash terminates the command substitution.
When using the newer $(command) form, all characters between the parentheses make up the command; none are treated specially.
Both forms can be nested, but the back-tick variety requires the following form.
`echo \`foo\``
As opposed to:
$(echo $(foo))
There is little difference, except for what unescaped characters you can use inside of the command. You can even put `...` commands inside $(...) ones (and vice versa) for a more complicated two-level-deep command substitution.
There is a slightly different interpretation of the backslash character/operator. Among other things, when nesting `...` substitution commands, you must escape the inner ` characters with \, whereas with $() substition it understands the nesting automatically.
"What's the difference if any between the two methods?"
Make attention to this behaviour:
A="A_VARIABLE"
echo "$(echo "\$A")"
echo "`echo "\$A"`"
You will get these results:
$A
A_VARIABLE

What is the difference between $(command) and `command` in shell programming?

To store the output of a command as a variable in sh/ksh/bash, you can do either
var=$(command)
or
var=`command`
What's the difference if any between the two methods?
The backticks/gravemarks have been deprecated in favor of $() for command substitution because $() can easily nest within itself as in $(echo foo$(echo bar)). There are other differences such as how backslashes are parsed in the backtick/gravemark version, etc.
See BashFAQ/082 for several reasons to always prefer the $(...) syntax.
Also see the POSIX spec for detailed information on the various differences.
They behave the same. The difference is syntactical: it's easier to nest $() than ``:
listing=$(ls -l $(cat filenames.txt))
vs.
listing=`ls -l \`cat filenames.txt\``
July 2014: The commit f25f5e6 (by Elia Pinto (devzero2000), April 2014, Git 2.0) adds to the nesting issue:
The backquoted form is the traditional method for command substitution, and is supported by POSIX.
However, all but the simplest uses become complicated quickly.
In particular, embedded command substitutions and/or the use of double quotes require
careful escaping with the backslash character.
That is why the git/Documentation/CodingGuidelines mentions:
We prefer $( ... ) for command substitution; unlike ``, it properly nests.
It should have been the way Bourne spelled it from day one, but unfortunately isn't.
thiton commented:
That is why `echo `foo`` won't work in general because of the inherent ambiguity because each ``can be opening or closing.
It might work for special cases due to luck or special features.
Update January 2016: Git 2.8 (March 2016) gets rid of backticks entirely.
See commit ec1b763, commit 9c10377, commit c7b793a, commit 80a6b3f, commit 9375dcf, commit e74ef60, commit 27fe43e, commit 2525c51, commit becd67f, commit a5c98ac, commit 8c311f9, commit 57da049, commit 1d9e86f, commit 78ba28d, commit efa639f, commit 1be2fa0, commit 38e9476, commit 8823d2f, commit 32858a0, commit cd914d8 (12 Jan 2016) by Elia Pinto (devzero2000).
(Merged by Junio C Hamano -- gitster -- in commit e572fef, 22 Jan 2016)
From Git 2.8 onwards, it is all $(...), no more `...`.
When the older back-tick form is used, backslash retains its literal meaning except when followed by $, `, or \. The first back-tick not preceded by a backslash terminates the command substitution.
When using the newer $(command) form, all characters between the parentheses make up the command; none are treated specially.
Both forms can be nested, but the back-tick variety requires the following form.
`echo \`foo\``
As opposed to:
$(echo $(foo))
There is little difference, except for what unescaped characters you can use inside of the command. You can even put `...` commands inside $(...) ones (and vice versa) for a more complicated two-level-deep command substitution.
There is a slightly different interpretation of the backslash character/operator. Among other things, when nesting `...` substitution commands, you must escape the inner ` characters with \, whereas with $() substition it understands the nesting automatically.
"What's the difference if any between the two methods?"
Make attention to this behaviour:
A="A_VARIABLE"
echo "$(echo "\$A")"
echo "`echo "\$A"`"
You will get these results:
$A
A_VARIABLE

Resources