วิธีการเชื่อมสตริงตัวแปรใน Bash


2767

ใน PHP สตริงจะถูกรวมเข้าด้วยกันดังนี้:

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

ที่นี่$fooกลายเป็น "Hello World"

สิ่งนี้สำเร็จได้อย่างไรใน Bash


6
foo="Hello" foo=$foo" World" echo $foo สิ่งนี้ค่อนข้างใช้ได้กับ "#! / bin / sh"
parasrish

1
จะทำอย่างไรถ้าคุณต้องการให้ HelloWorld ไม่มีที่ว่าง?
Adi

@Adifoo1="World" foo2="Hello" foo3="$foo1$foo2"
GeneCode

ช่องว่างมีความหมายในการทุบตี)
238

คำตอบ:


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

โดยทั่วไปแล้วการรวมสองตัวแปรเข้าด้วยกันคุณสามารถเขียนมันทีละตัว:

a='Hello'
b='World'
c="${a} ${b}"
echo "${c}"
> Hello World

314
น่าจะดีที่จะได้ติดนิสัยในการใส่$fooเครื่องหมายคำพูดคู่สำหรับเวลาที่มันสำคัญจริงๆ
Cascabel

104
เราถูกสอนให้ทำเช่นนั้นเสมอเพราะเมื่อมีการแทนที่เกิดขึ้นช่องว่างจะถูกละเว้นโดยเชลล์ แต่เครื่องหมายคำพูดคู่จะป้องกันช่องว่างเหล่านั้นเสมอ
สตรอเบอร์รี่

62
ต้องมีช่องว่างในตัวอย่างแรกของคุณหรือไม่? เป็นไปได้ไหมที่จะทำอะไรแบบนี้foo="$fooworld"? ฉันจะถือว่าไม่ได้ ...
nonsensickle

341
@nonsensickle fooworldที่จะมองหาชื่อตัวแปร Disambiguating ที่ทำด้วยเหล็กดัดฟันดังเช่นในfoo="${foo}world"...
twalberg

4
@ JVE999 ใช่มันใช้งานได้ดีแม้ว่าในความคิดของฉันมันไม่ดีสำหรับความชัดเจนของรหัส ... แต่นั่นอาจเป็นความชอบของฉัน ... มีอีกสองวิธีที่สามารถทำได้เช่นกัน - ประเด็นคือ ตรวจสอบให้แน่ใจว่าชื่อตัวแปรถูกแยกออกจากส่วนที่ไม่ใช่ชื่อตัวแปรเพื่อให้แยกวิเคราะห์ได้อย่างถูกต้อง
twalberg

1127

Bash ยังรองรับ+=โอเปอเรเตอร์ดังที่แสดงในรหัสนี้:

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

2
ฉันสามารถใช้ไวยากรณ์นี้กับคำหลักส่งออกได้หรือไม่ เช่นexport A+="Z"หรืออาจAจะต้องส่งออกตัวแปรเพียงครั้งเดียว
levesque

3
@levesque: ทั้งสอง :-) ตัวแปรจะต้องส่งออกเพียงครั้งเดียว แต่ก็ใช้export A+=Zงานได้ดีเช่นกัน
thkala

38
ฉันคิดว่ามันคุ้มค่าที่จะกล่าวถึงว่าคุณไม่ควรใช้#!/bin/shสคริปต์ในการสร้างสิ่งนี้
คะแนน _ ต่ำกว่า

2
มันเป็นตัวดำเนินการเฉพาะและเป็นบวกเท่านั้น นั่นคือไม่เหมือน Javascript ใน Bash echo $ A + $ B พิมพ์ "X Y + Z"
phpguru

6
bashism เป็นคุณสมบัติของเชลล์ที่สนับสนุนbashและเชลล์ระดับสูงอื่น ๆ เท่านั้น มันจะไม่ทำงานภายใต้busybox shหรือdash(ซึ่ง/bin/shมีจำนวนมาก distros) หรือกระสุนอื่น ๆ บางอย่างเช่นที่/bin/shมีให้ใน FreeBSD
คะแนน _ ต่ำกว่า

960

ทุบตีก่อน

เมื่อคำถามนี้ตรงกับBashโดยเฉพาะส่วนแรกของคำตอบจะนำเสนอวิธีที่แตกต่างในการทำสิ่งนี้อย่างถูกต้อง:

+=: ผนวกเข้ากับตัวแปร

ไวยากรณ์+=อาจถูกใช้ในวิธีที่ต่างกัน:

