Helpex - Trao đổi & giúp đỡ Đăng nhập
2371

Trong PHP, các chuỗi được nối với nhau như sau:

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

Ở đây, $footrở thành "Xin chào thế giới".

Làm thế nào điều này được thực hiện trong Bash?

2371 hữu ích 2 bình luận 3.1m xem chia sẻ
28 trả lời 28
3239
foo="Hello"
foo="$foo World"
echo $foo
> Hello World

Nói chung để nối hai biến, bạn chỉ có thể viết từng biến một:

a='hello'
b='world'
c="$a$b"
echo $c
> helloworld
3239 hữu ích 5 bình luận chia sẻ
1011

Bash cũng hỗ trợ một +=toán tử như trong mã này:

$ A="X Y"
$ A+=" Z"
$ echo "$A"
X Y Z
1011 hữu ích 5 bình luận chia sẻ
875

Bash đầu tiên

Vì câu hỏi này dành riêng cho Bash , phần đầu tiên của câu trả lời của tôi sẽ trình bày các cách khác nhau để làm điều này đúng:

+=: Nối vào biến

Cú pháp +=có thể được sử dụng theo những cách khác nhau:

Nối vào chuỗi var+=...

(Bởi vì tôi tằn tiện, tôi sẽ chỉ sử dụng hai biến fooavà sau đó tái sử dụng như nhau trong toàn bộ câu trả lời ;-).

a=2
a+=4
echo $a
24

Sử dụng cú pháp câu hỏi Stack Overflow ,

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

hoạt động tốt

Nối vào một số nguyên ((var+=...))

biến alà một chuỗi, nhưng cũng là một số nguyên

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

Nối vào một mảng var+=(...)

Chúng tôi acũng là một mảng chỉ có một yếu tố.

echo ${a[@]}
36

a+=(18)

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

Lưu ý rằng giữa các dấu ngoặc đơn, có một mảng được phân tách bằng dấu cách . Nếu bạn muốn lưu trữ một chuỗi chứa khoảng trắng trong mảng của mình, bạn phải kèm theo chúng:

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

Hmm .. đây không phải là một lỗi, mà là một tính năng ... Để ngăn bash cố gắng phát triển !", bạn có thể:

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: Xây dựng lại biến bằng lệnh dựng sẵn

Lệnh printf dựng sẵn cung cấp một cách mạnh mẽ để vẽ định dạng chuỗi. Vì đây là một nội dung Bash , có một tùy chọn để gửi chuỗi được định dạng tới một biến thay vì in trên stdout:

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

Có bảy chuỗi trong mảng này. Vì vậy, chúng ta có thể xây dựng một chuỗi được định dạng chứa chính xác bảy đối số vị trí:

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

Hoặc chúng ta có thể sử dụng một chuỗi định dạng đối số sẽ được lặp lại khi có nhiều đối số được gửi ...

Lưu ý rằng chúng tôi avẫn là một mảng! Chỉ có yếu tố đầu tiên được thay đổi!

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!")'

Trong bash, khi bạn truy cập một tên biến mà không chỉ định chỉ mục, bạn luôn chỉ xử lý phần tử đầu tiên!

Vì vậy, để lấy lại mảng bảy trường của chúng ta, chúng ta chỉ cần đặt lại phần tử thứ 1:

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!")'

Một chuỗi định dạng đối số có nhiều đối số được truyền cho:

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

Sử dụng cú pháp câu hỏi Stack Overflow :

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

Nota: Việc sử dụng hai dấu ngoặc kép có thể hữu ích cho các thao tác chuỗi có chứa spaces, tabulationsvà / hoặcnewlines

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

Shell bây giờ

Trong vỏ POSIX , bạn không thể sử dụng bashism , do đó không có nội dung dựng sẵn printf .

Về cơ bản

Nhưng bạn có thể chỉ cần làm:

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

Định dạng, sử dụng rẽ nhánh printf

Nếu bạn muốn sử dụng các công trình phức tạp hơn, bạn phải sử dụng một ngã ba (quy trình con mới thực hiện công việc và trả về kết quả thông qua stdout):

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

Trong lịch sử, bạn có thể sử dụng backticks để lấy kết quả của một ngã ba :

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

Nhưng điều này không dễ dàng để làm tổ :

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

với backticks, bạn phải thoát các nhánh bên trong bằng dấu gạch chéo ngược :

foo="Today is: "
foo=`printf "%s %s" "$foo" "\`date\`"`
echo $foo
Today is: Sun Aug 4 11:59:10 CEST 2013
875 hữu ích 4 bình luận chia sẻ
122

Bạn cũng có thể làm nó như vậy:

$ var="myscript"

$ echo $var

myscript


