关于shell:如何在bash中连接字符串变量

How to concatenate string variables in Bash

在PHP中,字符串按如下方式连接在一起:

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

在这里,$foo变成了"你好世界"。

这是如何在bash中完成的?


1
2
3
4
foo="Hello"
foo="$foo World"
echo $foo
> Hello World

一般来说,要连接两个变量,您可以一个接一个地编写它们:

1
2
3
4
5
a='hello'
b='world'
c="$a$b"
echo $c
> helloworld


bash还支持+=操作符,如以下代码所示:

1
2
3
4
$ A="X Y"
$ A+=" Z"
$ echo"$A"
X Y Z


猛击第一

因为这个问题专门代表bash,所以我的第一部分答案将给出正确执行此操作的不同方法:

+=:追加到变量

语法+=可以用不同的方式使用:

追加到字符串EDOCX1[5]

(因为我节俭,我只使用两个变量fooa,然后在整个答案中重复使用相同的变量。;-)

1
2
3
4
a=2
a+=4
echo $a
24

使用堆栈溢出问题语法,

1
2
3
4
foo="Hello"
foo+=" World"
echo $foo
Hello World

工作很好!

附加到整数EDOCX1[8]

变量a是一个字符串,也是一个整数。

1
2
3
4
5
echo $a
24
((a+=12))
echo $a
36

追加到数组EDOCX1[10]

我们的a也是一个只有一个元素的数组。

1
2
3
4
5
6
7
8
9
10
11
echo ${a[@]}
36

a+=(18)

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

注意在括号之间有一个空格分隔的数组。如果要在数组中存储包含空格的字符串,则必须将它们括起来:

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

隐马尔可夫模型。。这不是一个bug,而是一个特性…为了防止bash尝试开发!",您可以:

1
2
3
4
5
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:使用builtin命令重新构造变量

printf内置命令提供了一种绘制字符串格式的强大方法。因为这是bash内置的,所以有一个选项可以将格式化字符串发送到变量,而不是在stdout上打印:

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

这个数组中有七个字符串。因此,我们可以构建一个格式字符串,其中正好包含七个位置参数:

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

或者我们可以使用一个参数格式字符串,该字符串将重复提交的参数…

注意,我们的a仍然是一个数组!只更改第一个元素!

1
2
3
4
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!")'

在bash下,当您在不指定索引的情况下访问变量名时,总是只处理第一个元素!

因此,要检索七个字段数组,只需重新设置第一个元素:

1
2
3
4
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!")'

一个参数格式字符串,多个参数传递给:

1
2
3
4
5
6
7
8
9
10
printf -v a[0] '<%s>
'
"${a[@]}"
echo"$a"
<36>
<18>
<one>
<word>
<hello world!>
<hello world!>
<hello world!>

使用堆栈溢出问题语法:

1
2
3
4
foo="Hello"
printf -v foo"%s World" $foo
echo $foo
Hello World

注:使用双引号可能有助于操作包含spacestabulations和/或newlines的字符串。

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

贝壳现在

在posix shell下,不能使用bashims,因此没有内置的printf

基本上

但你可以简单地做到:

1
2
3
4
foo="Hello"
foo="$foo World"
echo $foo
Hello World

格式化,使用分叉printf

如果要使用更复杂的结构,则必须使用fork(新的子进程,该进程生成作业并通过stdout返回结果):

1
2
3
4
foo="Hello"
foo=$(printf"%s World""$foo")
echo $foo
Hello World

历史上,您可以使用backticks来检索fork的结果:

1
2
3
4
foo="Hello"
foo=`printf"%s World""$foo"`
echo $foo
Hello World

但这并不容易筑巢:

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

用反勾号,你必须用反斜杠从内部叉子中逃脱:

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


您也可以这样做:

1
2
3
4
5
6
7
8
9
10
11
12
$ var="myscript"

$ echo $var

myscript


$ var=${var}.sh

$ echo $var

myscript.sh


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