ต่อท้ายสตริง var+=...

(เพราะฉันประหยัดฉันจะใช้สองตัวแปรfooและaแล้วกลับมาใช้เหมือนกันในคำตอบทั้งหมด. ;-)

a=2
a+=4
echo $a
24

การใช้ไวยากรณ์คำถาม Stack Overflow

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

ทำงานได้ดี!

ผนวกเข้ากับจำนวนเต็ม ((var+=...))

ตัวแปรaเป็นสตริง แต่ยังเป็นจำนวนเต็ม

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

ผนวกเข้ากับอาร์เรย์ var+=(...)

เราaยังเป็นอาร์เรย์ขององค์ประกอบเดียวเท่านั้น

echo ${a[@]}
36

a+=(18)

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

หมายเหตุว่าระหว่างวงเล็บมีพื้นที่แยกอาร์เรย์ หากคุณต้องการเก็บสตริงที่มีช่องว่างในอาเรย์ของคุณคุณต้องใส่มันเข้าไป:

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

อืม .. นี่ไม่ใช่ข้อผิดพลาด แต่เป็นคุณสมบัติ ... เพื่อป้องกันการทุบตีเพื่อพยายามพัฒนา!"คุณสามารถ:

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 builtinคำสั่งให้วิธีที่มีประสิทธิภาพของการวาดรูปแบบสตริง เนื่องจากนี่เป็น Bash builtinจึงมีตัวเลือกสำหรับส่งสตริงที่จัดรูปแบบไปยังตัวแปรแทนที่จะพิมพ์บนstdout:

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

มีเจ็ดสายในอาร์เรย์นี้ ดังนั้นเราสามารถสร้างสตริงที่จัดรูปแบบที่มีข้อโต้แย้งตำแหน่งเจ็ดประการ:

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

หรือเราสามารถใช้รูปแบบอาร์กิวเมนต์หนึ่งสตริงซึ่งจะทำซ้ำเป็นจำนวนมากส่ง ...

โปรดทราบว่าเราaยังคงเป็นอาร์เรย์! มีการเปลี่ยนแปลงองค์ประกอบแรกเท่านั้น!

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 อีกครั้ง:

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

สตริงรูปแบบอาร์กิวเมนต์หนึ่งสตริงที่มีอาร์กิวเมนต์จำนวนมากส่งผ่านไปยัง:

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

การใช้ไวยากรณ์คำถาม Stack Overflow :

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

หมายเหตุ: การใช้ราคาสองครั้งอาจจะมีประโยชน์สำหรับการจัดการสตริงที่มีspaces, tabulationsและ / หรือnewlines

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

เชลล์ตอนนี้

ภายใต้POSIXเปลือกคุณไม่สามารถใช้bashismsดังนั้นไม่มีbuiltin printf

เป็นพื้น

แต่คุณสามารถทำได้:

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

จัดรูปแบบโดยใช้ทางแยก printf

หากคุณต้องการใช้สิ่งปลูกสร้างที่ซับซ้อนมากขึ้นคุณต้องใช้ทางแยก (กระบวนการลูกใหม่ที่ทำให้งานและส่งคืนผลลัพธ์ผ่านstdout):

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

ในอดีตคุณสามารถใช้backticksเพื่อดึงผลลัพธ์ของfork :

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

แต่นี่ไม่ใช่เรื่องง่ายสำหรับการทำรัง :

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

ด้วย backticks คุณต้องหลบหนีจากส้อมด้านในด้วยแบ็กสแลช :

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

4
+=ผู้ประกอบการยังจะเร็วกว่า$a="$a$b"ในการทดสอบของฉัน .. ซึ่งทำให้รู้สึก
Matt

7
คำตอบนี้ยอดเยี่ยม แต่ฉันคิดว่ามันไม่มีvar=${var}.shตัวอย่างจากคำตอบอื่นซึ่งมีประโยชน์มาก
genorama

1
เป็นbashเชลล์ตัวเดียวที่มี+=โอเปอเรเตอร์หรือไม่ ฉันต้องการที่จะดูว่ามันพกพาได้หรือไม่
2559

1
@dashesy ไม่ ฉันไม่ได้เป็นเพียงเปลือกหอยที่มี+=ตัวดำเนินการเท่านั้น แต่วิธีทั้งหมดนี้เป็นการทุบตีดังนั้นจึงไม่พกพาได้! แม้คุณสามารถพบข้อผิดพลาดพิเศษในกรณีที่ทุบตีรุ่นผิด
F. Hauri

