Categories
bash concatenation shell string-concatenation syntax

How to concatenate string variables in Bash

3299

In PHP, strings are concatenated together as follows:

$foo = "Hello";
$foo .= " World";

Here, $foo becomes "Hello World".

How is this accomplished in Bash?

5

  • 10

    foo="Hello" foo=$foo" World" echo $foo this rather worked for “#!/bin/sh”

    – parasrish

    Mar 27, 2018 at 5:39


  • 1

    What to do if you want HelloWorld without space?

    – Adi

    Jul 3, 2018 at 16:22

  • 1

    @Adi foo1="World" foo2="Hello" foo3="$foo1$foo2"

    – GeneCode

    Apr 17, 2019 at 2:02


  • 2

    spaces does a matter in bash)

    – Capibar

    May 23, 2019 at 13:10

  • 1

    to give an example of inserting into a string do echo "sh ${HOME}/ultimate-utils/run_tb.sh"

    Jul 22, 2021 at 15:29

4496

foo="Hello"
foo="${foo} World"
echo "${foo}"
> Hello World

In general to concatenate two variables you can just write them one after another:

a="Hello"
b='World'
c="${a} ${b}"
echo "${c}"
> Hello World

15

  • 73

    Does there have to be a space in your first example? Is it possible to do something like foo="$fooworld"? I would assume not…

    Jan 30, 2014 at 21:25

  • 375

    @nonsensickle That would look for a variable named fooworld. Disambiguating that is done with braces, as in foo="${foo}world"

    – twalberg

    Mar 7, 2014 at 17:29

  • 2

    @twalberg I’ve found you can also use foo=$foo'world'

    – JVE999

    Dec 10, 2014 at 2:54

  • 6

    @JVE999 Yes, that works as well, although in my opinion it’s not quite as good for code clarity… But that may just be my preference… There are a couple other ways it can be done as well – the point is making sure the variable name is separated from the non-variable-name parts so that it parses correctly.

    – twalberg

    Dec 10, 2014 at 3:57

  • 3

    One problem with putting the whole thing in double quotes, as with foo="$foo World", is that the additional string (“world” in this case) would be interpreted by the shell if it contained variable names, etc, which is usually not wanted. IMO, the common case requires the syntax $foo="$foo"' world'.

    Dec 14, 2014 at 22:47


1284

Bash also supports a += operator as shown in this code:

A="X Y"
A+=" Z"
echo "$A"

output

X Y Z

10

  • 2

    Can I use this syntax with the export keyword? e.g. export A+="Z" or maybe the A variable only needs to be exported once?

    – levesque

    Mar 20, 2014 at 17:13


  • 4

    @levesque: Both :-). Variables only need to be exported once, but export A+=Z works quite nicely as well.

    – thkala

    Mar 20, 2014 at 17:16

  • 59

    Since this is a bashism, I think it’s worth a mention that you should never use #!/bin/sh in a script using this construction.

    Apr 28, 2015 at 16:40

  • 3

    It’s specifically and only a plus-equals operator. That is, unlike Javascript, in Bash, echo $A+$B prints “X Y+Z”

    – phpguru

    Feb 13, 2017 at 19:04

  • 10

    A bashism is a shell feature which is only supported in bash and certain other more advanced shells. It will not work under busybox sh or dash (which is /bin/sh on a lot of distros), or certain other shells like the /bin/sh provided on FreeBSD.

    Sep 28, 2017 at 14:12

1055

+50

Bash first

As this question stand specifically for Bash, my first part of the answer would present different ways of doing this properly:

+=: Append to variable

The syntax += may be used in different ways:

Append to string var+=...

