How to concatenate string variables in Bash
Solution 1
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
Solution 2
Bash also supports a +=
operator as shown in this code:
A="X Y"
A+=" Z"
echo "$A"
output
X Y Z
Solution 3
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
Solution 4
You can do this too:
$ var="myscript"
$ echo $var
myscript
$ var=${var}.sh
$ echo $var
myscript.sh
Solution 5
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.
Strawberry
I want to learn industry practices and apply them to my projects to make myself successful
Updated on July 08, 2022Comments
-
Strawberry almost 2 years
In PHP, strings are concatenated together as follows:
$foo = "Hello"; $foo .= " World";
Here,
$foo
becomes "Hello World".How is this accomplished in Bash?
-
parasrish about 6 years
foo="Hello"
foo=$foo" World"
echo $foo
this rather worked for "#!/bin/sh" -
Adi almost 6 yearsWhat to do if you want HelloWorld without space?
-
GeneCode about 5 years@Adi
foo1="World" foo2="Hello" foo3="$foo1$foo2"
-
Capibar almost 5 yearsspaces does a matter in bash)
-
Charlie Parker almost 3 yearsto give an example of inserting into a string do
echo "sh ${HOME}/ultimate-utils/run_tb.sh"
-
-
installero over 11 yearsI'm afraid this is not what was meant
-
Stefan about 11 yearsThis is the most useful answer for shell scripting. I have found myself the last 30 minutes because I had a space before and after the equal sign!!
-
user3383301 almost 11 yearsDoesn't work. I get "backupstorefolder: command not found" from bash where "backupstorefolder" is the name of a variable.
-
nonsensickle over 10 yearsDoes there have to be a space in your first example? Is it possible to do something like
foo="$fooworld"
? I would assume not... -
Nik O'Lai over 10 yearsthis happens because the underscore is the valid character in variable names, so bash sees foo_ as a variable. When it is necessary to tell bash the exact var name boundaries, the curly braces can be used: PREFIX_${foo}_$bar
-
Nik O'Lai over 10 yearsOr alternatively, ${FILEPATH}_$DATEX. Here {} are used to indicate the boundaries of the variable name. This is appropariate because the underscore is a legal character in variable names, so in your snippet bash actually tries to resolve FILEPATH_, not just $FILEPATH
-
twalberg about 10 years@nonsensickle That would look for a variable named
fooworld
. Disambiguating that is done with braces, as infoo="${foo}world"
... -
levesque about 10 yearsCan I use this syntax with the export keyword? e.g.
export A+="Z"
or maybe theA
variable only needs to be exported once? -
thkala about 10 years@levesque: Both :-). Variables only need to be exported once, but
export A+=Z
works quite nicely as well. -
F. Hauri - Give Up GitHub almost 10 yearsWhile no special chars, nor spaces are used, double quotes, quotes and curly brackets are useless:
var=myscript;var=$var.sh;echo $var
would have same effects (This work under bash, dash, busybox and others). -
F. Hauri - Give Up GitHub almost 10 yearsOn 1st line, you could drop a fork by using:
date "+The current time is %a %b %d %Y +%T"
, instead ofecho ...$(date)
. Under recent bash, you could write:printf "The current time is %(%a %b %d %Y +%T)T\n" -1
. -
techno over 9 yearsNice, But I think I could obtain more precision by using Python !
-
JVE999 over 9 years@twalberg I've found you can also use
foo=$foo'world'
-
twalberg over 9 years@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.
-
Mason Heller over 9 yearsOne 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'
. -
petersohn about 9 yearsThe problem with this solution is that it is very inefficient. the value of
$foo
is copied then the new value is appended, which takes a long time if the string is very long. It becomes especially apparent if you append strings in a loop, then the complexity of the loop becomes quadratic instead of linear. -
Score_Under about 9 yearsSince this is a bashism, I think it's worth a mention that you should never use
#!/bin/sh
in a script using this construction. -
Rho Phi almost 9 yearsThanks for pointing this out, I was just searching for which version is require for this to work.
-
M4tho over 8 yearsIf i use this code it gives me " world" as output. what can i do to fix this?
-
Ray Foss over 8 yearsThis helps syntax highlighting quite a bit, and removes some human ambiguity.
-
quimnuss over 8 yearsThat's what I did, and I found it so much simple and straight-forward than the other answers. Is there a reason nobody on the most voted answers pointed this option out?
-
Matt about 8 yearsThe
+=
operator is also much faster than$a="$a$b"
in my tests.. Which makes sense. -
Indrajeet Gour almost 8 yearsfor me I had one variable i.e. $var1 and constant next to this, so echo $var1_costant_traling_part works for me
-
geneorama almost 8 yearsThis answer is awesome, but I think it's missing the
var=${var}.sh
example from other answers, which is very useful. -
dashesy almost 8 yearsIs
bash
the only shell with+=
operator? I want to see if it is portable enough -
F. Hauri - Give Up GitHub almost 8 years@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! -
XXL over 7 yearsfoo="${foo}World"
-
jlliagre over 7 years@quimnuss The fact the strings do not match those used in the OP question might be a good reason.
-
Chaminda Bandara over 7 yearsCan't print as follows in a single write ?
echo 'User Name: $USER'
-
Fahad Naeem over 7 yearsIn addition to the answer: str="World" echo "Hello "$str. If you want to concatenate a constant string and a variable.
-
XavierStuvw over 7 yearsAlso
var3=$var1\ $var2
has the same effect -
XavierStuvw over 7 yearsToo many quotation marks, IMHO.
var=$B$b"a"; echo Hello\ $var
would do, I believe -
XavierStuvw over 7 yearsThe point of the strings with a space that are read as a command shows up at the point of definition. So
d=DD DD
would giveDD: command not found
--- note that is the last DD, rather d that is not found. If all operands are properly formatted and already contain the required spaces, you can simply concatenate withs=${a}${b}${c}${d}; echo $s
, with less quote marks. Also you could use\
(escaped whitespace) to avoid these issues ---d=echo\ echo
will not launch any echo invocation, whereasd=echo echo
will. -
XavierStuvw over 7 yearsThe syntax of the first block is confusing. What do these $ signs mean?
-
XavierStuvw over 7 yearsI guess one needs only one backlash for escaping:
echo $a\_$b
would do. As hinted in the comment of Nik O'Lai the underscore is a regular character. The handling of white spaces is much more sensitive for strings, echo and concatenation --- one can use\
and read this thread thoroughly as this issue comes back now and then. -
XavierStuvw over 7 years...hence
${a}\ World
producesHello World
-
phpguru over 7 yearsIt's specifically and only a plus-equals operator. That is, unlike Javascript, in Bash, echo $A+$B prints "X Y+Z"
-
codeaviator over 6 years@Score_Under What is a bashism? Thanks
-
Score_Under over 6 yearsA bashism is a shell feature which is only supported in
bash
and certain other more advanced shells. It will not work underbusybox sh
ordash
(which is/bin/sh
on a lot of distros), or certain other shells like the/bin/sh
provided on FreeBSD. -
JrBenito over 6 years
foo="$foo World"
this can be extremely slow if the made in a loop with large strings (string growing every iteration). In this case,+=
very very faster -
Bruno Bronosky over 6 yearsIf you are concerned about performance, see an analysis in my answer stackoverflow.com/a/47878161/117471
-
Bruno Bronosky over 6 yearsIf you are concerned about performance, see an analysis in my answer stackoverflow.com/a/47878161/117471
-
Danijel over 6 yearsNote: there are no spaces around
=
! This will not work:a ='hello'
, neither will this:a = ' hello'
, etc. -
Doktor J about 6 years@ChamindaBandara variables are not evaluated in single-quote strings. Use
echo "User Name: $USER"
instead (or better,echo "User Name: ${USER}"
). If you absolutely, positively must use single quotes, put the variable outside the single quotes, i.e.echo 'User Name: '$USER
. -
betontalpfa almost 6 yearsI suggest to use all of the quotation marks, cause if you put it everywhere you cannot miss, you dont have to think.
-
codeforester over 5 yearsCalling a function, that too in a subshell, is too much an overkill for a simple concat.
-
mwfearnley over 5 yearsThis surprises me; I would have expected
c=$a$b
here to do the same thing asc=$a World
(which would try to runWorld
as a command). I guess that means the assignment is parsed before the variables are expanded.. -
Anthony Rutledge almost 5 yearsThis works, but it will sometimes yield unpredictable results because the variable interpolation is not protected. Thus, you cannot rely on this form for all use cases.
-
Anthony Rutledge almost 5 yearsAre there any use cases where this might yield an unpredictable result? Would it be better to create a generic concat function, instead of hoping that the
+=
form does not hit an edge case? -
thkala almost 5 years@AnthonyRutledge: I am not aware of any edge cases, except for a script not actually using Bash by mistake. Even this works:
let A=1; A+=1; echo $A
- it prints11
, which is what you'd expect from a string concatenation operator. But I'd argue that if you are worried about edge cases, then you should probably use a "proper" programming language, maybe even one with a proper type system... -
Sergio A. over 4 years@XXL surely I'd rather use brackets to encapsulate var's name. Highly recommended
-
Pynchia over 4 years@F.Hauri thank you for pointing that out. But if you were to append a number, it would not work: e.g.
echo $var2
does not producemyscript2
-
F. Hauri - Give Up GitHub over 4 years@Pynchia This work because of the dot
.
illegal in variable name. If elseecho ${var}2
or see my answer -
ulkas over 4 yearsquite a lot of characters. i would use rather
$VAR1""$VAR2
. this way i save the curved brackets -
F. Hauri - Give Up GitHub about 4 yearsInteresting! Consider:
join <(LANG=C bash -c 'a="a" c=1 last=${EPOCHREALTIME//.};while :;do a+=$a;now=${EPOCHREALTIME//.};echo $((c++)) ${#a} $((now-last));last=$now;done') <(LANG=C bash -c 'a="a" c=1 last=${EPOCHREALTIME//.};while :;do a=$a$a;now=${EPOCHREALTIME//.};echo $((c++)) ${#a} $((now-last));last=$now;done')|sed -ue '1icnt strlen a+=$a a=$a$a' -e 's/^\([0-9]\+\) \([0-9]\+\) \([0-9]\+\) \2/\1 \2 \3/' | xargs printf "%4s %11s %9s %9s\n"
(Try this on not productive host!! ;) -
Solx almost 4 yearsI needed to use this += operator. I found that if I tried to put an underscore between the variables that bash would mistakenly think the name of the first variable included the underscore. Example if A=foo and B=bar, then $A$B is foobar, but $A_$B is only bar. Apparently thinks there is a variable named A_. Note that a dash works fine, meaning this case works as expected: $A-$B is foo-bar.
-
A. K. over 3 yearsThis is the correct answer IMO, because i was looking for concatenating without spaces, and += works like a charm.
-
MadScientist over 2 years@Solx you have to use
{}
if your variable reference is followed by another character that might be part of the variable name. Just write${A}_$B
and it will work fine in all shells. -
alper over 2 yearsCan I also use
echo -e
if I want to have newline in between strings as:c="${a}\n${b}"
-
F. Hauri - Give Up GitHub about 2 yearsPlaying with strings, see my function shrinkStr in Head & tail string in one line - possible?