134

คุณสามารถทำได้เช่นกัน:

$ var="myscript"

$ echo $var

myscript


$ var=${var}.sh

$ echo $var

myscript.sh

4
ในขณะที่ไม่ใช้ตัวอักษรพิเศษหรือช่องว่างเครื่องหมายคำพูดคู่และเครื่องหมายปีกกาจะไม่มีประโยชน์: var=myscript;var=$var.sh;echo $varจะมีเอฟเฟกต์เหมือนกัน
F. Hauri

@ F.Hauri ขอบคุณที่ชี้ให้เห็น แต่ถ้าคุณจะผนวกตัวเลขมันจะไม่ทำงาน: เช่นecho $var2ไม่ผลิตmyscript2
Pynchia

@Pynchia งานนี้เพราะจุด.ผิดกฎหมายในชื่อตัวแปร ถ้าอย่างอื่นecho ${var}2หรือดูคำตอบของฉัน
F. Hauri

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

จะส่งออก

helloohaikthxbye

สิ่งนี้มีประโยชน์เมื่อ $blaohai นำไปสู่ข้อผิดพลาดที่ไม่พบตัวแปร หรือถ้าคุณมีช่องว่างหรืออักขระพิเศษอื่น ๆ ในสตริงของคุณ "${foo}"หลบหนีสิ่งที่คุณใส่ไว้อย่างถูกต้อง


3
ใช้งานไม่ได้ ฉันได้รับ "backupstorefolder: ไม่พบคำสั่ง" จาก bash โดยที่ "backupstorefolder" เป็นชื่อของตัวแปร
Zian Choy

7
สิ่งนี้ช่วยให้ไวยากรณ์เน้นความสำคัญได้เล็กน้อยและขจัดความคลุมเครือของมนุษย์ออกไป
เรย์ฟอสส์

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

     


10
นี่เป็นคำตอบที่มีประโยชน์ที่สุดสำหรับเชลล์สคริปต์ ฉันพบว่าตัวเอง 30 นาทีสุดท้ายเพราะฉันมีพื้นที่ก่อนและหลังเครื่องหมายเท่ากับ !!
สเตฟาน

8
foo = "$ {foo} World"
XXL

@XXL แน่นอนฉันควรใช้เครื่องหมายวงเล็บในการสรุปชื่อของ var แนะนำเป็นอย่างยิ่ง
Sergio A.

33

วิธีที่ฉันจะแก้ปัญหาก็คือ

$a$b

ตัวอย่างเช่น,

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

ซึ่งผลิต

Hello World

หากคุณพยายามต่อสตริงเข้ากับสตริงอื่นตัวอย่างเช่น

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

จากนั้นecho "$c"จะผลิต

Hello World

ด้วยพื้นที่พิเศษ

$aWorld

ไม่ทำงานอย่างที่คุณอาจจินตนาการ แต่

${a}World

ผลิต

HelloWorld

1
... จึง${a}\ Worldสร้างHello World
XavierStuvw

เรื่องนี้ทำให้ฉันประหลาดใจ ฉันคาดว่าc=$a$bที่นี่จะทำสิ่งเดียวกันกับc=$a World(ซึ่งจะพยายามเรียกใช้Worldเป็นคำสั่ง) ฉันเดาว่าหมายถึงการได้รับมอบหมายก่อนที่จะแยกตัวแปรที่มีการขยายตัว ..
mwfearnley

30

นี่เป็นบทสรุปโดยสังเขปของสิ่งที่คำตอบส่วนใหญ่พูดถึง

สมมติว่าเรามีสองตัวแปรและ $ 1 ถูกตั้งค่าเป็น 'หนึ่ง':

set one two
a=hello
b=world

ตารางด้านล่างอธิบายบริบทที่แตกต่างกันซึ่งเราสามารถรวมค่าของ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

หมายเหตุเล็กน้อย:

  • การล้อมรอบ RHS ของการมอบหมายในเครื่องหมายคำพูดคู่นั้นเป็นวิธีปฏิบัติที่ดีแม้ว่ามันจะค่อนข้างเป็นทางเลือกในหลายกรณี
  • += ดีกว่าจากจุดยืนประสิทธิภาพหากสตริงขนาดใหญ่จะถูกสร้างขึ้นทีละน้อยโดยเฉพาะในวง
  • ใช้{}ชื่อตัวแปรรอบ ๆ เพื่อแก้ปัญหาการขยายตัว (เช่นในแถวที่ 2 ในตารางด้านบน) ดังที่เห็นในแถวที่ 3 และ 4 ไม่จำเป็นต้อง{}เว้นเสียแต่ว่าตัวแปรจะถูกต่อกับสตริงที่ขึ้นต้นด้วยอักขระที่เป็นอักขระตัวแรกที่ถูกต้องในชื่อตัวแปรเชลล์นั่นคือตัวอักษรหรือขีดล่าง