$ var=${var}.sh

$ echo $var

myscript.sh
122 hữu ích 1 bình luận chia sẻ
115
bla=hello
laber=kthx
echo "${bla}ohai${laber}bye"

Sẽ xuất

helloohaikthxbye

Điều này rất hữu ích khi $blaohai dẫn đến một biến không tìm thấy lỗi. Hoặc nếu bạn có khoảng trắng hoặc các ký tự đặc biệt khác trong chuỗi của bạn. "${foo}"đúng cách thoát khỏi bất cứ điều gì bạn đặt vào nó.

115 hữu ích 2 bình luận chia sẻ
40
foo="Hello "
foo="$foo World"

40 hữu ích 2 bình luận chia sẻ
32

Cách tôi giải quyết vấn đề chỉ là

$a$b

Ví dụ,

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

sản xuất

Hello World

Ví dụ: nếu bạn cố nối một chuỗi với một chuỗi khác,

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

sau đó echo "$c"sẽ sản xuất

Hello World

với một không gian thêm.

$aWorld

không hoạt động, như bạn có thể tưởng tượng, nhưng

${a}World

sản xuất

HelloWorld
32 hữu ích 2 bình luận chia sẻ
27
$ a=hip
$ b=hop
$ ab=$a$b
$ echo $ab
hiphop
$ echo $a$b
hiphop
27 hữu ích 0 bình luận chia sẻ
20

Nếu bạn muốn nối thêm một cái gì đó như dấu gạch dưới, hãy sử dụng esc (\)

FILEPATH=/opt/myfile

Điều này không hoạt động:

echo $FILEPATH_$DATEX

Điều này hoạt động tốt:

echo $FILEPATH\\_$DATEX
20 hữu ích 3 bình luận chia sẻ
20

Dưới đây là một bản tóm tắt ngắn gọn về những gì hầu hết các câu trả lời đang nói về.

Giả sử chúng ta có hai biến:

a=hello
b=world

Bảng dưới đây giải thích các bối cảnh khác nhau nơi chúng ta có thể kết hợp các giá trị abđể tạo một biến mới , 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, 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

Một vài lưu ý:

  • kèm theo RHS của một bài tập trong dấu ngoặc kép nói chung là một cách thực hành tốt, mặc dù nó khá tùy chọn trong nhiều trường hợp
  • += sẽ tốt hơn từ quan điểm hiệu suất nếu một chuỗi lớn đang được xây dựng theo từng bước nhỏ, đặc biệt là trong một vòng lặp
  • sử dụng {}xung quanh tên biến để phân tán sự mở rộng của chúng (như trong hàng 2 trong bảng trên)

Xem thêm:

20 hữu ích 1 bình luận chia sẻ
19

Một cách tiếp cận khác ...

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

... và còn một cái nữa.

> H="Hello "
> U=$H"universe."
> echo $U
Hello universe.
19 hữu ích 3 bình luận chia sẻ
15

Bạn có thể nối mà không có dấu ngoặc kép. Đây là một ví dụ:

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

Tuyên bố cuối cùng này sẽ in "OpenSystems" (không có dấu ngoặc kép).

Đây là một ví dụ về tập lệnh Bash:

v1=hello
v2=world
v3="$v1       $v2"
echo $v3            # Output: hello world
echo "$v3"          # Output: hello       world
15 hữu ích 1 bình luận chia sẻ
15

Cách đơn giản nhất với dấu ngoặc kép:

B=Bar
b=bar
var="$B""$b""a"
echo "Hello ""$var"
15 hữu ích 2 bình luận chia sẻ
14

Ngay cả khi toán tử + = hiện được phép, nó đã được giới thiệu trong Bash 3.1 năm 2004.

Bất kỳ tập lệnh nào sử dụng toán tử này trên các phiên bản Bash cũ hơn sẽ không thành công với lỗi "không tìm thấy lệnh" nếu bạn may mắn hoặc "lỗi cú pháp gần mã thông báo không mong muốn".

Đối với những người quan tâm đến khả năng tương thích ngược, hãy sử dụng các phương pháp nối Bash tiêu chuẩn cũ hơn, giống như các phương pháp được đề cập trong câu trả lời đã chọn:

foo="Hello"
foo="$foo World"
echo $foo
> Hello World
14 hữu ích 1 bình luận chia sẻ
13

Tôi thích sử dụng dấu ngoặc nhọn ${}để mở rộng biến trong chuỗi:

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

Dấu ngoặc nhọn sẽ phù hợp với việc sử dụng chuỗi liên tục:

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

Nếu không sử dụng foo = "$fooWorld"sẽ không hoạt động.

13 hữu ích 0 bình luận chia sẻ
7

