问题
String concatenation on bash script doesn't work on comma "," character.
A="Hello";
B=",World";
C=$A$B
echo $C;
It prints the output as
Hello World
Bash version is:
GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
The same code seems to work in here
回答1:
The most likely explanation is that you have $IFS
set to ,
The simplest way around this is to double-quote $C
, in which case echo
is passed the value unmodified:
echo "$C"
Also note that you don't need the semicolons to terminate your commands, given that each command is on its own line.
To print the current value of $IFS
in unambiguous form, use
printf '%q\n' "$IFS" # the default value will print as $' \t\n' - space, tab, newline
As for why the ,
disappeared:
- When you use an unquoted variable reference such as
$C
, the shell applies various shell expansions to the value. - Notably, word splitting is applied, which means that the value is split into tokens using any of the characters contained in the special
$IFS
variable as a separator ("IFS" stands for "Internal Field Separator"). - By default,
$IFS
contains a space, a tab, and a newline, effectively splitting by whitespace. - In your case,
$IFS
likely contained,
resulting inHello,World
getting split intoHello
andWorld
, which are then passed toecho
as separate arguments. As stated, double-quoting variable references prevents this behavior. echo
, when given multiple arguments, always uses a single space to separate them on output.
Tips for setting $IFS
:
Since $IFS
is a global variable, it's good practice to restore it to its previous value after changing it:
prevIFS=$IFS IFS=',' # save old value, set desired value (',', in this example)
# ... perform operations with custom $IFS in effect
IFS=$prevIFS # restore old value
However, there are techniques that localize the change, which means you do not have to explicitly save and restore its previous value:
If a custom $IFS
value is only needed for a single command based on an external utility or builtin -- typically read
-- prepend IFS=...
to the command; e.g.:
IFS=/ read -r var1 var2 <<<'a/b' # -> $var1 == 'a', $var2 == 'b'
This makes the changed $IFS
take effect only for the command invoked.
Caveat: This does NOT work in situations where the changed IFS value must take effect BEFORE invoking the builtin / executable, such as with shell expansions; e.g.:
# !! Does NOT work as intended, because $var is expanded BEFORE `IFS=/` takes effect.
var='a/b'; IFS=/ set -- $var
Inside a shell function, if you want to change $IFS
for the entire function, but only for that function, use a local $IFS
variable that shadows the global $IFS
:
foo() {
local IFS=/ var1 var2 # $IFS change confined to this function due to `local`
read -r var1 var2 <<<"$1"
echo "[$var1] [$var2]"
}
foo "a/b" # -> '[a] [b]'
If feasible, enclose a list of commands in a subshell:
(arr=(a b); IFS=/; echo "${arr[*]}") # -> 'a/b'
The $IFS
modification is only visible to subshell.
Caveat: variables modified or created in the subshell are not visible to the current shell (which is, in fact, what this technique relies on).
来源:https://stackoverflow.com/questions/29493353/string-concatenation-doesnt-work-for-comma-character