ดูสิ่งนี้ด้วย:


2
หากคุณกังวลเกี่ยวกับประสิทธิภาพการทำงานให้ดูการวิเคราะห์ในคำตอบของฉันstackoverflow.com/a/47878161/117471
Bruno Bronosky


20

อีกวิธีหนึ่ง ...

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

... และยังเป็นอีกหนึ่ง

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

1
นั่นคือสิ่งที่ฉันทำและฉันพบว่ามันง่ายและตรงไปตรงมามากกว่าคำตอบอื่น ๆ มีเหตุผลที่ไม่มีคำตอบที่ถูกโหวตมากที่สุดชี้ให้เห็นตัวเลือกนี้หรือไม่?
quimnuss

1
@quimnuss ข้อเท็จจริงที่ว่าสตริงไม่ตรงกับที่ใช้ในคำถาม OP อาจเป็นเหตุผลที่ดี
jlliagre

20

หากคุณต้องการผนวกสิ่งที่ขีดเส้นใต้ให้ใช้ escape (\)

FILEPATH=/opt/myfile

สิ่งนี้ไม่ทำงาน:

echo $FILEPATH_$DATEX

ใช้งานได้ดี:

echo $FILEPATH\\_$DATEX

11
หรือมิฉะนั้น $ {FILEPATH} _ $ DATEX นี่ {} ใช้เพื่อระบุขอบเขตของชื่อตัวแปร นี่คือ appropariate เนื่องจากขีดล่างเป็นอักขระตามกฎหมายในชื่อตัวแปรดังนั้นในตัวอย่างข้อมูลของคุณจริง ๆ แล้วพยายามแก้ไข FILEPATH_ ไม่ใช่แค่ $ FILEPATH
Nik O'Lai

1
สำหรับฉันฉันมีหนึ่งตัวแปรเช่น $ var1 และค่าคงที่ถัดจากนี้ดังนั้น echo $ var1_costant_traling_part ได้ผลสำหรับฉัน
YouAreAwesome

2
ฉันเดาว่าต้องการแบ็กแลชเพียงอันเดียวสำหรับการหลบหนี: echo $a\_$bจะทำ ตามที่พูดถึงในความคิดเห็นของ Nik O'Lai ขีดเส้นใต้เป็นตัวละครปกติ การจัดการช่องว่างสีขาวนั้นมีความละเอียดอ่อนมากขึ้นสำหรับสตริงเสียงก้องและการต่อข้อมูล --- หนึ่งสามารถใช้\ และอ่านเธรดนี้อย่างละเอียดเนื่องจากปัญหานี้กลับมาแล้วในตอนนี้
XavierStuvw

16

วิธีที่ง่ายที่สุดด้วยเครื่องหมายคำพูด:

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

1
เครื่องหมายคำพูดมากเกินไป IMHO var=$B$b"a"; echo Hello\ $varฉันจะทำอย่างไรเชื่อ
XavierStuvw

ฉันแนะนำให้ใช้เครื่องหมายคำพูดทั้งหมดทำให้เกิดถ้าคุณใส่ทุกที่ที่คุณไม่ควรพลาดคุณไม่ต้องคิด
betontalpfa

15

คุณสามารถต่อกันได้โดยไม่ต้องใส่เครื่องหมายคำพูด นี่คือตัวอย่าง:

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

คำสั่งสุดท้ายนี้จะพิมพ์ "OpenSystems" (ไม่มีเครื่องหมายคำพูด)

นี่คือตัวอย่างของสคริปต์ Bash:

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

1
ไวยากรณ์ของบล็อกแรกสร้างความสับสน เครื่องหมาย $ เหล่านี้หมายความว่าอย่างไร
XavierStuvw

15

แม้ว่าตอนนี้จะอนุญาตให้ใช้เครื่องหมาย + = ได้ถูกนำมาใช้ในBash 3.1ในปี 2004

