ti-enxame.com

Como concatenar variáveis ​​de string no Bash

No PHP, as strings são concatenadas juntas da seguinte maneira:

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

Aqui, $foo se torna "Hello World".

Como isso é feito em Bash?

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

Em geral, para concatenar duas variáveis, você pode escrevê-las uma após a outra:

a='hello'
b='world'
c="$a$b"
echo $c
> helloworld
3285
codaddict

O Bash também suporta um operador += conforme mostrado neste código:

$ A="X Y"
$ A+=" Z"
$ echo "$A"
X Y Z
1026
thkala

Bash primeiro

Como esta questão é especificamente para Bash , minha primeira parte da resposta apresentaria maneiras diferentes de fazer isso corretamente:

+=: Append to variable

A sintaxe+=pode ser usada de diferentes maneiras:

Anexar à cadeia var+=...

(Como sou frugal, só usarei duas variáveis ​​foo e a e, em seguida, reutilizarei as mesmas em toda a resposta. ;-)

a=2
a+=4
echo $a
24

Usando a sintaxe pergunta sobre estouro de pilha,

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

funciona bem!

Anexar a um inteiro ((var+=...))

variável a é uma string, mas também um inteiro

echo $a
24
((a+=12))
echo $a
36

Anexar a um array var+=(...)

Nosso a também é uma matriz de apenas um elemento.

echo ${a[@]}
36

a+=(18)

echo ${a[@]}
36 18
echo ${a[0]}
36
echo ${a[1]}
18

Note que entre parênteses, existe um espaço separado. Se você quiser armazenar uma string contendo espaços em sua matriz, você deve colocá-los:

a+=(one Word "hello world!" )
bash: !": event not found

Hmm .. isso não é um bug, mas um recurso ... Para evitar que o bash tente desenvolver !", você poderia:

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: Re-construct variable usando o comando builtin

O comando printfbuiltin fornece uma maneira poderosa de desenhar o formato de string. Como este é um Bash builtin, há uma opção para enviar uma string formatada para uma variável em vez de imprimir em stdout:

echo ${a[@]}
36 18 one Word hello world! hello world! hello world!

Existem sete strings neste array. Então, poderíamos construir uma string formatada contendo exatamente sete argumentos posicionais:

printf -v a "%s./.%s...'%s' '%s', '%s'=='%s'=='%s'" "${a[@]}"
echo $a
36./.18...'one' 'Word', 'hello world!'=='hello world!'=='hello world!'

Ou podemos usar string de formato de um argumento que será repetido como muitos argumentos enviados ...

Note que o nosso a ainda é um array! Apenas o primeiro elemento é alterado!

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!")'

Sob bash, quando você acessa um nome de variável sem especificar o índice, você sempre endereça somente o primeiro elemento!

Então, para recuperar nosso array de sete campos, precisamos apenas re-configurar o primeiro elemento:

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!")'

Uma string de formato de argumento com muitos argumentos passados ​​para:

printf -v a[0] '<%s>\n' "${a[@]}"
echo "$a"
<36>
<18>
<one>
<Word>
<hello world!>
<hello world!>
<hello world!>

Usando a sintaxe pergunta sobre estouro de pilha:

foo="Hello"
printf -v foo "%s World" $foo
echo $foo
Hello World

Nota: O uso de aspas duplas pode ser útil para manipular strings que contenham spaces, tabulations e/ou newlines

printf -v foo "%s World" "$foo"

Shell agora

Em POSIX Shell, você não pode usar bashisms, então não há builtinprintf.

Basicamente

Mas você poderia simplesmente fazer:

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

Formatado, usando bifurcadaprintf

Se você quer usar construções mais sofisticadas, você tem que usar um fork (novo processo filho que faz o job e retorna o resultado via stdout):

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

Historicamente, você poderia usar backticks para recuperar o resultado de um fork:

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

Mas isso não é fácil para aninhamento:

foo="Today is: "
foo=$(printf "%s %s" "$foo" "$(date)")
echo $foo
Today is: Sun Aug 4 11:58:23 CEST 2013

com backticks, você tem que escapar de garfos internos com barras invertidas:

foo="Today is: "
foo=`printf "%s %s" "$foo" "\`date\`"`
echo $foo
Today is: Sun Aug 4 11:59:10 CEST 2013
885
F. Hauri

Você também pode fazer isso:

$ var="myscript"

$ echo $var

myscript


$ var=${var}.sh

$ echo $var

myscript.sh
123
userend
bla=hello
laber=kthx
echo "${bla}ohai${laber}bye"

Saída

helloohaikthxbye

Isso é útil quando $blaohai leva a uma variável não encontrada. Ou se você tiver espaços ou outros caracteres especiais nas suas strings. "${foo}" escapa corretamente qualquer coisa que você coloca nela.

115
orkoden
foo="Hello "
foo="$foo World"

41
vinothkr

A maneira que eu resolveria o problema é apenas

$a$b

Por exemplo,

a="Hello"
b=" World"
c=$a$b
echo "$c"

que produz

Hello World

Se você tentar concatenar uma string com outra string, por exemplo,

a="Hello"
c="$a World"

então echo "$c" produzirá

Hello World

com um espaço extra.

$aWorld

não funciona, como você pode imaginar, mas

${a}World

produz

HelloWorld
32
Chris Smith
$ a=hip
$ b=hop
$ ab=$a$b
$ echo $ab
hiphop
$ echo $a$b
hiphop
27
bcosca

Aqui está um resumo conciso do que a maioria das respostas está falando.

Vamos dizer que temos duas variáveis:

a=hello
b=world

A tabela abaixo explica os diferentes contextos onde podemos combinar os valores de a e b para criar uma nova variável, 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

