Как объединить строковые переменные в Bash - PullRequest
2481 голосов
/ 15 ноября 2010

В PHP строки объединяются следующим образом:

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

Здесь $foo становится "Hello World".

Как это достигается в Bash?

Ответы [ 30 ]

3358 голосов
/ 15 ноября 2010
foo="Hello"
foo="$foo World"
echo $foo
> Hello World

В общем случае для объединения двух переменных вы можете просто записать их одну за другой:

a='hello'
b='world'
c="$a$b"
echo $c
> helloworld
1046 голосов
/ 15 ноября 2010

Bash также поддерживает оператор +=, как показано в этом коде:

$ A="X Y"
$ A+=" Z"
$ echo "$A"
X Y Z
901 голосов
/ 04 августа 2013

Bash first

Поскольку этот вопрос обозначает специально 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 встроенная команда дает мощный способ рисования формата строки.Поскольку это 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"

Оболочка теперь

Под POSIX оболочкой нельзя использовать bashisms , поэтому нет встроенных printf.

В основном

Но вы можете просто сделать:

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

Отформатировано, используя разветвленный printf

Если вы хотите использоватьболее сложные конструкции, вам нужно использовать fork (новый дочерний процесс, который выполняет задание и возвращает результат через stdout):

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

Исторически сложилось, что backticks можно было использовать для получения результата fork :

foo="Hello"
foo=`printf "%s World" "$foo"`
echo $foo
Hello World

Но это не так просто для nesting :

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
126 голосов
/ 28 октября 2011

Вы тоже можете сделать это:

$ var="myscript"

$ echo $var

myscript


$ var=${var}.sh

$ echo $var

myscript.sh
115 голосов
/ 25 июля 2013
bla=hello
laber=kthx
echo "${bla}ohai${laber}bye"

Будет выводить

helloohaikthxbye

Это полезно, когда $blaohai приводит к ошибке переменной not found.Или если у вас есть пробелы или другие специальные символы в ваших строках."${foo}" должным образом избегает всего, что вы положили в него.

42 голосов
/ 15 ноября 2010
foo="Hello "
foo="$foo World"

32 голосов
/ 07 марта 2014

Я бы решил эту проблему просто

$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
28 голосов
/ 15 ноября 2010
$ a=hip
$ b=hop
$ ab=$a$b
$ echo $ab
hiphop
$ echo $a$b
hiphop
22 голосов
/ 06 декабря 2017

Вот краткое изложение того, о чем говорит большинство ответов.

Допустим, у нас есть две переменные и $ 1 установлен в 'one':

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

Несколько заметок:

  • Заключение RHS присвоения в двойные кавычки, как правило, является хорошей практикой, хотя во многих случаях это необязательно
  • += лучше с точки зрения производительности, если большая строка строится с небольшими приращениями, особенно в цикле
  • используйте {} вокруг имен переменных для устранения неоднозначности их расширения (как в строке 2 в таблице выше). Как видно из строк 3 и 4, нет необходимости в {}, если переменная не конкатенируется со строкой, которая начинается с символа, который является допустимым первым символом в имени переменной оболочки, то есть алфавита или подчеркивания.

Смотри также:

20 голосов
/ 20 сентября 2013

Если вы хотите добавить что-то вроде подчеркивания, используйте escape (\)

FILEPATH=/opt/myfile

Это не работает:

echo $FILEPATH_$DATEX

Это отлично работает:

echo $FILEPATH\\_$DATEX
...