(Because I am frugal, I will only use two variables foo and a and then re-use the same in the whole answer. 😉

a=2
a+=4
echo $a
24

Using the Stack Overflow question syntax,

foo="Hello"
foo+=" World"
echo $foo
Hello World

works fine!

Append to an integer ((var+=...))

variable a is a string, but also an integer

echo $a
24
((a+=12))
echo $a
36

Append to an array var+=(...)

Our a is also an array of only one element.

echo ${a[@]}
36

a+=(18)

echo ${a[@]}
36 18
echo ${a[0]}
36
echo ${a[1]}
18

Note that between parentheses, there is a space separated array. If you want to store a string containing spaces in your array, you have to enclose them:

a+=(one word "hello world!" )
bash: !": event not found

Hmm.. this is not a bug, but a feature… To prevent bash to try to develop !", you could:

a+=(one word "hello world"! 'hello world!' $'hello world\041')

declare -p a
declare -a a="([0]="36" [1]="18" [2]="one" [3]="word" [4]="hello world!" [5]="h
ello world!" [6]="hello world!")"

printf: Re-construct variable using the builtin command

The printf builtin command gives a powerful way of drawing string format. As this is a Bash builtin, there is a option for sending formatted string to a variable instead of printing on stdout:

echo ${a[@]}
36 18 one word hello world! hello world! hello world!

There are seven strings in this array. So we could build a formatted string containing exactly seven positional arguments:

printf -v a "%s./.%s...'%s' '%s', '%s'=='%s'=='%s'" "${a[@]}"
echo $a
36./.18...'one' 'word', 'hello world!'=='hello world!'=='hello world!'

Or we could use one argument format string which will be repeated as many argument submitted…

Note that our a is still an array! Only first element is changed!

declare -p a
declare -a a="([0]="36./.18..."\''one'\'' '\''word'\'', '\''hello world!'\''=='\
''hello world!'\''=='\''hello world!'\''" [1]="18" [2]="one" [3]="word" [4]="hel
lo world!" [5]="hello world!" [6]="hello world!")'

Under bash, when you access a variable name without specifying index, you always address first element only!

So to retrieve our seven field array, we only need to re-set 1st element:

a=36
declare -p a
declare -a a="([0]="36" [1]="18" [2]="one" [3]="word" [4]="hello world!" [5]="he
llo world!" [6]="hello world!")"

One argument format string with many argument passed to:

printf -v a[0] '<%s>\n' "${a[@]}"
echo "$a"
<36>
<18>
<one>
<word>
<hello world!>
<hello world!>
<hello world!>

Using the Stack Overflow question syntax:

foo="Hello"
printf -v foo "%s World" $foo
echo $foo
Hello World

Nota: The use of double-quotes may be useful for manipulating strings that contain spaces, tabulations and/or newlines

printf -v foo "%s World" "$foo"

Shell now

Under POSIX shell, you could not use bashisms, so there is no builtin printf.

Basically

But you could simply do:

foo="Hello"
foo="$foo World"
echo $foo
Hello World

Formatted, using forked printf

If you want to use more sophisticated constructions you have to use a fork (new child process that make the job and return the result via stdout):

foo="Hello"
foo=$(printf "%s World" "$foo")
echo $foo
Hello World

Historically, you could use backticks for retrieving result of a fork:

foo="Hello"
foo=`printf "%s World" "$foo"`
echo $foo
Hello World

But this is not easy for nesting:

foo="Today is: "
foo=$(printf "%s %s" "$foo" "$(date)")
echo $foo
Today is: Sun Aug 4 11:58:23 CEST 2013

with backticks, you have to escape inner forks with backslashes:

foo="Today is: "
foo=`printf "%s %s" "$foo" "\`date\`"`
echo $foo
Today is: Sun Aug 4 11:59:10 CEST 2013

6

  • 7

    The += operator is also much faster than $a="$a$b" in my tests.. Which makes sense.

    – Matt

    Feb 21, 2016 at 5:13

  • 10

    This answer is awesome, but I think it’s missing the var=${var}.sh example from other answers, which is very useful.

    – geneorama

    Jul 20, 2016 at 22:29

  • 1

    Is bash the only shell with += operator? I want to see if it is portable enough

    – dashesy

    Aug 15, 2016 at 15:41

  • 1

    @dashesy no. i’ts surely not the only shell with += operator, but all this ways are bashisms, so not portable! Even you could encounter special bug in case of wrong bash version!

    Aug 16, 2016 at 6:15

  • 1

    This is the correct answer IMO, because i was looking for concatenating without spaces, and += works like a charm.

    – A. K.

    Nov 17, 2020 at 16:46