[bash] How to concatenate string variables in Bash

In PHP, strings are concatenated together as follows:

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

Here, $foo becomes "Hello World".

How is this accomplished in Bash?

This question is related to bash shell syntax concat string-concatenation

The answer is


Here is a concise summary of what most answers are talking about.

Let's say we have two variables and $1 is set to 'one':

set one two
a=hello
b=world

The table below explains the different contexts where we can combine the values of a and b to create a new variable, c.

Context                               | Expression            | Result (value of c)
--------------------------------------+-----------------------+---------------------
Two variables                         | c=$a$b                | helloworld
A variable and a literal              | c=${a}_world          | hello_world
A variable and a literal              | c=$1world             | oneworld
A variable and a literal              | c=$a/world            | hello/world
A variable, a literal, with a space   | c=${a}" world"        | hello world
A more complex expression             | c="${a}_one|${b}_2"   | hello_one|world_2
Using += operator (Bash 3.1 or later) | c=$a; c+=$b           | helloworld
Append literal with +=                | c=$a; c+=" world"     | hello world

A few notes:

  • enclosing the RHS of an assignment in double quotes is generally a good practice, though it is quite optional in many cases
  • += is better from a performance standpoint if a big string is being constructed in small increments, especially in a loop
  • use {} around variable names to disambiguate their expansion (as in row 2 in the table above). As seen on rows 3 and 4, there is no need for {} unless a variable is being concatenated with a string that starts with a character that is a valid first character in shell variable name, that is alphabet or underscore.

See also:


I prefer to use curly brackets ${} for expanding variable in string:

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

Curly brackets will fit to Continuous string usage:

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

Otherwise using foo = "$fooWorld" will not work.


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

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

output

X Y Z


In my opinion, the simplest way to concatenate two strings is to write a function that does it for you, then use that function.

function concat ()
{
    prefix=$1
    suffix=$2

    echo "${prefix}${suffix}"
}

foo="Super"
bar="man"

concat $foo $bar   # Superman

alien=$(concat $foo $bar)

echo $alien        # Superman

Here is the one through AWK:

$ foo="Hello"
$ foo=$(awk -v var=$foo 'BEGIN{print var" World"}')
$ echo $foo
Hello World

I don't know about PHP yet, but this works in Linux Bash. If you don't want to affect it to a variable, you could try this:

read pp;  *# Assumes I will affect Hello to pp*
pp=$( printf $pp ;printf ' World'; printf '!');
echo $pp;

>Hello World!

You could place another variable instead of 'Hello' or '!'. You could concatenate more strings as well.


Even if the += operator is now permitted, it has been introduced in Bash 3.1 in 2004.

Any script using this operator on older Bash versions will fail with a "command not found" error if you are lucky, or a "syntax error near unexpected token".

For those who cares about backward compatibility, stick with the older standard Bash concatenation methods, like those mentioned in the chosen answer:

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

If it is as your example of adding " World" to the original string, then it can be:

#!/bin/bash

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

The output:

Hello World

Note that this won't work

foo=HELLO
bar=WORLD
foobar=PREFIX_$foo_$bar

as it seems to drop $foo and leaves you with:

PREFIX_WORLD

but this will work:

foobar=PREFIX_"$foo"_"$bar"

and leave you with the correct output:

PREFIX_HELLO_WORLD


If what you are trying to do is to split a string into several lines, you can use a backslash:

$ a="hello\
> world"
$ echo $a
helloworld

With one space in between:

$ a="hello \
> world"
$ echo $a
hello world

This one also adds only one space in between:

$ a="hello \
>      world"
$ echo $a
hello world

I wanted to build a string from a list. Couldn't find an answer for that so I post it here. Here is what I did:

list=(1 2 3 4 5)
string=''

for elm in "${list[@]}"; do
    string="${string} ${elm}"
done

echo ${string}

and then I get the following output:

1 2 3 4 5

The way I'd solve the problem is just

$a$b

For example,

a="Hello"
b=" World"
c=$a$b
echo "$c"

which produces

Hello World

If you try to concatenate a string with another string, for example,

a="Hello"
c="$a World"

then echo "$c" will produce

Hello World

with an extra space.

$aWorld

doesn't work, as you may imagine, but

${a}World

produces

HelloWorld

There's one particular case where you should take care:

user=daniel
cat > output.file << EOF
"$user"san
EOF

Will output "daniel"san, and not danielsan, as you might have wanted. In this case you should do instead:

user=daniel
cat > output.file << EOF
${user}san
EOF

I do it this way when convenient: Use an inline command!

echo "The current time is `date`"
echo "Current User: `echo $USER`"

var1='hello'
var2='world'
var3=$var1" "$var2 
echo $var3

You can do this too:

$ var="myscript"