意志输出

1
helloohaikthxbye

$blaohai导致变量找不到错误。或者字符串中有空格或其他特殊字符。"${foo}"正确地避开你放进去的任何东西。


1
2
foo="Hello"
foo="$foo World"

&(二)


我解决这个问题的方法只是

1
$a$b

例如,

1
2
3
4
a="Hello"
b=" World"
c=$a$b
echo"$c"

产生

1
Hello World

例如,如果您试图将一个字符串与另一个字符串连接起来,

1
2
a="Hello"
c="$a World"

那么,echo"$c"将产生

1
Hello World

有额外的空间。

1
$aWorld

不起作用,你可以想象,但是

1
${a}World

生产

1
HelloWorld


1
2
3
4
5
6
7
$ a=hip
$ b=hop
$ ab=$a$b
$ echo $ab
hiphop
$ echo $a$b
hiphop

如果要附加下划线之类的内容,请使用转义()

1
FILEPATH=/opt/myfile

这不起作用:

1
echo $FILEPATH_$DATEX

这很好用:

1
echo $FILEPATH\\_$DATEX


以下是对大多数答案的简要总结。

假设我们有两个变量:

1
2
a=hello
b=world

下表解释了不同的上下文,我们可以将ab的值结合起来创建一个新的变量c

1
2
3
4
5
6
7
8
Context                               | Expression            | Result (value of c)
--------------------------------------+-----------------------+---------------------
Two variables                         | c=$a$b                | helloworld
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

几点注意事项

  • 用双引号括住赋值的rhs通常是一个很好的实践,尽管在许多情况下它是非常可选的。
  • 如果一个大字符串以较小的增量(尤其是在循环中)构造,那么从性能角度来看,+=更好。
  • 在变量名周围使用{}消除变量扩展的歧义(如上表第2行所示)。

参见:

  • bashfaq/013-如何连接两个变量?
  • 我们什么时候需要在shell变量周围使用大括号?


另一种方法…

1
2
3
4
> H="Hello"
> U="$H""universe."
> echo $U
Hello universe.

…还有另一个。

1
2
3
4
> H="Hello"
> U=$H"universe."
> echo $U
Hello universe.


使用引号的最简单方法:

1
2
3
4
B=Bar
b=bar
var="$B""$b""a"
echo"Hello""$var"


您可以不带引号地连接。下面是一个例子:

1
2
3
4
$Variable1 Open
$Variable2 Systems
$Variable3 $Variable1$Variable2
$echo $Variable3

最后一条语句将打印"OpenSystems"(不带引号)。

这是bash脚本的一个示例:

1
2
3
4
5
v1=hello
v2=world
v3="$v1       $v2"
echo $v3            # Output: hello world
echo"$v3"          # Output: hello       world


即使现在允许使用+=操作符,2004年bash 3.1中也引入了它。

在旧的bash版本上使用此运算符的任何脚本都将失败,如果幸运的话,将出现"command not found"错误,或者出现"syntax error near unexpected token"。

对于那些关心向后兼容性的人,请坚持使用旧的标准bash连接方法,如所选答案中提到的方法:

1
2
3
4
foo="Hello"
foo="$foo World"
echo $foo
> Hello World


我喜欢使用花括号${}来扩展字符串中的变量:

1
2
3
4
foo="Hello"
foo="${foo} World"
echo $foo
> Hello World

大括号将适合连续使用字符串:

1
2
3
4
foo="Hello"
foo="${foo}World"
echo $foo
> HelloWorld

否则,使用foo ="$fooWorld"将不起作用。


如果您要做的是将字符串拆分为多行,则可以使用反斜杠:

1
2
3
4
$ a="hello\
> world"

$ echo $a
helloworld

中间有一个空格:

1
2
3
4
$ a="hello \
> world"

$ echo $a
hello world

这一个只在中间添加了一个空格:

1
2
3
4
$ a="hello \
>      world"

$ echo $a
hello world


更安全的方式:

