Питання Як об'єднати рядкові змінні в Bash


У PHP рядки об'єднуються наступним чином:

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

Тут $foo стає "Hello World".

Як це відбувається в Баш?


2102
2017-11-15 05:38


походження


foo="Hello"  foo=$foo" World"  echo $foo      це досить працювало для "#! / bin / sh" - parasrish
Що робити, якщо ви хочете HelloWorld без простору? - Adi


Відповіді:


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

Загалом, для об'єднання двох змінних можна просто написати їх один за іншим:

a='hello'
b='world'
c=$a$b
echo $c
> helloworld

2851
2017-11-15 05:41



Напевно, добре потрапити у звичку вкладати $foo всередині подвійних лапок, за часи, коли воно дійсно має значення. - Cascabel
Нас навчають завжди робити це, тому що, коли відбувається заміна, пробіли будуть ігноруватися оболонкою, однак подвійні лапки завжди захищатимуть ці прогалини. - Strawberry
Чи повинен ваш перший приклад бути пробілом? Чи можна зробити щось подібне foo="$fooworld"? Я б не вважала, ні ... - nonsensickle
@nonsensickle Це буде шукати змінну з ім'ям fooworld. Знижуючи це, це робиться з дужками, як у foo="${foo}world"... - twalberg
@ JVE999 Так, це також працює, хоча, на мій погляд, це не так добре для коди чіткості ... Але це може бути просто моїм уподобанням ... Існує ще пара способів, якими можна це зробити, - справа в тому, переконайтеся, що ім'я змінної відокремлено від частин без змінної назви, щоб він правильно аналізувався. - twalberg


Bash також підтримує оператор + =, як показано у наступному транскрипції:

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

939
2017-11-15 08:33



Це набагато краще, ніж прийнята відповідь, спасибі! Додано "додати" як тег, щоб зробити це питання легше знайти. - noamtm
Чи можу я використовувати цей синтаксис з ключовим словом експорту? наприклад, export A+="Z" або може бути A змінна тільки потрібно експортувати один раз? - levesque
@levesque: Обидва :-). Змінні потрібно експортувати лише один раз, але export A+=Z працює досить добре. - thkala
Оскільки це бастізм, я думаю, варто згадати, що ви ніколи не повинні користуватися #!/bin/sh в скрипті з використанням цієї конструкції. - Score_Under
Це конкретно і лише оператор плюс-рівний. Тобто, на відміну від Javascript, в Bash, echo $ A + $ B відбитки "X Y + Z" - phpguru


Перший баш

Оскільки це питання стоїть спеціально для Баш, моя перша частина відповіді дасть різні способи зробити це правильно:

+=: Додати до змінної

Синтаксис += можуть використовуватися різними способами:

Додайте до рядка 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: Повторно побудуйте змінну, використовуючи побудований команда

The printf  побудований команда дає потужний спосіб накреслення рядкового формату. Оскільки це Баш побудований, існує можливість відправлення відформатованого рядка до змінної, а не для друку 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!")'

Під грудкою, коли ви отримуєте доступ до імені змінного, не вказуючи індекс, ви завжди звертаєтесь до першого елементу!

Отже, для отримання нашого семи полевого масиву нам потрібно лише перевстановити 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

Історично ви могли використовувати заставки для отримання результату a вилка:

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

807
2017-08-04 10:04



The += Оператор також набагато швидше, ніж $a="$a$b" в моїх тестах .. Що має сенс - Matt
Ця відповідь чудова, але я думаю, що це не вистачає var=${var}.sh приклад з інших відповідей, що дуже корисно. - geneorama
Є bash єдина оболонка з += оператор Я хочу бачити, чи достатньо портативний - dashesy
@dashesy немає я, звичайно, не єдиний корпус з += Оператор, але всі ці способи є басизми, так що не портативний! Навіть у вас може виникнути особлива помилка у випадку неправильної версії bash! - F. Hauri


Ви також можете це зробити:

$ var="myscript"

$ echo $var

myscript


$ var=${var}.sh

$ echo $var

myscript.sh

114
2017-10-28 03:09



Хоча спеціальні символи, пробіли не використовуються, подвійні лапки, цитати та фігурні дужки марні: var=myscript;var=$var.sh;echo $varбуде мати такий же ефект (ця робота під баш, тире, busybox та інші). - F. Hauri


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

Вийде

helloohaikthxbye

Це корисно, коли      $blaohai призводить до змінної, не знайденої помилки. Або якщо у ваших рядках є пробіли чи інші спеціальні символи. "${foo}" належним чином уникає все, що ти вклав у нього.


103
2017-07-25 15:48



Не працює. Я отримую команду "backupstorefolder: команда не знайдено" з bash, де "backupstorefolder" - це назва змінної. - Zian Choy
Це сильно підкреслює синтаксис і знімає деяку неоднозначність в людині. - Ray Foss


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


35
2017-11-15 05:44



Це найбільш корисна відповідь для сценаріїв оболонки. Я знайшов собі останні 30 хвилин, тому що я мав пробіл до і після знаку рівності !! - Stefan
foo = "$ {foo} Світ" - XXL


Те, як я вирішу цю проблему, це просто

$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

29
2018-03-07 16:43



... звідси ${a}\ World випускає Hello World - XavierStuvw


$ a=hip
$ b=hop
$ ab=$a$b
$ echo $ab
hiphop
$ echo $a$b
hiphop

22
2017-11-15 05:42





Ще один підхід ...

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

... а ще ще один.

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

18
2018-03-18 08:24



Це те, що я зробив, і я виявив це настільки простим і прямим, ніж інші відповіді. Чи є причиною, чому ніхто з найбільш голосованих відповідей не вказав цей варіант? - quimnuss
@quimnuss Факт, що рядки не відповідають тим, що використовуються в питанні ОП, може бути вагомою причиною. - jlliagre
... а ще ще один: U=${H}universe..... - XavierStuvw


Якщо ви хочете додати щось на зразок підкреслення, скористайтеся командою escape (\)

FILEPATH=/opt/myfile

Це робить ні робота:

echo $FILEPATH_$DATEX

Це добре працює:

echo $FILEPATH\\_$DATEX

18
2017-09-20 19:15



Або, альтернатива, $ {FILEPATH} _ $ DATEX. Тут {} використовуються для позначення меж імені змінної. Це є адекватним, оскільки підкреслення є юридичним символом в іменах змінних, тому у вашому фрагменті bash насправді намагається вирішити FILEPATH_, а не тільки $ FILEPATH - Nik O'Lai
для мене у мене була одна змінна, тобто $ var1 та постійна поряд з цим, тому echo $ var1_costant_traling_part працює для мене - Indrajeet Gour
Я думаю, для цього потрібно лише один зворотний бік: echo $a\_$b зробив би. Як натякнув в коментарі Ніка О'Лаї підкреслення є звичайним персонажем. Обробка білих просторів є набагато чутливішою для рядків, ехо і об'єднання --- можна використовувати \  і уважно прочитайте цю тему, оскільки ця проблема повертається зараз і потім. - XavierStuvw