String concatenation doesn't work for comma character

徘徊边缘 提交于 2019-12-07 19:04:40

问题


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 in Hello,World getting split into Hello and World, which are then passed to echo 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!