1
2
3
4
5
6
7
a="AAAAAAAAAAAA"
b="BBBBBBBBBBBB"
c="CCCCCCCCCCCC"
d="DD DD"
s="${a}${b}${c}${d}"
echo"$s"
AAAAAAAAAAAABBBBBBBBBBBBCCCCCCCCCCCCDD DD

包含空格的字符串可以成为命令的一部分,请使用"$XXX"和"$XXX"避免这些错误。

再看看其他答案+=


有一个特别的情况,你应该注意:

1
2
3
4
user=daniel
cat > output.file << EOF
"$user"san
EOF

将输出"daniel"san,而不是danielsan,正如您可能想要的那样。在这种情况下,您应该这样做:

1
2
3
4
user=daniel
cat > output.file << EOF
${user}san
EOF

如果是将" World"添加到原始字符串的示例,则可以是:

1
2
3
4
5
#!/bin/bash

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

输出:

1
Hello World


1
2
3
4
var1='hello'
var2='world'
var3=$var1""$var2
echo $var3


我想从列表中构建一个字符串。找不到答案,所以我把它贴在这里。以下是我所做的:

1
2
3
4
5
6
7
8
list=(1 2 3 4 5)
string=''

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

echo ${string}

然后我得到以下输出:

1
1 2 3 4 5

注意这不管用

1
2
3
foo=HELLO
bar=WORLD
foobar=PREFIX_$foo_$bar

因为它好像掉了$foo,留给你:

PREFIX_WORLD

但这是可行的:

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

并为您提供正确的输出:

PREFIX_HELLO_WORLD


1
2
3
a="Hello,"
a=$a" World!"
echo $a

这是连接两个字符串的方法。


有人对性能表示担忧,但没有提供任何数据。我建议你做一个简单的测试。

(注:MacOS上的date不提供纳秒,因此必须在Linux上完成。)

我在Github上创建了append_test.sh,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/bin/bash -e

output(){
    ptime=$ctime;
    ctime=$(date +%s.%N);
    delta=$(bc <<<"$ctime - $ptime");
    printf"%2s. %16s chars  time: %s  delta: %s
"
$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

试验1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
$ ./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

试验2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
$ ./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

错误表明我的bash在崩溃前达到335.54432 MB。您可以将代码从加倍数据改为附加常量,以获得更细粒度的图形和故障点。但我认为这应该给你足够的信息来决定你是否在乎。个人而言,低于100兆我不知道。您的里程可能会有所不同。


我在方便的时候这样做:使用一个内联命令!

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


这是一个通过awk:

1
2
3
4
5
6
7
8
9
10
11
12
13
$ foo="Hello"
$ foo=$(awk -v var=$foo 'BEGIN{print var" World
<div class="suo-content">[collapse title=""]<ul><li>很好,但我想我可以通过使用python获得更高的精度!</li></ul>[/collapse]</div><hr>
<p>
I kind of like making a quick function.
</p>

[cc lang="bash"]#! /bin/sh -f
function combo() {
    echo $@
}

echo $(combo '
foo''bar')

另一种剥猫皮的方法。这次功能:d


我还不知道PHP,但它在LinuxBash中工作。如果不想将其影响到变量,可以尝试以下操作:

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

>Hello World!

您可以放置另一个变量,而不是"hello"或"!"。您也可以连接更多的字符串。


你可以试试下面的方法。当替换发生时,双引号将保留空格。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var1="Ram"    
var2="Lakshmana"
echo $var1$var2
or
echo var1+=$var2"bash support += operation.

bcsmc2rtese001 [/tmp]$ var1="
Ram"  
bcsmc2rtese001 [/tmp]$ var2="
Lakshmana"  
bcsmc2rtese001 [/tmp]$ echo $var1$var2  
Ram Lakshmana  

bcsmc2rtese001 [/tmp]$ var1+=$var2  
bcsmc2rtese001 [/tmp]$ echo $var1  
Ram Lakshmana