สคริปต์ใด ๆ ที่ใช้ตัวดำเนินการนี้ในเวอร์ชัน Bash ที่เก่ากว่าจะล้มเหลวด้วยข้อผิดพลาด "ไม่พบคำสั่ง" หากคุณโชคดีหรือ "ข้อผิดพลาดทางไวยากรณ์ใกล้โทเค็นที่ไม่คาดคิด"

สำหรับผู้ที่ใส่ใจกับความเข้ากันได้แบบย้อนหลังให้ใช้วิธีการต่อข้อมูล Bash แบบมาตรฐานแบบเก่าเช่นเดียวกับที่กล่าวไว้ในคำตอบที่เลือก:

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

1
ขอบคุณที่ชี้ให้เห็นว่าฉันแค่ค้นหาเวอร์ชันที่ต้องการให้ใช้งานได้
Rho Phi

14

ฉันชอบที่จะใช้วงเล็บปีกกา${}สำหรับการขยายตัวแปรในสตริง:

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

วงเล็บปีกกาจะพอดีกับการใช้สตริงอย่างต่อเนื่อง:

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

มิฉะนั้นการใช้foo = "$fooWorld"จะไม่ทำงาน


8

หากสิ่งที่คุณพยายามทำคือการแยกสตริงออกเป็นหลายบรรทัดคุณสามารถใช้แบ็กสแลช:

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

ด้วยหนึ่งช่องว่างระหว่าง:

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

อันนี้ยังเพิ่มเพียงหนึ่งช่องว่างในระหว่าง:

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

ฉันกลัวว่านี่ไม่ใช่สิ่งที่ตั้งใจ
ไว้

7

วิธีที่ปลอดภัยกว่า:

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

สตริงที่มีช่องว่างสามารถเป็นส่วนหนึ่งของคำสั่งใช้ "$ XXX" และ "$ {XXX}" เพื่อหลีกเลี่ยงข้อผิดพลาดเหล่านี้

ลองดูคำตอบอื่น ๆ เกี่ยวกับ+ =


จุดของสตริงที่มีช่องว่างที่อ่านเป็นคำสั่งจะปรากฏขึ้นที่จุดของคำนิยาม ดังนั้นd=DD DDจะให้DD: command not found--- ทราบว่าจะเป็นวันสุดท้าย DD, D มากกว่าที่จะไม่พบ หากตัวถูกดำเนินการทั้งหมดมีการจัดรูปแบบอย่างเหมาะสมและมีช่องว่างที่ต้องการอยู่แล้วคุณสามารถต่อกันได้โดยs=${a}${b}${c}${d}; echo $sมีเครื่องหมายคำพูดน้อยกว่า นอกจากนี้คุณสามารถใช้\ (ช่องว่างที่หลบหนี) เพื่อหลีกเลี่ยงปัญหาเหล่านี้ --- d=echo\ echoจะไม่เปิดใช้ echo การเรียกร้องใด ๆ ในขณะที่d=echo echoจะ
XavierStuvw

7

มีกรณีหนึ่งที่คุณควรระวัง:

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

จะเอาท์พุท"daniel"sanและไม่danielsanตามที่คุณอาจต้องการ ในกรณีนี้คุณควรทำแทน:

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

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

นี่คือวิธีที่คุณเชื่อมโยงสองสายเข้าด้วยกัน


1
ใช้งานได้ แต่บางครั้งจะให้ผลลัพธ์ที่คาดเดาไม่ได้เนื่องจากการแก้ไขตัวแปรไม่ได้รับการป้องกัน ดังนั้นคุณไม่สามารถพึ่งพาแบบฟอร์มนี้สำหรับทุกกรณีการใช้งาน
Anthony Rutledge

5

ถ้ามันเป็นตัวอย่างของคุณในการเพิ่ม" World"สตริงเดิมก็สามารถ:

#!/bin/bash

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

ผลลัพธ์:

Hello World


5

มีข้อกังวลเกี่ยวกับประสิทธิภาพ แต่ไม่มีการเสนอข้อมูล ฉันขอแนะนำการทดสอบอย่างง่าย

(หมายเหตุ: dateบน macOS ไม่มีนาโนวินาทีดังนั้นจะต้องทำบน Linux)

ฉันได้สร้างappend_test.sh บน GitHubด้วยเนื้อหา:

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

ทดสอบ 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

ทดสอบ 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