Nếu những gì bạn đang cố gắng làm là chia một chuỗi thành nhiều dòng, bạn có thể sử dụng dấu gạch chéo ngược:

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

Với một khoảng trống ở giữa:

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

Điều này cũng chỉ thêm một không gian ở giữa:

$ a="hello \
>      world"
$ echo $a
hello world
7 hữu ích 1 bình luận chia sẻ
7

Cách an toàn hơn:

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

Các chuỗi chứa khoảng trắng có thể trở thành một phần của lệnh, sử dụng "$ XXX" và "$ {XXX}" để tránh các lỗi này.

Ngoài ra, hãy xem câu trả lời khác về + =

7 hữu ích 1 bình luận chia sẻ
6

Có một trường hợp cụ thể mà bạn nên quan tâm:

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

Sẽ đầu ra "daniel"san, và không danielsan, như bạn có thể muốn. Trong trường hợp này, bạn nên làm thay thế:

user=daniel
cat > output.file << EOF
${user}san
EOF
6 hữu ích 0 bình luận chia sẻ
5

Nếu nó là ví dụ của bạn về việc thêm " World"vào chuỗi gốc, thì nó có thể là:

#!/bin/bash

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

Đầu ra:

Hello World
5 hữu ích 0 bình luận chia sẻ
5
var1='hello'
var2='world'
var3=$var1" "$var2 
echo $var3
5 hữu ích 1 bình luận chia sẻ
4

Tôi muốn xây dựng một chuỗi từ một danh sách. Không thể tìm thấy câu trả lời cho điều đó vì vậy tôi đăng nó ở đây. Đây là những gì tôi đã làm:

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

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

echo ${string}

và sau đó tôi nhận được đầu ra sau:

1 2 3 4 5
4 hữu ích 0 bình luận chia sẻ
3

Lưu ý rằng điều này sẽ không hoạt động

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

vì nó dường như giảm $ foo và để lại cho bạn:

PREFIX_WORLD

nhưng điều này sẽ làm việc:

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

và để lại cho bạn đầu ra chính xác:

PREFIX_HELLO_WORLD

3 hữu ích 1 bình luận chia sẻ
3

Có những lo ngại về hiệu suất, nhưng không có dữ liệu được cung cấp. Hãy để tôi đề nghị một bài kiểm tra đơn giản.

(LƯU Ý: datetrên macOS không cung cấp nano giây, vì vậy điều này phải được thực hiện trên Linux.)

Tôi đã tạo append_test.sh trên GitHub với nội dung:

#!/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

Kiểm tra 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

Bài kiểm tra 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

Các lỗi chỉ ra rằng Bash của tôi đã lên tới 335.54432 MB trước khi nó bị hỏng. Bạn có thể thay đổi từ nhân đôi dữ liệu sang nối thêm hằng số để có được biểu đồ chi tiết hơn và điểm thất bại. Nhưng tôi nghĩ điều này sẽ cung cấp cho bạn đủ thông tin để quyết định xem bạn có quan tâm hay không. Cá nhân, dưới 100 MB tôi không. Số dặm của bạn có thể thay đổi.

3 hữu ích 0 bình luận chia sẻ
2
a="Hello,"
a=$a" World!"
echo $a

Đây là cách bạn nối hai chuỗi.

2 hữu ích 0 bình luận chia sẻ
1

Tôi làm theo cách này khi thuận tiện: Sử dụng lệnh nội tuyến!

echo "The current time is `date`"
echo "Current User: `echo $USER`"
1 hữu ích 1 bình luận chia sẻ
1

Đây là một trong những thông qua AWK :

$ foo="Hello"
$ foo=$(awk -v var=$foo 'BEGIN{print var" World"}')
$ echo $foo
Hello World
1 hữu ích 1 bình luận chia sẻ
1

Tôi giống như làm một chức năng nhanh chóng.

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

echo $(combo 'foo''bar')

Một cách khác để lột da một con mèo. Lần này với các chức năng: D

1 hữu ích 1 bình luận chia sẻ
1

Tôi chưa biết về PHP, nhưng điều này hoạt động trong Linux Bash. Nếu bạn không muốn ảnh hưởng đến biến đó, bạn có thể thử điều này:

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

>Hello World!

Bạn có thể đặt một biến khác thay vì 'Xin chào' hoặc '!'. Bạn cũng có thể nối nhiều chuỗi hơn.

1 hữu ích 1 bình luận chia sẻ
loading
Không tìm thấy câu trả lời bạn tìm kiếm? Duyệt qua các câu hỏi được gắn thẻ bash shell syntax concat string-concatenation , hoặc hỏi câu hỏi của bạn.

Có thể bạn quan tâm

loading