[英]How to concatenate string variables in Bash
In PHP, strings are concatenated together as follows:在 PHP 中,字符串按如下方式连接在一起:
$foo = "Hello";
$foo .= " World";
Here, $foo
becomes "Hello World".在这里, $foo
变成了“Hello World”。
How is this accomplished in Bash?这是如何在 Bash 中实现的?
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
Bash also supports a +=
operator as shown in this code: Bash 还支持+=
运算符,如以下代码所示:
A="X Y"
A+=" Z"
echo "$A"
output输出
XYZ XYZ
As this question stand specifically for Bash , my first part of the answer would present different ways of doing this properly:由于这个问题专门针对Bash ,我的第一部分答案将提出正确执行此操作的不同方法:
+=
: Append to variable +=
: 附加到变量The syntax +=
may be used in different ways:语法+=
可以以不同的方式使用:
var+=...
附加到字符串var+=...
(Because I am frugal, I will only use two variables foo
and a
and then re-use the same in the whole answer. ;-) (因为我很节俭,所以我只会使用两个变量foo
和a
,然后在整个答案中重复使用相同的变量。;-)
a=2
a+=4
echo $a
24
Using the Stack Overflow question syntax,使用Stack Overflow 问题语法,
foo="Hello"
foo+=" World"
echo $foo
Hello World
works fine!工作正常!
((var+=...))
附加到一个整数((var+=...))
variable a
is a string, but also an integer变量a
是一个字符串,但也是一个整数
echo $a
24
((a+=12))
echo $a
36
var+=(...)
追加到数组var+=(...)
Our a
is also an array of only one element.我们的a
也是一个只有一个元素的数组。
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:嗯..这不是一个错误,而是一个功能......为了防止 bash 尝试开发!"
,你可以:
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 printf
:使用内置命令重新构造变量The printf
builtin command gives a powerful way of drawing string format. printf
内置命令提供了一种绘制字符串格式的强大方法。 As this is a Bash builtin , there is a option for sending formatted string to a variable instead of printing on stdout
:由于这是一个 Bash内置函数,因此可以选择将格式化字符串发送到变量而不是在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!请注意,我们的a
仍然是一个数组! 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!在 bash 下,当您访问变量名而不指定索引时,您总是只寻址第一个元素!
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!>
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
注意:双引号的使用可能有助于处理包含spaces
、 tabulations
newlines
和/或newlines
字符串
printf -v foo "%s World" "$foo"
Under POSIX shell, you could not use bashisms , so there is no builtin printf
.在POSIX shell 下,您不能使用bashisms ,因此没有内置printf
。
But you could simply do:但你可以简单地做:
foo="Hello"
foo="$foo World"
echo $foo
Hello World
printf
格式化,使用分叉的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
):如果你想使用更复杂的结构,你必须使用一个fork (新的子进程完成工作并通过stdout
返回结果):
foo="Hello"
foo=$(printf "%s World" "$foo")
echo $foo
Hello World
Historically, you could use backticks for retrieving result of a fork :从历史上看,您可以使用反引号来检索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
You can do this too:你也可以这样做:
$ var="myscript"
$ echo $var
myscript
$ var=${var}.sh
$ echo $var
myscript.sh
bla=hello
laber=kthx
echo "${bla}ohai${laber}bye"
Will output会输出
helloohaikthxbye
This is useful when $blaohai
leads to a variable not found error.当$blaohai
导致变量未找到错误时,这很有用。 Or if you have spaces or other special characters in your strings.或者,如果您的字符串中有空格或其他特殊字符。 "${foo}"
properly escapes anything you put into it. "${foo}"
正确地转义了您放入其中的任何内容。
foo="Hello "
foo="$foo World"
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':假设我们有两个变量,并且 $1 设置为“一”:
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
.下表解释了我们可以组合a
和b
的值以创建新变量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:一些注意事项:
+=
is better from a performance standpoint if a big string is being constructed in small increments, especially in a loop如果以小增量构造大字符串,尤其是在循环中,则从性能的角度来看+=
会更好{}
around variable names to disambiguate their expansion (as in row 2 in the table above).在变量名称周围使用{}
以消除其扩展的歧义(如上表中的第 2 行)。 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.如第 3 行和第 4 行所示,不需要{}
除非变量与以 shell 变量名称中有效第一个字符(即字母表或下划线)开头的字符串连接。See also:也可以看看:
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然后echo "$c"
将产生
Hello World
with an extra space.有额外的空间。
$aWorld
doesn't work, as you may imagine, but不工作,正如你想象的那样,但是
${a}World
produces产生
HelloWorld
$ a=hip
$ b=hop
$ ab=$a$b
$ echo $ab
hiphop
$ echo $a$b
hiphop
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.
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
The simplest way with quotation marks:带引号的最简单方法:
B=Bar
b=bar
var="$B""$b""a"
echo "Hello ""$var"
Even if the += operator is now permitted, it has been introduced in Bash 3.1 in 2004.即使现在允许使用 += 运算符,它也已在 2004 年的Bash 3.1中引入。
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".如果幸运的话,在较旧的 Bash 版本上使用此运算符的任何脚本都将失败,并显示“未找到命令”错误,或者“意外标记附近的语法错误”。
For those who cares about backward compatibility, stick with the older standard Bash concatenation methods, like those mentioned in the chosen answer:对于那些关心向后兼容性的人,请坚持使用较旧的标准 Bash 连接方法,如所选答案中提到的方法:
foo="Hello"
foo="$foo World"
echo $foo
> Hello World
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).最后一条语句将打印“OpenSystems”(不带引号)。
This is an example of a Bash script:这是 Bash 脚本的示例:
v1=hello
v2=world
v3="$v1 $v2"
echo $v3 # Output: hello world
echo "$v3" # Output: hello world
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.否则使用foo = "$fooWorld"
将不起作用。
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
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.包含空格的字符串可以成为命令的一部分,使用“$XXX”和“${XXX}”来避免这些错误。
Plus take a look at other answer about +=另外看看关于+= 的其他答案
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.将输出"daniel"san
,而不是您可能想要的danielsan
。 In this case you should do instead:在这种情况下,您应该改为:
user=daniel
cat > output.file << EOF
${user}san
EOF
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.如果可能,请避免它。
a="Hello,"
a=$a" World!"
echo $a
This is how you concatenate two strings.这就是连接两个字符串的方式。
If it is as your example of adding " World"
to the original string, then it can be:如果是将" World"
添加到原始字符串的示例,则可以是:
#!/bin/bash
foo="Hello"
foo=$foo" World"
echo $foo
The output:输出:
Hello World
var1='hello'
var2='world'
var3=$var1" "$var2
echo $var3
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.) (注意:macOS 上的date
不提供纳秒,因此这必须在 Linux 上完成。)
I have created append_test.sh on GitHub with the contents:我在 GitHub 上创建了append_test.sh的内容:
#!/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:测试 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:测试 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.错误表明我的 Bash 在崩溃之前达到了335.54432 MB 。 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.就个人而言,低于 100 MB 我没有。 Your mileage may vary.你的旅费可能会改变。
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
Note that this won't work请注意,这将不起作用
foo=HELLO
bar=WORLD
foobar=PREFIX_$foo_$bar
as it seems to drop $foo and leaves you with:因为它似乎放弃了 $foo 并给你留下了:
PREFIX_WORLD PREFIX_WORLD
but this will work:但这会起作用:
foobar=PREFIX_"$foo"_"$bar"
and leave you with the correct output:并为您留下正确的输出:
PREFIX_HELLO_WORLD PREFIX_HELLO_WORLD
Variables and arrays (indexed or associative*) in bash are always strings by default, but you can use flags to the declare
builtin, to give them attributes like "integer" ( -i
) or "reference"** ( -n
), which change the way they behave. bash 中的变量和数组(索引或关联*)在默认情况下始终是字符串,但您可以使用declare
内置函数的标志,为它们提供诸如“整数”( -i
)或“引用”**( -n
)之类的属性,这改变了他们的行为方式。
Bash arithmetic accepts ASCII/string numbers for input, so there are few reasons to actually use the integer attribute. Bash 算法接受 ASCII/字符串数字作为输入,因此实际使用整数属性的理由很少。
Also, variable values can't contain ASCII NULL
(ie. 8 bit zero), because regular null terminated C strings are used to implement them.此外,变量值不能包含 ASCII NULL
(即 8 位零),因为使用常规的空终止 C 字符串来实现它们。
* Ie one or more key + value pairs. * 即一个或多个键+值对。
** Reference variables expand to the value of another variable, whose label is assigned to the reference variable ** 引用变量扩展为另一个变量的值,其标签分配给引用变量
Append a string:附加一个字符串:
$ foo=Hello
$ foo+=' world!'
$ echo "$foo"
Hello world!
$ num=3
$ num+=4
echo "$num"
34 # Appended string (not a sum)
One of the few reasons to use the integer attribute, is that it changes the behaviour of the +=
assignment operator:使用 integer 属性的少数原因之一是它改变了+=
赋值运算符的行为:
$ declare -i num=3
$ num+=4
echo "$num"
7 # Sum
Note that this doesn't work for -=
, /=
, etc. unless you do it inside arithmetic ( (( ))
and $(( ))
), where numbers are already treated the same with or without the integer attribute.请注意,这不适用于-=
、 /=
等,除非您在算术( (( ))
和$(( ))
)中执行此操作,其中无论是否使用 integer 属性,数字都已被视为相同。 See the section "arithmetic evaluation" of man bash
for a full list of those operators, which are the same as for C.有关这些运算符的完整列表,请参阅man bash
“算术评估”部分,这些运算符与 C 相同。
The +=
assignment operator can also be used to append new elements to an indexed array (AKA "list"): +=
赋值运算符还可用于将新元素附加到索引数组(又名“列表”):
$ foo=(one)
$ foo+=(two)
$ printf 'Separate element: %s\n' "${foo[@]}"
Separate element: one
Separate element: two
Another common way to do this is to use a counter:另一种常见的方法是使用计数器:
$ foo[c++]=one
$ foo[c++]=two
POSIX shells do not use the +=
assignment operator to append strings , so you have to do it like this: POSIX shell不使用+=
赋值运算符来附加 strings ,因此您必须这样做:
$ foo=Hello
$ foo="$foo world!"
$ echo "$foo"
Hello world!
This is fine in bash
too, so it could be considered a more portable syntax.这在bash
也很好,所以它可以被认为是一种更便携的语法。
I do it this way when convenient: Use an inline command!我在方便时这样做:使用内联命令!
echo "The current time is `date`"
echo "Current User: `echo $USER`"
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
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这次有函数:D
In PHP, strings are concatenated together as follows:在PHP中,字符串按以下方式串联在一起:
$foo = "Hello";
$foo .= " World";
Here, $foo
becomes "Hello World".在这里, $foo
变成“ Hello World”。
How is this accomplished in Bash?如何在Bash中完成?
You can try the below way. 您可以尝试以下方式。 When substitution takes place, double quotes will keep the spaces. 当替换发生时,双引号将保留空格。
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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.