переназначение - linux bash переменная
Как конкатенировать строковые переменные в Bash (19)
Сначала Бэш
Поскольку этот вопрос стоит конкретно для 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
Хм .. это не ошибка, а особенность ... Чтобы предотвратить 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
builtin дает мощный способ рисования строкового формата. Поскольку это встроенный 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
Примечание. Использование двойных кавычек может быть полезно для манипулирования строками, которые содержат spaces
, tabulations
и / или newlines
printf -v foo "%s World" "$foo"
Shell теперь
В оболочке POSIX вы не можете использовать базисы , поэтому нет встроенного printf
.
В принципе
Но вы могли бы просто сделать:
foo="Hello"
foo="$foo World"
echo $foo
Hello World
Отформатирован, используя forked printf
Если вы хотите использовать более сложные конструкции, вам нужно использовать fork (новый дочерний процесс, который выполняет задание и возвращает результат через 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
В PHP строки объединяются следующим образом:
$foo = "Hello";
$foo .= " World";
Здесь $foo
становится «Hello World».
Как это делается в Баше?
Bash также поддерживает оператор + =, как показано в следующем расшифровке:
$ A="X Y"
$ A+="Z"
$ echo "$A"
X YZ
Вот один из них: AWK :
$ foo="Hello"
$ foo=$(awk -v var=$foo 'BEGIN{print var" World"}')
$ echo $foo
Hello World
Вы можете объединиться без кавычек. Вот пример:
$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
Высказываются опасения по поводу производительности, но данные не предлагаются. Позвольте мне предложить простой тест.
(ПРИМЕЧАНИЕ: 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 МБ я этого не делаю. Ваш пробег может отличаться.
Даже если теперь разрешен оператор + =, он был введен в Bash 3.1 в 2004 году.
Любой скрипт, использующий этот оператор в более старых версиях Bash, сбой «с ошибкой команды», если вам повезет, или «синтаксическая ошибка около неожиданного токена» будет сбой.
Для тех, кто заботится о обратной совместимости, придерживайтесь более старых стандартных методов конкатенации Bash, подобных тем, которые указаны в выбранном ответе:
foo="Hello"
foo="$foo World"
echo $foo
> Hello World
Если вы хотите добавить что-то вроде подчеркивания, используйте escape (\)
FILEPATH=/opt/myfile
Это не работает:
echo $FILEPATH_$DATEX
Это прекрасно работает:
echo $FILEPATH\\_$DATEX
Если это ваш пример добавления " World"
к исходной строке, это может быть:
#!/bin/bash
foo="Hello"
foo=$foo" World"
echo $foo
Выход:
Hello World
Еще один подход ...
> H="Hello "
> U="$H""universe."
> echo $U
Hello universe.
... и все же еще один.
> H="Hello "
> U=$H"universe."
> echo $U
Hello universe.
Ниже приведен краткий обзор того, что говорит большинство ответов.
Допустим, у нас есть две переменные:
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 в таблице выше)
Смотрите также:
Самый простой способ с кавычками:
B=Bar
b=bar
var="$B""$b""a"
echo "Hello ""$var"
То, как я решаю проблему, - это просто
$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
Я вроде как быстро выполняю функцию.
#! /bin/sh -f
function combo() {
echo [email protected]
}
echo $(combo 'foo''bar')
Еще один способ кожи кошки. На этот раз с функциями: D
Я делаю это так, когда это удобно: используйте встроенную команду!
echo "The current time is `date`"
echo "Current User: `echo $USER`"
Я предпочитаю использовать фигурные скобки ${}
для расширения переменной в строке:
foo="Hello"
foo="${foo} World"
echo $foo
> Hello World
Кудрявые скобки будут соответствовать непрерывному использованию строки:
foo="Hello"
foo="${foo}World"
echo $foo
> HelloWorld
В противном случае использование foo = "$fooWorld"
не будет работать.
Я хотел построить строку из списка. Не удалось найти ответ, поэтому я размещаю его здесь. Вот что я сделал:
list=(1 2 3 4 5)
string=''
for elm in "${list[@]}"; do
string="${string} ${elm}"
done
echo ${string}
и затем я получаю следующий вывод:
1 2 3 4 5
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