String concatenation does not work for comma
the most likely explanation is that you have set to $IFS
,
The easiest way is double-quote$C
, in this case echo
the value is passed unmodified:
echo "$C"
Also note that you don't need semicolons to break your commands, given that each command is on its own line.
To print the current value$IFS
in an unambiguous manner, use
printf '%q\n' "$IFS" # the default value will print as $' \t\n' - space, tab, newline
As for why it ,
disappeared :
- When you use an unquoted reference, for example
$C
, the shell applies different shell extension values to the value. - Specifically, word splitting is applied, which means that the value is split into tokens using any of the characters contained in the special variable
$IFS
as the delimiter ("IFS" stands for "Internal Field Separator"). $IFS
Contains space, tab and newline by default , effectively separating spaces.- In your case
$IFS
, it most likely contained,
, resulting inHello,World
split intoHello
andWorld
, which are then passedecho
in as separate arguments. As stated, double quoted links do not allow this behavior. -
echo
when multiple arguments are given, a single space is always used to allocate them on output.
Tips for setting $IFS
:
Since it is a global variable , it is recommended to restore its previous value after changing it: $IFS
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 methods that localize the change , which means you don't need to explicitly save and restore its previous value:
If a custom value $IFS
is only required for a single command based on an external utility or builtin - usually read
- prepend IFS=...
for the command ; eg:.
IFS=/ read -r var1 var2 <<<'a/b' # -> $var1 == 'a', $var2 == 'b'
This causes the changed to be $IFS
effective only for the called command.
Caution . This does NOT work in situations where the changed IFS value needs to take effect BEFORE invoking the embedded / executable, such as with a shell extension; eg:.
# !! Does NOT work as intended, because $var is expanded BEFORE `IFS=/` takes effect.
var='a/b'; IFS=/ set -- $var
Inside a wrapper function , if you want to change $IFS
for the whole 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 possible, enclose the command list in a subshell :
(arr=(a b); IFS=/; echo "${arr[*]}") # -> 'a/b'
The modification $IFS
is only visible to the subshell.
Caveat : Variables modified or created in the subshell are not visible to the current shell (which is actually what this method relies on).
source to share