Ответы:
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
Используя синтаксис вопроса 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
Хм .. это не ошибка, а особенность ... Чтобы предотвратить попытки разработки 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
: Перестроить переменную с помощью встроенной команды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 вы не можете использовать bashisms , поэтому нет встроенных 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
bla=hello
laber=kthx
echo "${bla}ohai${laber}bye"
Будет выходной
helloohaikthxbye
Это полезно, когда
$blaohai
приводит к ошибке переменной not found. Или если у вас есть пробелы или другие специальные символы в ваших строках. "${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
Несколько заметок:
+=
лучше с точки зрения производительности, если большая строка строится с небольшими приращениями, особенно в цикле{}
вокруг имен переменных, чтобы устранить неоднозначность их расширения (как в строке 2 в таблице выше). Как видно из строк 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
будет.
Есть один конкретный случай, когда вы должны позаботиться:
user=daniel
cat > output.file << EOF
"$user"san
EOF
Будет выводить "daniel"san
, а не так danielsan
, как вы, возможно, хотели. В этом случае вы должны сделать вместо этого:
user=daniel
cat > output.file << EOF
${user}san
EOF
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!
Вы можете поместить другую переменную вместо «Hello» или «!». Вы также можете объединить больше строк.
foo="Hello"
foo=$foo" World"
echo $foo
это скорее сработало для "#! / bin / sh"