Provavelmente é bom adquirir o hábito de colocar $fooaspas duplas, nos momentos em que realmente importa.
Cascabel
104
Somos ensinados a sempre fazer isso porque, quando a substituição ocorre, os espaços serão ignorados pelo shell, mas as aspas duplas sempre protegem esses espaços.
Strawberry
62
Tem que haver um espaço no seu primeiro exemplo? É possível fazer algo assim foo="$fooworld"? Eu diria que não ...
nonsensickle
341
@ nonsensickle Isso procuraria uma variável chamada fooworld. Disambiguating que é feito com colchetes, como foo="${foo}world"...
twalberg
4
@ JVE999 Sim, isso também funciona, embora, na minha opinião, não seja tão bom quanto à clareza do código ... Mas isso pode ser apenas a minha preferência ... Existem outras maneiras de fazer isso - o ponto é certificando-se de que o nome da variável seja separado das partes que não são de variáveis, para que seja analisado corretamente.
twalberg
1128
O Bash também suporta um +=operador, como mostrado neste código:
Posso usar esta sintaxe com a palavra-chave exportar? por exemplo, export A+="Z"ou talvez a Avariável precise ser exportada apenas uma vez?
Leveque
3
@levesque: Ambos :-). As variáveis precisam ser exportadas apenas uma vez, mas também export A+=Zfuncionam muito bem.
Thkala
38
Como isso é um basismo, acho que vale a pena mencionar que você nunca deve usar #!/bin/shum script usando essa construção.
Score_Under
2
É especificamente e apenas um operador mais-igual. Ou seja, ao contrário de Javascript, em Bash, eco impressões $ A + $ B "X Y + Z"
phpguru
6
Um bashism é um recurso de shell que é suportado apenas em bashe em alguns outros shells mais avançados. Não funcionará sob busybox shou dash(que está /bin/shem muitas distros), ou em alguns outros shells, como o /bin/shfornecido no FreeBSD.
Score_Under
960
Bash primeiro
Como esta pergunta se refere especificamente ao Bash , minha primeira parte da resposta apresentaria diferentes maneiras de fazer isso corretamente:
+=: Anexar à variável
A sintaxe +=pode ser usada de diferentes maneiras:
Anexar à string var+=...
(Porque eu sou frugal, eu só vai usar duas variáveis fooe aem seguida, re-utilizar o mesmo em toda a resposta. ;-)
a=2
a+=4
echo $a
24
Usando a sintaxe da pergunta Stack Overflow ,
foo="Hello"
foo+=" World"
echo $foo
HelloWorld
funciona bem!
Anexar a um número inteiro ((var+=...))
A variável aé uma sequência, mas também um número inteiro
Observe que entre parênteses, há uma matriz separada por espaço . Se você deseja armazenar uma sequência contendo espaços em sua matriz, é necessário incluí-los:
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: Reconstrua a variável usando o comando embutido
O comando printfinterno fornece uma maneira poderosa de desenhar o formato de sequência. Como este é um Bash embutido , há uma opção para enviar uma string formatada para uma variável em vez de imprimir em stdout:
echo ${a[@]}3618 one word hello world! hello world! hello world!
O +=operador também é muito mais rápido do que $a="$a$b"nos meus testes. O que faz sentido.
Matt
7
Esta resposta é incrível, mas acho que está faltando o var=${var}.shexemplo de outras respostas, o que é muito útil.
geneorama
1
É basho único shell com +=operador? Quero ver se ele é portátil o suficiente
dashesy
1
@dashesy no. Certamente não é o único shell com +=operador, mas todas essas formas são basismos , portanto não portáteis! Mesmo você pode encontrar um bug especial em caso de versão errada do bash!
Embora não sejam utilizados caracteres especiais nem espaços, aspas duplas, aspas e colchetes são inúteis: var=myscript;var=$var.sh;echo $varteriam os mesmos efeitos (este trabalho em bash, dash, busybox e outros).
F. Hauri
@ F.Hauri obrigado por apontar isso. Mas se você fosse para acrescentar um número, ele não iria funcionar: por exemplo, echo $var2não produzmyscript2
Pynchia
@ Synchia Este trabalho é devido ao ponto .ilegal no nome da variável. Se outra pessoa echo ${var}2ou ver a minha resposta
F. Hauri
119
bla=hello
laber=kthx
echo "${bla}ohai${laber}bye"
Saída
helloohaikthxbye
Isso é útil quando
$blaohai
leva a um erro de variável não encontrada. Ou se você tiver espaços ou outros caracteres especiais em suas seqüências. "${foo}"escapa adequadamente tudo o que você coloca nele.
Esta é a resposta mais útil para scripts de shell. Eu me encontrei nos últimos 30 minutos, porque eu tinha um espaço antes e depois do sinal de igual !!
Stefan
8
foo = "$ {foo} World"
XXL
@XXL certamente prefiro usar colchetes para encapsular o nome do var. Altamente recomendado
Sergio A.
33
A maneira como eu resolveria o problema é apenas
$a$b
Por exemplo,
a="Hello"
b=" World"
c=$a$b
echo "$c"
que produz
HelloWorld
Se você tentar concatenar uma sequência com outra, por exemplo,
Isso me surpreende; Eu esperava c=$a$baqui fazer a mesma coisa que c=$a World(que tentaria executar Worldcomo um comando). Eu acho que significa que a atribuição é analisado antes de as variáveis são expandidas ..
mwfearnley
30
Aqui está um resumo conciso do que a maioria das respostas está falando.
Digamos que temos duas variáveis e $ 1 é definido como 'one':
set one two
a=hello
b=world
A tabela abaixo explica os diferentes contextos em que podemos combinar os valores ae bcriar 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 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
Algumas notas:
incluir o RHS de uma tarefa entre aspas duplas geralmente é uma boa prática, embora seja bastante opcional em muitos casos
+= é melhor do ponto de vista de desempenho se uma grande string estiver sendo construída em pequenos incrementos, especialmente em um loop
use em {}torno de nomes de variáveis para desambiguar sua expansão (como na linha 2 da tabela acima). Como visto nas linhas 3 e 4, não há necessidade, a {}menos que uma variável esteja sendo concatenada com uma sequência que comece com um caractere que seja um primeiro caractere válido no nome da variável do shell, que é alfabeto ou sublinhado.
Ou, como alternativa, $ {FILEPATH} _ $ DATEX. Aqui {} são usados para indicar os limites do nome da variável. Esta é appropariate porque o sublinhado é um personagem legal em nomes de variáveis, portanto, em sua festança trecho realmente tenta resolver FILEPATH_, não apenas US $ FILEPATH
Nik O'Lai
1
para mim, eu tinha uma variável, ou seja, $ var1 e constante ao lado, para que o eco $ var1_costant_traling_part funcione para mim
YouAreAwesome
2
Acho que é preciso apenas uma reação para escapar: echo $a\_$bfaria. Como sugerido no comentário de Nik O'Lai, o sublinhado é um personagem regular. O manuseio de espaços em branco é muito mais sensível a seqüências de caracteres, eco e concatenação - é possível usar \ e ler completamente este encadeamento, pois esse problema volta agora e depois.
A sintaxe do primeiro bloco é confusa. O que esses sinais $ significam?
XavierStuvw
15
Mesmo que o operador + = agora seja 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 com um "erro de sintaxe próximo ao token inesperado".
Para quem se preocupa com a compatibilidade com versões anteriores, siga os métodos de concatenação Bash padrão mais antigos, como os mencionados na resposta escolhida:
O ponto das strings com um espaço que é lido como um comando aparece no ponto de definição. Então d=DD DD, daria DD: command not found--- note que esse é o último DD, e não o que foi encontrado. Se todos os operandos estiverem formatados corretamente e já contiverem os espaços necessários, você poderá simplesmente concatenar com s=${a}${b}${c}${d}; echo $s, com menos aspas. Além disso, você pode usar \ (espaço em branco com escape) para evitar esses problemas - d=echo\ echonão iniciará nenhuma chamada de eco, enquanto o d=echo echofará.
XavierStuvw
7
Há um caso específico em que você deve tomar cuidado:
Isso funciona, mas às vezes gera resultados imprevisíveis porque a interpolação variável não está protegida. Portanto, você não pode confiar neste formulário para todos os casos de uso.
Anthony Rutledge
5
Se for o seu exemplo de adição " World"à string original, poderá ser:
Os erros indicam que meu Bash chegou a 335.54432 MB antes de travar . Você pode alterar o código de duplicar os dados para acrescentar uma constante para obter um gráfico mais granular e um ponto de falha. Mas acho que isso deve lhe fornecer informações suficientes para decidir se você se importa. Pessoalmente, abaixo de 100 MB, não. Sua milhagem pode variar.
isso acontece porque o sublinhado é o caractere válido nos nomes das variáveis; portanto, o bash vê foo_ como uma variável. Quando é necessário informar ao bash os limites exatos do nome do var, os chavetas podem ser usadas: PREFIXAR _ $ {foo} _ $ bar
Na 1ª linha, você pode soltar um garfo usando :, em date "+The current time is %a %b %d %Y +%T"vez de echo ...$(date). Sob recente bash, você poderia escrever: printf "The current time is %(%a %b %d %Y +%T)T\n" -1.
31514 F Hauri
1
Na minha opinião, a maneira mais simples de concatenar duas strings é escrever uma função que faça isso por você e, em seguida, usar essa função.
foo="Hello"
foo=$foo" World"
echo $foo
esta vez trabalhou para "#! / bin / sh!"foo1="World" foo2="Hello" foo3="$foo1$foo2"
Respostas:
Em geral, para concatenar duas variáveis, basta escrevê-las uma após a outra:
fonte
$foo
aspas duplas, nos momentos em que realmente importa.foo="$fooworld"
? Eu diria que não ...fooworld
. Disambiguating que é feito com colchetes, comofoo="${foo}world"
...O Bash também suporta um
+=
operador, como mostrado neste código:fonte
export A+="Z"
ou talvez aA
variável precise ser exportada apenas uma vez?export A+=Z
funcionam muito bem.#!/bin/sh
um script usando essa construção.bash
e em alguns outros shells mais avançados. Não funcionará sobbusybox sh
oudash
(que está/bin/sh
em muitas distros), ou em alguns outros shells, como o/bin/sh
fornecido no FreeBSD.Bash primeiro
Como esta pergunta se refere especificamente ao Bash , minha primeira parte da resposta apresentaria diferentes maneiras de fazer isso corretamente:
+=
: Anexar à variávelA sintaxe
+=
pode ser usada de diferentes maneiras:Anexar à string
var+=...
(Porque eu sou frugal, eu só vai usar duas variáveis
foo
ea
em seguida, re-utilizar o mesmo em toda a resposta. ;-)Usando a sintaxe da pergunta Stack Overflow ,
funciona bem!
Anexar a um número inteiro
((var+=...))
A variável
a
é uma sequência, mas também um número inteiroAnexar a uma matriz
var+=(...)
Nossa
a
também é uma matriz de apenas um elemento.Observe que entre parênteses, há uma matriz separada por espaço . Se você deseja armazenar uma sequência contendo espaços em sua matriz, é necessário incluí-los:
Hmm .. isso não é um bug, mas um recurso ... Para impedir que o bash tente se desenvolver
!"
, você pode:printf
: Reconstrua a variável usando o comando embutidoO comando
printf
interno fornece uma maneira poderosa de desenhar o formato de sequência. Como este é um Bash embutido , há uma opção para enviar uma string formatada para uma variável em vez de imprimir emstdout
:Existem sete strings nessa matriz. Assim, poderíamos construir uma string formatada contendo exatamente sete argumentos posicionais:
Ou podemos usar uma string de formato de argumento que será repetida como muitos argumentos enviados ...
Note que o nosso
a
ainda é um array! Apenas o primeiro elemento é alterado!No bash, quando você acessa um nome de variável sem especificar o índice, sempre aborda apenas o primeiro elemento!
Portanto, para recuperar nossa matriz de sete campos, precisamos redefinir apenas o 1º elemento:
Uma sequência de formato de argumento com muitos argumentos transmitidos para:
Usando a sintaxe da pergunta Stack Overflow :
Nota: O uso de aspas podem ser úteis para a manipulação de cadeias que contêm
spaces
,tabulations
e / ounewlines
Shell agora
Sob o shell POSIX , você não pode usar basismos , portanto, não há construtores
printf
.Basicamente
Mas você poderia simplesmente fazer:
Formatado, usando bifurcada
printf
Se você quiser usar construções mais sofisticadas, precisará usar um fork (novo processo filho que faz o trabalho e retorna o resultado via
stdout
):Historicamente, você poderia usar reticulares para recuperar o resultado de um garfo :
Mas isso não é fácil para aninhar :
com barras, você precisa escapar dos garfos internos com barras invertidas :
fonte
+=
operador também é muito mais rápido do que$a="$a$b"
nos meus testes. O que faz sentido.var=${var}.sh
exemplo de outras respostas, o que é muito útil.bash
o único shell com+=
operador? Quero ver se ele é portátil o suficiente+=
operador, mas todas essas formas são basismos , portanto não portáteis! Mesmo você pode encontrar um bug especial em caso de versão errada do bash!Você também pode fazer isso:
fonte
var=myscript;var=$var.sh;echo $var
teriam os mesmos efeitos (este trabalho em bash, dash, busybox e outros).echo $var2
não produzmyscript2
.
ilegal no nome da variável. Se outra pessoaecho ${var}2
ou ver a minha respostaSaída
Isso é útil quando
$blaohai
leva a um erro de variável não encontrada. Ou se você tiver espaços ou outros caracteres especiais em suas seqüências."${foo}"
escapa adequadamente tudo o que você coloca nele.fonte
fonte
A maneira como eu resolveria o problema é apenas
Por exemplo,
que produz
Se você tentar concatenar uma sequência com outra, por exemplo,
então
echo "$c"
irá produzircom um espaço extra.
não funciona, como você pode imaginar, mas
produz
fonte
${a}\ World
produzHello World
c=$a$b
aqui fazer a mesma coisa quec=$a World
(que tentaria executarWorld
como um comando). Eu acho que significa que a atribuição é analisado antes de as variáveis são expandidas ..Aqui está um resumo conciso do que a maioria das respostas está falando.
Digamos que temos duas variáveis e $ 1 é definido como 'one':
A tabela abaixo explica os diferentes contextos em que podemos combinar os valores
a
eb
criar uma nova variávelc
.Algumas notas:
+=
é melhor do ponto de vista de desempenho se uma grande string estiver sendo construída em pequenos incrementos, especialmente em um loop{}
torno de nomes de variáveis para desambiguar sua expansão (como na linha 2 da tabela acima). Como visto nas linhas 3 e 4, não há necessidade, a{}
menos que uma variável esteja sendo concatenada com uma sequência que comece com um caractere que seja um primeiro caractere válido no nome da variável do shell, que é alfabeto ou sublinhado.Veja também:
fonte
fonte
Ainda outra abordagem ...
... e ainda mais um.
fonte
Se você deseja acrescentar algo como um sublinhado, use escape (\)
Isso não funciona:
Isso funciona bem:
fonte
echo $a\_$b
faria. Como sugerido no comentário de Nik O'Lai, o sublinhado é um personagem regular. O manuseio de espaços em branco é muito mais sensível a seqüências de caracteres, eco e concatenação - é possível usar\
e ler completamente este encadeamento, pois esse problema volta agora e depois.A maneira mais simples com aspas:
fonte
var=$B$b"a"; echo Hello\ $var
faria, acredito eu #Você pode concatenar sem as aspas. Aqui está um exemplo:
Esta última declaração imprimiria "OpenSystems" (sem aspas).
Este é um exemplo de script Bash:
fonte
Mesmo que o operador + = agora seja 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 com um "erro de sintaxe próximo ao token inesperado".
Para quem se preocupa com a compatibilidade com versões anteriores, siga os métodos de concatenação Bash padrão mais antigos, como os mencionados na resposta escolhida:
fonte
Eu prefiro usar colchetes
${}
para expandir a variável na string:Os colchetes encaixam-se ao uso contínuo das cordas:
Caso contrário, o uso
foo = "$fooWorld"
não funcionará.fonte
Se o que você está tentando fazer é dividir uma sequência em várias linhas, você pode usar uma barra invertida:
Com um espaço no meio:
Este também adiciona apenas um espaço no meio:
fonte
Maneira mais segura:
Seqüências de caracteres que contêm espaços podem se tornar parte do comando, use "$ XXX" e "$ {XXX}" para evitar esses erros.
Além disso, dê uma olhada em outras respostas sobre + =
fonte
d=DD DD
, dariaDD: command not found
--- note que esse é o último DD, e não o que foi encontrado. Se todos os operandos estiverem formatados corretamente e já contiverem os espaços necessários, você poderá simplesmente concatenar coms=${a}${b}${c}${d}; echo $s
, com menos aspas. Além disso, você pode usar\
(espaço em branco com escape) para evitar esses problemas -d=echo\ echo
não iniciará nenhuma chamada de eco, enquanto od=echo echo
fará.Há um caso específico em que você deve tomar cuidado:
Produzirá
"daniel"san
, e nãodanielsan
, como você poderia querer. Nesse caso, você deve fazer:fonte
É assim que você concatena duas strings.
fonte
Se for o seu exemplo de adição
" World"
à string original, poderá ser:A saída:
fonte
fonte
var3=$var1\ $var2
tem o mesmo efeitoHá preocupações expressas sobre desempenho, mas nenhum dado é oferecido. Deixe-me sugerir um teste simples.
(NOTA:
date
no macOS não oferece nanossegundos, portanto, isso deve ser feito no Linux.)Eu criei append_test.sh no GitHub com o conteúdo:
Teste 1:
Teste 2:
Os erros indicam que meu Bash chegou a 335.54432 MB antes de travar . Você pode alterar o código de duplicar os dados para acrescentar uma constante para obter um gráfico mais granular e um ponto de falha. Mas acho que isso deve lhe fornecer informações suficientes para decidir se você se importa. Pessoalmente, abaixo de 100 MB, não. Sua milhagem pode variar.
fonte
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"
(Tente isso em um host não produtivo !!;)Eu queria construir uma string a partir de uma lista. Não foi possível encontrar uma resposta para isso, então eu posto aqui. Aqui está o que eu fiz:
e então recebo a seguinte saída:
fonte
Apesar do operador especial
+=
, para concatenação, há um caminho mais simples a seguir:As aspas duplas levam um tempo de cálculo extra para a interpretação das variáveis internas. Evite se possível.
fonte
Observe que isso não vai funcionar
como parece soltar $ foo e deixa você com:
mas isso vai funcionar:
e deixar você com a saída correta:
fonte
Aqui está o AWK :
fonte
Faço-o desta maneira quando conveniente: Use um comando embutido!
fonte
date "+The current time is %a %b %d %Y +%T"
vez deecho ...$(date)
. Sob recente bash, você poderia escrever:printf "The current time is %(%a %b %d %Y +%T)T\n" -1
.Na minha opinião, a maneira mais simples de concatenar duas strings é escrever uma função que faça isso por você e, em seguida, usar essa função.
fonte
Eu meio que gosto de fazer uma função rápida.
Mais uma maneira de esfolar um gato. Desta vez com funções: D
fonte
Ainda não sei o PHP, mas isso funciona no Linux Bash. Se você não deseja afetá-lo em uma variável, tente o seguinte:
Você pode colocar outra variável em vez de 'Hello' ou '!'. Você também pode concatenar mais seqüências de caracteres.
fonte