Algumas notas:

  • encerrar o RHS de uma atribuição entre aspas duplas geralmente é uma boa prática, embora seja bastante opcional em muitos casos
  • += é melhor do ponto de vista do desempenho se uma string grande estiver sendo construída em pequenos incrementos, especialmente em um loop
  • use {} em torno dos nomes das variáveis ​​para desambiguar sua expansão (como na linha 2 da tabela acima)

Veja também:

20
codeforester

Se você quiser acrescentar algo como um sublinhado, use escape (\)

FILEPATH=/opt/myfile

Isso faz com que o not work:

echo $FILEPATH_$DATEX

Isso funciona bem:

echo $FILEPATH\\_$DATEX
20
user2800471

Ainda outra abordagem ...

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

... e ainda outro.

> H="Hello "
> U=$H"universe."
> echo $U
Hello universe.
19
Akseli Palén

A maneira mais simples com aspas:

B=Bar
b=bar
var="$B""$b""a"
echo "Hello ""$var"
15
betontalpfa

Você pode concatenar sem as aspas. Aqui está um exemplo:

$Variable1 Open
$Variable2 Systems
$Variable3 $Variable1$Variable2
$echo $Variable3

Esta última declaração imprimiria "OpenSystems" (sem aspas).

Este é um exemplo de um script Bash:

v1=hello
v2=world
v3="$v1       $v2"
echo $v3            # Output: hello world
echo "$v3"          # Output: hello       world
15
mariana soffer

Mesmo se o operador + = agora for permitido, ele foi introduzido no Bash 3.1 em 2004.

Qualquer script que use esse operador em versões mais antigas do Bash falhará com um erro "comando não encontrado" se você tiver sorte ou um "erro de sintaxe próximo ao token inesperado".

Para aqueles que se preocupam com a retrocompatibilidade, siga os métodos de concatenação Bash padrão mais antigos, como os mencionados na resposta escolhida:

foo="Hello"
foo="$foo World"
echo $foo
> Hello World
14
Louis-Félix

Eu prefiro usar chaves ${} para expandir a variável na string:

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

Os colchetes encaracolados se encaixam no uso contínuo de cadeias de caracteres:

foo="Hello"
foo="${foo}World"
echo $foo
> HelloWorld

Caso contrário, usar foo = "$fooWorld" não funcionará.

13
Nick Tsai

Caminho mais seguro:

a="AAAAAAAAAAAA"
b="BBBBBBBBBBBB"
c="CCCCCCCCCCCC"
d="DD DD"
s="${a}${b}${c}${d}"
echo "$s"
AAAAAAAAAAAABBBBBBBBBBBBCCCCCCCCCCCCDD DD

Strings contendo espaços podem se tornar parte do comando, use "$ XXX" e "$ {XXX}" para evitar esses erros.

Além disso, dê uma olhada em outra resposta sobre + =

7
Bohdan

Se o que você está tentando fazer é split uma string em várias linhas, você pode usar uma barra invertida:

$ a="hello\
> world"
$ echo $a
helloworld

Com um espaço entre eles:

$ a="hello \
> world"
$ echo $a
hello world

Este também adiciona apenas um espaço entre eles:

$ a="hello \
>      world"
$ echo $a
hello world
7
jcarballo

Existe um caso particular em que você deve tomar cuidado:

user=daniel
cat > output.file << EOF
"$user"san
EOF

Vai produzir "daniel"san, e não danielsan, como você poderia querer. Neste caso, você deve fazer em vez disso:

user=daniel
cat > output.file << EOF
${user}san
EOF
6
diogovk

Se for como seu exemplo de adicionar " World" à string original, então pode ser:

#!/bin/bash

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

A saída:

Hello World
5
太極者無極而生
var1='hello'
var2='world'
var3=$var1" "$var2 
echo $var3
5
hari

Há dúvidas sobre o desempenho, mas nenhum dado é oferecido. Deixe-me sugerir um teste simples.

(NOTA: date no macOS não oferece nanossegundos, então isso deve ser feito no Linux.)

Eu criei append_test.sh no GitHub com o conteúdo:

#!/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

Teste 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

Teste 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

Os erros indicam que o meu Bash subiu para 335.54432 MB antes de ter travado. Você pode alterar o código da duplicação dos dados para acrescentar uma constante para obter um gráfico mais granular e um ponto de falha. Mas acho que isso deve lhe dar informações suficientes para decidir se você se importa. Pessoalmente, abaixo de 100 MB eu não faço. Sua milhagem pode variar.

4
Bruno Bronosky
a="Hello,"
a=$a" World!"
echo $a

É assim que você concatena duas strings.

4
CodeNinjaPI

Eu queria construir uma string de uma lista. Não foi possível encontrar uma resposta para isso, então eu postei aqui. Aqui está o que eu fiz:

list=(1 2 3 4 5)
string=''

for Elm in "${list[@]}"; do
    string="${string} ${Elm}"
done

echo ${string}

e então eu recebo a seguinte saída:

1 2 3 4 5
4
Simon Bachmann

Note que isso não vai funcionar

foo=HELLO
bar=WORLD
foobar=PREFIX_$foo_$bar

como parece cair $ foo e deixa você com:

PREFIX_WORLD

mas isso vai funcionar:

foobar=PREFIX_"$foo"_"$bar"

e deixar você com a saída correta:

PREFIX_HELLO_WORLD

3
Dss

Eu faço desta forma quando conveniente: use um comando inline!

echo "The current time is `date`"
echo "Current User: `echo $USER`"
1
Marty

Aqui está aquele através de AWK :

$ foo="Hello"
$ foo=$(awk -v var=$foo 'BEGIN{print var" World"}')
$ echo $foo
Hello World
1
Avinash Raj