bash - كيفية ربط متغيرات السلسلة في باش




shell syntax (19)

باش اولا

نظرًا لأن هذا السؤال يقف تحديدًا لصالح 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+=(...)

لدينا هو أيضا مجموعة من عنصر واحد فقط.

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

يعطي الأمر printin المدمج طريقة قوية لرسم تنسيق السلسلة. نظرًا لأن هذا هو Bash مضمن ، هناك خيار لإرسال سلسلة منسقة إلى متغير بدلاً من الطباعة على 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!'

أو يمكننا استخدام سلسلة تنسيق وسيطة واحدة والتي سيتم تكرارها كلما تم تقديم الوسيطة ...

لاحظ أنه لا يزال لدينا مجموعة! يتم تغيير العنصر الأول فقط!

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 ، عندما تصل إلى اسم متغير بدون تحديد فهرس ، فإنك دائمًا ما تتناول العنصر الأول فقط!

لذا لاسترداد صفيف الحقول السبعة ، نحتاج فقط إلى إعادة تعيين عنصر 1st:

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 shell ، لا يمكنك استخدام bashisms ، لذلك لا يوجد printin مدمج .

في الأساس

لكن يمكنك ببساطة القيام بما يلي:

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

منسق ، وذلك باستخدام printf

إذا كنت ترغب في استخدام منشآت أكثر تطوراً ، فيجب عليك استخدام شوكة (عملية أطفال جديدة تقوم بهذا العمل stdout النتيجة عبر stdout ):

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

تاريخيا ، يمكنك استخدام باكتكس لاسترجاع نتيجة الشوكة :

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

في PHP ، يتم تجميع السلاسل معاً كما يلي:

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

هنا ، يصبح $foo "Hello World".

كيف يتم هذا في باش؟


أبسط طريقة مع علامات الاقتباس:

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

أفعلها بهذه الطريقة عندما تكون مريحة: استخدم أمر مضمن!

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

إذا كان لديك مثالًا لإضافة " World" إلى السلسلة الأصلية ، فيمكن أن يكون:

#!/bin/bash

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

الإخراج:

Hello World

إذا كنت تريد إلحاق شيء مثل شرطة سفلية ، استخدم الهروب (\)

FILEPATH=/opt/myfile

هذا لا يعمل:

echo $FILEPATH_$DATEX

هذا يعمل بشكل جيد:

echo $FILEPATH\\_$DATEX

حتى إذا تم السماح + عامل التشغيل الآن ، فقد تم تقديمه في Bash 3.1 في عام 2004.

سوف يفشل أي برنامج نصي يستخدم هذا المشغل على إصدارات باش القديمة مع ظهور خطأ "لم يتم العثور على أمر" إذا كنت محظوظًا ، أو "خطأ في بناء الجملة بالقرب من رمز غير متوقع".

بالنسبة لأولئك الذين يهتمون بالتوافق مع الإصدارات السابقة ، يلتزمون بطرق سَلسَلة Bash القياسية القديمة ، مثل تلك المذكورة في الإجابة المختارة:

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

طريقة حل المشكلة هي فقط

$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

فيما يلي ملخص موجز لما تتحدث عنه معظم الإجابات.

لنفترض أن لدينا متغيرين:

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, 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 في الجدول أعلاه)

أنظر أيضا:


لاحظ أن هذا لن ينجح

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

حيث يبدو أنه يسقط $ foo ويترك لك ما يلي:

PREFIX_WORLD

لكن هذا سيعمل:

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

ويترك لك الإخراج الصحيح:

PREFIX_HELLO_WORLD


نهج آخر ...

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

... وحتى الآن واحد آخر.

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

هناك حالة واحدة بعينها ينبغي عليك فيها الاهتمام:

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

سوف إخراج "daniel"san ، وليس danielsan ، كما قد ترغب. في هذه الحالة يجب عليك أن تفعل بدلاً من ذلك:

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

هناك مخاوف بشأن الأداء ، ولكن لا يتم تقديم أي بيانات. دعني أقترح اختبار بسيط.

(ملاحظة: لا يقدم 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

تشير الأخطاء إلى أن My Bash حصلت على 335.54432 ميغابايت قبل أن تتعطل . يمكنك تغيير الرمز من مضاعفة البيانات لإلحاق ثابت للحصول على رسم بياني أكثر دقة ونقطة فشل. لكن أعتقد أن هذا يجب أن يعطيك معلومات كافية لتقرر ما إذا كنت تهتم. شخصيا ، أقل من 100 ميغابايت لا. الأميال الخاص بك قد تختلف.


يمكنك تسلسل دون علامات الاقتباس. هنا مثال:

$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

أنا نوع من مثل جعل وظيفة سريعة.

#! /bin/sh -f
function combo() {
    echo [email protected]
}

echo $(combo 'foo''bar')

طريقة أخرى لتقشير القطة. هذه المرة مع وظائف: د


لا أعرف عن PHP بعد ، لكن هذا يعمل في Linux Bash. إذا كنت لا ترغب في التأثير على المتغير ، فيمكنك تجربة ذلك:

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

>Hello World!

يمكنك وضع متغير آخر بدلاً من "Hello" أو "!". يمكنك سلسلة المزيد من السلاسل كذلك.


يمكنك تجربة الطريقة أدناه. عندما يحدث الإحلال ، فإن علامات الاقتباس المزدوجة تحافظ على الفراغات.

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

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

سوف الناتج

helloohaikthxbye

هذا مفيد عندما يؤدي $blaohai إلى خطأ متغير غير موجود. أو إذا كان لديك مسافات أو أحرف خاصة أخرى في السلاسل الخاصة بك. "${foo}" بشكل صحيح يهرب من أي شيء تضعه فيه.


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


var1='hello'
var2='world'
var3=$var1" "$var2 
echo $var3






string-concatenation