$ echo $var

myscript


$ var=${var}.sh

$ echo $var

myscript.sh

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

bla=hello
laber=kthx
echo "${bla}ohai${laber}bye"

Will output

helloohaikthxbye

This is useful when $blaohai leads to a variable not found error. Or if you have spaces or other special characters in your strings. "${foo}" properly escapes anything you put into it.


Despite of the special operator, +=, for concatenation, there is a simpler way to go:

foo='Hello'
foo=$foo' World'
echo $foo

Double quotes take an extra calculation time for interpretation of variables inside. Avoid it if possible.


I kind of like making a quick function.

#! /bin/sh -f
function combo() {
    echo $@
}

echo $(combo 'foo''bar')

Yet another way to skin a cat. This time with functions :D


There are voiced concerns about performance, but no data is offered. Let me suggest a simple test.

(NOTE: date on macOS does not offer nanoseconds, so this must be done on Linux.)

I have created append_test.sh on GitHub with the contents:

#!/bin/bash -e

output(){
    ptime=$ctime;
    ctime=$(date +%s.%N);
    delta=$(bc <<<"$ctime - $ptime");
    printf "%2s. %16s chars  time: %s  delta: %s\n" $n "$(bc <<<"10*(2^$n)")" $ctime $delta;
}

method1(){
    echo 'Method: a="$a$a"'
    for n in {1..32}; do a="$a$a"; output; done
}

method2(){
    echo 'Method: a+="$a"'
    for n in {1..32}; do a+="$a";  output; done
}

ctime=0; a="0123456789"; time method$1

Test 1:

$ ./append_test.sh 1
Method: a="$a$a"
 1.               20 chars  time: 1513640431.861671143  delta: 1513640431.861671143
 2.               40 chars  time: 1513640431.865036344  delta: .003365201
 3.               80 chars  time: 1513640431.868200952  delta: .003164608
 4.              160 chars  time: 1513640431.871273553  delta: .003072601
 5.              320 chars  time: 1513640431.874358253  delta: .003084700
 6.              640 chars  time: 1513640431.877454625  delta: .003096372
 7.             1280 chars  time: 1513640431.880551786  delta: .003097161
 8.             2560 chars  time: 1513640431.883652169  delta: .003100383
 9.             5120 chars  time: 1513640431.886777451  delta: .003125282
10.            10240 chars  time: 1513640431.890066444  delta: .003288993
11.            20480 chars  time: 1513640431.893488326  delta: .003421882
12.            40960 chars  time: 1513640431.897273327  delta: .003785001
13.            81920 chars  time: 1513640431.901740563  delta: .004467236
14.           163840 chars  time: 1513640431.907592388  delta: .005851825
15.           327680 chars  time: 1513640431.916233664  delta: .008641276
16.           655360 chars  time: 1513640431.930577599  delta: .014343935
17.          1310720 chars  time: 1513640431.954343112  delta: .023765513
18.          2621440 chars  time: 1513640431.999438581  delta: .045095469
19.          5242880 chars  time: 1513640432.086792464  delta: .087353883
20.         10485760 chars  time: 1513640432.278492932  delta: .191700468
21.         20971520 chars  time: 1513640432.672274631  delta: .393781699
22.         41943040 chars  time: 1513640433.456406517  delta: .784131886
23.         83886080 chars  time: 1513640435.012385162  delta: 1.555978645
24.        167772160 chars  time: 1513640438.103865613  delta: 3.091480451
25.        335544320 chars  time: 1513640444.267009677  delta: 6.163144064
./append_test.sh: fork: Cannot allocate memory

Test 2:

$ ./append_test.sh 2
Method: a+="$a"
 1.               20 chars  time: 1513640473.460480052  delta: 1513640473.460480052
 2.               40 chars  time: 1513640473.463738638  delta: .003258586
 3.               80 chars  time: 1513640473.466868613  delta: .003129975
 4.              160 chars  time: 1513640473.469948300  delta: .003079687
 5.              320 chars  time: 1513640473.473001255  delta: .003052955
 6.              640 chars  time: 1513640473.476086165  delta: .003084910
 7.             1280 chars  time: 1513640473.479196664  delta: .003110499
 8.             2560 chars  time: 1513640473.482355769  delta: .003159105
 9.             5120 chars  time: 1513640473.485495401  delta: .003139632