ข้อผิดพลาดระบุว่า Bash ของฉันมีขนาดไม่เกิน335.54432 MBก่อนที่จะเกิดปัญหา คุณสามารถเปลี่ยนรหัสจากการเพิ่มข้อมูลเป็นสองเท่าเพื่อผนวกค่าคงที่เพื่อให้ได้กราฟที่ละเอียดยิ่งขึ้นและจุดความล้มเหลว แต่ฉันคิดว่านี่ควรให้ข้อมูลที่เพียงพอแก่คุณในการตัดสินใจว่าคุณใส่ใจหรือไม่ ส่วนตัวต่ำกว่า 100 MB ฉันไม่ ไมล์สะสมของคุณอาจแตกต่างกันไป


! ที่น่าสนใจ ลองพิจารณา: 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"(ลองใช้ตัวนี้ไม่ใช่โฮสต์ที่ให้ผลดี !!;)
F. Hauri

4

ฉันต้องการสร้างสตริงจากรายการ ไม่พบคำตอบสำหรับสิ่งนั้นดังนั้นฉันจึงโพสต์ไว้ที่นี่ นี่คือสิ่งที่ฉันทำ:

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

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

echo ${string}

แล้วฉันจะได้รับผลลัพธ์ต่อไปนี้:

1 2 3 4 5

4

แม้จะมีผู้ปฏิบัติงานพิเศษ+=สำหรับการต่อข้อมูล แต่ก็มีวิธีที่ง่ายกว่าในการไป:

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

เครื่องหมายคำพูดคู่ใช้เวลาในการคำนวณพิเศษสำหรับการแปลความหมายของตัวแปรภายใน หลีกเลี่ยงถ้าเป็นไปได้


3

โปรดทราบว่าสิ่งนี้จะไม่ทำงาน

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

ดูเหมือนว่าจะลดลง $ foo และทิ้งคุณไว้กับ:

PREFIX_WORLD

แต่สิ่งนี้จะได้ผล:

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

และปล่อยให้คุณมีผลลัพธ์ที่ถูกต้อง:

PREFIX_HELLO_WORLD


8
สิ่งนี้เกิดขึ้นเนื่องจากขีดล่างเป็นอักขระที่ถูกต้องในชื่อตัวแปรดังนั้น bash จึงเห็นว่า foo_ เป็นตัวแปร เมื่อจำเป็นต้องบอกขอบเขตของชื่อ var ที่ถูกต้องคุณสามารถใช้เครื่องมือจัดฟันแบบโค้งได้: PREFIX _ $ {foo} _ $ bar
Nik O'Lai

2

นี่คือหนึ่งในAWK :

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

1
ดีมาก แต่ฉันคิดว่าฉันจะได้รับความแม่นยำมากขึ้นโดยใช้ Python!
เทคโน

1

ฉันทำแบบนี้เมื่อสะดวก: ใช้คำสั่ง inline!

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

1
On line ที่ 1 คุณสามารถวางส้อมโดยใช้: แทนdate "+The current time is %a %b %d %Y +%T" echo ...$(date)ภายใต้ bash ล่าสุดคุณสามารถเขียน: printf "The current time is %(%a %b %d %Y +%T)T\n" -1.
F. Hauri

1

ในความคิดของฉันวิธีที่ง่ายที่สุดในการเชื่อมสองสายคือการเขียนฟังก์ชั่นที่เหมาะกับคุณแล้วใช้ฟังก์ชั่นนั้น

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

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

foo="Super"
bar="man"

concat $foo $bar   # Superman

alien=$(concat $foo $bar)

echo $alien        # Superman

-1

ฉันชอบทำฟังก์ชั่นอย่างรวดเร็ว

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

echo $(combo 'foo''bar')

อีกวิธีหนึ่งในการดูแลแมว เวลานี้มีฟังก์ชั่น: D


การเรียกใช้ฟังก์ชันที่อยู่ใน subshell นั้นเป็น overkill มากเกินไปสำหรับ concat ง่าย ๆ
codeforester

-1

ฉันยังไม่รู้เกี่ยวกับ PHP แต่ใช้งานได้ใน Linux Bash หากคุณไม่ต้องการส่งผลกระทบต่อตัวแปรคุณสามารถลองทำสิ่งนี้:

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

>Hello World!

คุณสามารถวางตัวแปรอื่นแทน 'Hello' หรือ '!' คุณสามารถต่อสตริงเข้าด้วยกันได้เช่นกัน


2
การใช้ subshell เพื่อทำ concatenation ง่าย ๆ นั้นแพงเกินไป!
codeforester
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.