Відповіді:
foo="Hello"
foo="${foo} World"
echo "${foo}"
> Hello World
Загалом для об'єднання двох змінних можна просто записати їх одна за одною:
a='Hello'
b='World'
c="${a} ${b}"
echo "${c}"
> Hello World
$foo
у подвійні цитати, коли це дійсно має значення.
foo="$fooworld"
? Я б припустив, що не ...
fooworld
. Розбір, що робиться за допомогою брекетів, як у foo="${foo}world"
...
Bash також підтримує +=
оператора, як показано в цьому коді:
$ A="X Y"
$ A+=" Z"
$ echo "$A"
X Y Z
export A+="Z"
або, можливо, A
змінну потрібно експортувати лише один раз?
export A+=Z
працює непогано.
#!/bin/sh
сценарій, використовуючи цю конструкцію.
bash
деяких інших більш досконалих оболонках. Він не працюватиме під busybox sh
або dash
(що знаходиться /bin/sh
в багатьох дистрибутивах), або в деяких інших оболонках, як це /bin/sh
передбачено у FreeBSD.
Оскільки це питання стоїть спеціально для Bash , моя перша частина відповіді представляла б різні способи цього правильно:
+=
: Додати до змінноїСинтаксис +=
може використовуватися різними способами:
var+=...
(Тому що я скромний, я буду використовувати тільки дві змінні foo
і a
потім повторно використовувати той же самий в цілому відповідь ;-).
a=2
a+=4
echo $a
24
Використовуючи синтаксис запитання про переповнення стека ,
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
: Переконструюйте змінну за допомогою вбудованої командиprintf
Вбудована команда дає потужний спосіб малювання формат рядка. Оскільки це вбудований 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!'
Або ми можемо використати один рядок формату аргументу, який буде повторюватися стільки, скільки поданих аргументів ...
Зауважте, що наш 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!>
foo="Hello"
printf -v foo "%s World" $foo
echo $foo
Hello World
Nota: Використання подвійних лапок може бути корисно для роботи зі рядками , які містять spaces
, tabulations
і / абоnewlines
printf -v foo "%s World" "$foo"
Під оболонкою POSIX ви не можете використовувати башизми , тому немає вбудованого printf
.
Але ви могли просто зробити:
foo="Hello"
foo="$foo World"
echo $foo
Hello World
printf
Якщо ви хочете використовувати більш складні конструкції, ви повинні використовувати виделку (новий дочірній процес, який робить роботу і повертає результат через 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
за допомогою задньої клавіші вам потрібно уникнути внутрішніх вил із зворотними нахилами :
foo="Today is: "
foo=`printf "%s %s" "$foo" "\`date\`"`
echo $foo
Today is: Sun Aug 4 11:59:10 CEST 2013
+=
Оператор також набагато швидше , ніж $a="$a$b"
в моїх тестах .. Який сенс.
var=${var}.sh
приклад з інших відповідей, що дуже корисно.
bash
єдина оболонка з +=
оператором? Я хочу дізнатися, чи достатньо портативний
+=
оператором, але всі ці способи - це башизми , тому не портативні! Навіть у вас може виникнути спеціальна помилка у разі неправильної версії bash!
Ви також можете це зробити:
$ var="myscript"
$ echo $var
myscript
$ var=${var}.sh
$ echo $var
myscript.sh
var=myscript;var=$var.sh;echo $var
мали б однакові ефекти (Ця робота під bash, dash, busybox та ін.).
echo $var2
myscript2
.
незаконну точку в назві змінної. Якщо інше echo ${var}2
чи дивіться мою відповідь
bla=hello
laber=kthx
echo "${bla}ohai${laber}bye"
Вийде
helloohaikthxbye
Це корисно, коли
$blaohai
призводить до помилки не знайдено змінної. Або якщо у ваших рядках є пробіли чи інші спеціальні символи. "${foo}"
належним чином уникає всього, що ви вкладете в нього.
foo="Hello "
foo="$foo 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}\ World
виробляєHello World
c=$a$b
тут зробить те саме, що c=$a World
(що спробував би запустити World
як команду). Я думаю, це означає, що призначення аналізується перед розширенням змінних ..
Ось стислий підсумок того, про що йдеться у більшості відповідей.
Скажімо, у нас є дві змінні, і $ 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
Кілька приміток:
+=
краще з точки зору продуктивності, якщо велика струна будується невеликими кроками, особливо в циклі{}
імена змінних, щоб розмежувати їх розширення (як у другому рядку в таблиці вище). Як видно з рядків 3 і 4, немає необхідності, {}
якщо змінна не буде об'єднана рядком, який починається з символу, який є дійсним першим символом у назві змінної оболонки, тобто алфавіту або підкреслення.Дивись також:
Ще один підхід ...
> H="Hello "
> U="$H""universe."
> echo $U
Hello universe.
... і ще один.
> H="Hello "
> U=$H"universe."
> echo $U
Hello universe.
Якщо ви хочете додати щось на зразок підкреслення, використовуйте escape (\)
FILEPATH=/opt/myfile
Це не працює:
echo $FILEPATH_$DATEX
Це добре працює:
echo $FILEPATH\\_$DATEX
echo $a\_$b
було б. Як натякнув у коментарі Нік О'Лай, підкреслення є регулярним символом. Обробка білих пробілів набагато більш чутлива для струн, відлуння та конкатенації --- ви можете \
ретельно використовувати та читати цю тему, оскільки ця проблема повертається раз у раз.
Найпростіший спосіб з лапками:
B=Bar
b=bar
var="$B""$b""a"
echo "Hello ""$var"
var=$B$b"a"; echo Hello\ $var
зробив би, я вважаю
Ви можете об'єднатись без лапок. Ось приклад:
$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
Навіть якщо оператор + = зараз дозволений, він був введений в Bash 3.1 в 2004 році.
Будь-який сценарій, що використовує цього оператора в старих версіях Bash, не вдасться з помилкою "команда не знайдена", якщо вам пощастить, або "помилкою синтаксису поблизу несподіваного маркера".
Для тих, хто піклується про зворотну сумісність, дотримуйтесь старих стандартних методів конкатенації Bash, таких як зазначені у вибраній відповіді:
foo="Hello"
foo="$foo World"
echo $foo
> Hello World
Я вважаю за краще використовувати фігурні дужки ${}
для розширення змінної в рядку:
foo="Hello"
foo="${foo} World"
echo $foo
> Hello World
Фігурні дужки підійдуть до постійного використання рядків:
foo="Hello"
foo="${foo}World"
echo $foo
> HelloWorld
Інакше використовувати foo = "$fooWorld"
не вийде.
Якщо ви намагаєтеся розділити рядок на кілька рядків, ви можете скористатися зворотною косою рисою:
$ a="hello\
> world"
$ echo $a
helloworld
З одним проміжком між ними:
$ a="hello \
> world"
$ echo $a
hello world
Цей додає лише один пробіл між ними:
$ a="hello \
> world"
$ echo $a
hello world
Більш безпечний спосіб:
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
не запустить жодного ехо-виклику, тоді як d=echo echo
буде.
a="Hello,"
a=$a" World!"
echo $a
Це те, як ви об'єднали два рядки.
Якщо це ваш приклад додавання " World"
до початкового рядка, то це може бути:
#!/bin/bash
foo="Hello"
foo=$foo" World"
echo $foo
Вихід:
Hello World
var1='hello'
var2='world'
var3=$var1" "$var2
echo $var3
var3=$var1\ $var2
має такий же ефект
Висловлюються занепокоєння щодо продуктивності, але даних не надано. Дозвольте запропонувати простий тест.
(ПРИМІТКА: 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 Мб, перш ніж він вийшов з ладу . Ви можете змінити код від подвоєння даних до додавання константи для отримання більш деталізованого графіка та точки відмови. Але я думаю, що це повинно дати вам достатньо інформації, щоб вирішити, чи вам це все одно. Особисто менше 100 МБ я не знаю. Ваш пробіг може відрізнятися.
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"
(Спробуйте це на не продуктивний хост !!;)
Зауважте, що це не спрацює
foo=HELLO
bar=WORLD
foobar=PREFIX_$foo_$bar
як здається, скидає $ foo і залишає вас з:
PREFIX_WORLD
але це спрацює:
foobar=PREFIX_"$foo"_"$bar"
і залишимо вам правильний вихід:
PREFIX_HELLO_WORLD
Я роблю це так, коли зручно: Використовуйте вбудовану команду!
echo "The current time is `date`"
echo "Current User: `echo $USER`"
date "+The current time is %a %b %d %Y +%T"
а не echo ...$(date)
. Згідно з недавнім Баш, ви могли б написати: printf "The current time is %(%a %b %d %Y +%T)T\n" -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
Мені подобається робити швидку функцію.
#! /bin/sh -f
function combo() {
echo $@
}
echo $(combo 'foo''bar')
Ще один спосіб зіпсувати кішку. Цього разу з функціями: D
Я ще не знаю про PHP, але це працює в Linux Bash. Якщо ви не хочете впливати на змінну, ви можете спробувати це:
read pp; *# Assumes I will affect Hello to pp*
pp=$( printf $pp ;printf ' World'; printf '!');
echo $pp;
>Hello World!
Ви можете розмістити іншу змінну замість "Привіт" або "!". Ви також можете об'єднати більше рядків.
foo="Hello"
foo=$foo" World"
echo $foo
це, скоріше, працювало на "#! / bin / sh"