10.            10240 chars  time: 1513640473.488655040  delta: .003159639
11.            20480 chars  time: 1513640473.491946159  delta: .003291119
12.            40960 chars  time: 1513640473.495354094  delta: .003407935
13.            81920 chars  time: 1513640473.499138230  delta: .003784136
14.           163840 chars  time: 1513640473.503646917  delta: .004508687
15.           327680 chars  time: 1513640473.509647651  delta: .006000734
16.           655360 chars  time: 1513640473.518517787  delta: .008870136
17.          1310720 chars  time: 1513640473.533228130  delta: .014710343
18.          2621440 chars  time: 1513640473.560111613  delta: .026883483
19.          5242880 chars  time: 1513640473.606959569  delta: .046847956
20.         10485760 chars  time: 1513640473.699051712  delta: .092092143
21.         20971520 chars  time: 1513640473.898097661  delta: .199045949
22.         41943040 chars  time: 1513640474.299620758  delta: .401523097
23.         83886080 chars  time: 1513640475.092311556  delta: .792690798
24.        167772160 chars  time: 1513640476.660698221  delta: 1.568386665
25.        335544320 chars  time: 1513640479.776806227  delta: 3.116108006
./append_test.sh: fork: Cannot allocate memory

The errors indicate that my Bash got up to 335.54432 MB before it crashed. You could change the code from doubling the data to appending a constant to get a more granular graph and failure point. But I think this should give you enough information to decide whether you care. Personally, below 100 MB I don't. Your mileage may vary.


Yet another approach...

> H="Hello "
> U="$H""universe."
> echo $U
Hello universe.

...and yet yet another one.

> H="Hello "
> U=$H"universe."
> echo $U
Hello universe.

The simplest way with quotation marks:

B=Bar
b=bar
var="$B""$b""a"
echo "Hello ""$var"

You can concatenate without the quotes. Here is an example:

$Variable1 Open
$Variable2 Systems
$Variable3 $Variable1$Variable2
$echo $Variable3

This last statement would print "OpenSystems" (without quotes).

This is an example of a Bash script:

v1=hello
v2=world
v3="$v1       $v2"
echo $v3            # Output: hello world
echo "$v3"          # Output: hello       world

a="Hello,"
a=$a" World!"
echo $a

This is how you concatenate two strings.


Safer way:

a="AAAAAAAAAAAA"
b="BBBBBBBBBBBB"
c="CCCCCCCCCCCC"
d="DD DD"
s="${a}${b}${c}${d}"
echo "$s"
AAAAAAAAAAAABBBBBBBBBBBBCCCCCCCCCCCCDD DD

Strings containing spaces can become part of command, use "$XXX" and "${XXX}" to avoid these errors.

Plus take a look at other answer about +=


If you want to append something like an underscore, use escape (\)

FILEPATH=/opt/myfile

This does not work:

echo $FILEPATH_$DATEX

This works fine:

echo $FILEPATH\\_$DATEX

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

     


$ a=hip
$ b=hop
$ ab=$a$b
$ echo $ab
hiphop
$ echo $a$b
hiphop

Examples related to bash

Comparing a variable with a string python not working when redirecting from bash script Zipping a file in bash fails How do I prevent Conda from activating the base environment by default? Get first line of a shell command's output Fixing a systemd service 203/EXEC failure (no such file or directory) /bin/sh: apt-get: not found VSCode Change Default Terminal Run bash command on jenkins pipeline How to check if the docker engine and a docker container are running? How to switch Python versions in Terminal?

Examples related to shell

Comparing a variable with a string python not working when redirecting from bash script Get first line of a shell command's output How to run shell script file using nodejs? Run bash command on jenkins pipeline Way to create multiline comments in Bash? How to do multiline shell script in Ansible How to check if a file exists in a shell script How to check if an environment variable exists and get its value? Curl to return http status code along with the response docker entrypoint running bash script gets "permission denied"

Examples related to syntax

What is the 'open' keyword in Swift? Check if returned value is not null and if so assign it, in one line, with one method call Inline for loop What does %>% function mean in R? R - " missing value where TRUE/FALSE needed " Printing variables in Python 3.4 How to replace multiple patterns at once with sed? What's the meaning of "=>" (an arrow formed from equals & greater than) in JavaScript? How can I fix MySQL error #1064? What do >> and << mean in Python?

Examples related to concat

Merge two dataframes by index Concatenate a list of pandas dataframes together How do I concatenate strings in Swift? Adding two Java 8 streams, or an extra element to a stream MySQL CONCAT returns NULL if any field contain NULL How to concat two ArrayLists? Concat a string to SELECT * MySql How to use GROUP_CONCAT in a CONCAT in MySQL Which is the preferred way to concatenate a string in Python? Prepend text to beginning of string

Examples related to string-concatenation

How do I concatenate strings? How do I concatenate strings in Swift? How to set the id attribute of a HTML element dynamically with angularjs (1.x)? C++ String Concatenation operator<< how to use concatenate a fixed string and a variable in Python How do I concatenate strings and variables in PowerShell? Concatenating variables in Bash SQL NVARCHAR and VARCHAR Limits Concatenating string and integer in python PHP string concatenation