Probablement bon de prendre l'habitude de mettre $foodes guillemets doubles, pour les moments où cela compte vraiment.
Cascabel
104
On nous apprend à toujours faire cela car lorsque la substitution a lieu, les espaces seront ignorés par le shell, mais les guillemets doubles protégeront toujours ces espaces.
Fraise
62
Doit-il y avoir un espace dans votre premier exemple? Est-il possible de faire quelque chose comme ça foo="$fooworld"? Je suppose que non ...
nonsensickle
341
@nonsensickle Cela rechercherait une variable nommée fooworld. Sans ambiguïté, cela se fait avec des accolades, comme dans foo="${foo}world"...
twalberg
4
@ JVE999 Oui, cela fonctionne aussi bien, mais à mon avis, ce n'est pas aussi bon pour la clarté du code ... Mais c'est peut-être ma préférence ... Il y a deux autres façons de le faire aussi - le fait est en s'assurant que le nom de variable est séparé des parties non nom-variable afin qu'il analyse correctement.
twalberg
1128
Bash prend également en charge un +=opérateur comme indiqué dans ce code:
Puis-je utiliser cette syntaxe avec le mot-clé d'exportation? par exemple export A+="Z"ou peut-être que la Avariable ne doit être exportée qu'une seule fois?
levesque
3
@levesque: Les deux :-). Les variables ne doivent être exportées qu'une seule fois, mais export A+=Zfonctionnent également très bien.
thkala
38
Comme il s'agit d'un bashisme, je pense qu'il vaut la peine de mentionner que vous ne devriez jamais utiliser #!/bin/shdans un script utilisant cette construction.
Score_Under
2
C'est spécifiquement et seulement un opérateur plus-égal. Autrement dit, contrairement à Javascript, dans Bash, l'écho $ A + $ B imprime "X Y + Z"
phpguru
6
Un bashisme est une fonction shell qui n'est prise en charge que dans bashcertains autres shell plus avancés. Il ne fonctionnera pas sous busybox shou dash(qui est /bin/shsur beaucoup de distributions), ou certains autres shells comme ceux /bin/shfournis sur FreeBSD.
Score_Under
960
Bash first
Comme cette question concerne spécifiquement Bash , ma première partie de la réponse présenterait différentes façons de le faire correctement:
+=: Ajouter à la variable
La syntaxe +=peut être utilisée de différentes manières:
Ajouter à la chaîne var+=...
(Parce que je suis frugal, je ne l' utilise deux variables fooet apuis réutiliser le même dans toute la réponse. ;-)
a=2
a+=4
echo $a24
En utilisant la syntaxe de question Stack Overflow ,
foo="Hello"
foo+=" World"
echo $fooHelloWorld
fonctionne bien!
Ajouter à un entier ((var+=...))
variable aest une chaîne, mais aussi un entier
echo $a24((a+=12))
echo $a36
Ajouter à un tableau var+=(...)
Notre aest également un tableau d'un seul élément.
Notez qu'entre parenthèses, il y a un tableau séparé par des espaces . Si vous souhaitez stocker une chaîne contenant des espaces dans votre tableau, vous devez les entourer:
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: Reconstruire la variable à l'aide de la commande intégrée
La commande printfintégrée donne un moyen puissant de dessiner le format de chaîne. Comme il s'agit d'un Bash intégré , il existe une option pour envoyer une chaîne formatée à une variable au lieu d'imprimer sur stdout:
echo ${a[@]}3618 one word hello world! hello world! hello world!
Il y a sept chaînes dans ce tableau. Nous pourrions donc construire une chaîne formatée contenant exactement sept arguments positionnels:
Nota: L'utilisation des guillemets doubles peut être utile pour manipuler des chaînes qui contiennent spaces, tabulationset / ounewlines
printf -v foo "%s World""$foo"
Shell maintenant
Sous le shell POSIX , vous ne pouviez pas utiliser de bashismes , il n'y a donc pas de fonction intégréeprintf .
Fondamentalement
Mais vous pourriez simplement faire:
foo="Hello"
foo="$foo World"
echo $fooHelloWorld
Formaté, en utilisant fourchueprintf
Si vous souhaitez utiliser des constructions plus sophistiquées, vous devez utiliser un fork (nouveau processus enfant qui fait le travail et renvoie le résultat via stdout):
L' +=opérateur est également beaucoup plus rapide que $a="$a$b"dans mes tests .. Ce qui est logique.
Matt
7
Cette réponse est géniale, mais je pense qu'il manque l' var=${var}.shexemple des autres réponses, ce qui est très utile.
geneorama
1
Est bashle seul shell avec +=opérateur? Je veux voir s'il est suffisamment portable
dashesy
1
@dashesy no. ce n'est sûrement pas le seul shell avec +=opérateur, mais tous ces moyens sont des bashismes , donc pas portables! Même vous pourriez rencontrer un bug spécial en cas de mauvaise version bash!
Bien qu'aucun caractère spécial, ni espace ne soit utilisé, les guillemets doubles, les guillemets et les accolades sont inutiles: var=myscript;var=$var.sh;echo $varauraient les mêmes effets (cela fonctionne sous bash, dash, busybox et autres).
F. Hauri
@ F.Hauri merci de l'avoir signalé. Mais si vous deviez ajouter un numéro, cela ne fonctionnerait pas: par exemple, echo $var2ne produit pasmyscript2
Pynchia
@Pynchia Cela fonctionne à cause du point .illégal dans le nom de variable. Sinon echo ${var}2ou voir ma réponse
F. Hauri
119
bla=hello
laber=kthx
echo "${bla}ohai${laber}bye"
Sortira
helloohaikthxbye
Ceci est utile lorsque
$blaohai
conduit à une erreur de variable non trouvée. Ou si vous avez des espaces ou d'autres caractères spéciaux dans vos chaînes. "${foo}"échappe correctement tout ce que vous y mettez.
C'est la réponse la plus utile pour les scripts shell. Je me suis retrouvé les 30 dernières minutes car j'avais un espace avant et après le signe égal !!
Stefan
8
foo = "$ {foo} World"
XXL
@XXL Je préfère sûrement utiliser des crochets pour encapsuler le nom de var. Fortement recommandé
Sergio A.
33
La façon dont je résoudrais le problème est simplement
$a$b
Par exemple,
a="Hello"
b=" World"
c=$a$b
echo "$c"
qui produit
HelloWorld
Si vous essayez de concaténer une chaîne avec une autre chaîne, par exemple,
a="Hello"
c="$a World"
puis echo "$c"produira
HelloWorld
avec un espace supplémentaire.
$aWorld
ne fonctionne pas, comme vous pouvez l'imaginer, mais
Cela me surprend; Je me serais attendu c=$a$bici à faire la même chose que c=$a World(qui essaierait de fonctionner Worldcomme une commande). Je suppose que cela signifie que l'affectation est analysée avant que les variables ne soient développées ..
mwfearnley
31
Voici un résumé concis de ce dont parlent la plupart des réponses.
Disons que nous avons deux variables et que $ 1 est réglé sur «un»:
set one two
a=hello
b=world
Le tableau ci - dessous explique les différents contextes où l' on peut combiner les valeurs aet bde créer une nouvelle variable, 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
Quelques notes:
mettre le RHS d'une affectation entre guillemets est généralement une bonne pratique, bien qu'elle soit tout à fait facultative dans de nombreux cas
+= est meilleur du point de vue des performances si une grosse chaîne est construite en petits incréments, en particulier dans une boucle
utilisez {}autour des noms de variables pour lever l'ambiguïté de leur expansion (comme dans la ligne 2 du tableau ci-dessus). Comme on le voit sur les lignes 3 et 4, il n'est pas nécessaire {}sauf si une variable est concaténée avec une chaîne qui commence par un caractère qui est un premier caractère valide dans le nom de la variable shell, c'est-à-dire l'alphabet ou le trait de soulignement.
C'est ce que j'ai fait et je l'ai trouvé tellement simple et direct que les autres réponses. Y a-t-il une raison pour laquelle personne sur les réponses les plus votées n'a signalé cette option?
quimnuss
1
@quimnuss Le fait que les chaînes ne correspondent pas à celles utilisées dans la question OP peut être une bonne raison.
jlliagre
20
Si vous souhaitez ajouter quelque chose comme un trait de soulignement, utilisez escape (\)
Ou bien, $ {FILEPATH} _ $ DATEX. Ici, {} sont utilisés pour indiquer les limites du nom de la variable. Ceci est approprié car le trait de soulignement est un caractère légal dans les noms de variable, donc dans votre extrait de code bash essaie en fait de résoudre FILEPATH_, pas seulement $ FILEPATH
Nik O'Lai
1
pour moi, j'avais une variable, à savoir $ var1 et constante à côté de cela, donc echo $ var1_costant_traling_part fonctionne pour moi
YouAreAwesome
2
Je suppose que l'on n'a besoin que d'un seul jeu pour s'échapper: echo $a\_$bferait l'affaire. Comme l'indique le commentaire de Nik O'Lai, le trait de soulignement est un personnage régulier. La gestion des espaces blancs est beaucoup plus sensible pour les chaînes, l'écho et la concaténation --- on peut utiliser \ et lire attentivement ce fil car ce problème revient de temps en temps.
La syntaxe du premier bloc prête à confusion. Que signifient ces signes $?
XavierStuvw
15
Même si l'opérateur + = est désormais autorisé, il a été introduit dans Bash 3.1 en 2004.
Tout script utilisant cet opérateur sur les anciennes versions de Bash échouera avec une erreur "commande introuvable" si vous êtes chanceux, ou une "erreur de syntaxe près d'un jeton inattendu".
Pour ceux qui se soucient de la compatibilité descendante, respectez les anciennes méthodes de concaténation Bash standard, comme celles mentionnées dans la réponse choisie:
Le point des chaînes avec un espace lu comme une commande apparaît au point de définition. Alors d=DD DDdonnerait DD: command not found--- note qui est la dernière DD plutôt d qu'on ne trouve pas. Si tous les opérandes sont correctement formatés et contiennent déjà les espaces requis, vous pouvez simplement concaténer avec s=${a}${b}${c}${d}; echo $s, avec moins de guillemets. Vous pouvez également utiliser \ (espaces blancs échappés) pour éviter ces problèmes --- d=echo\ echone lancera aucune invocation d'écho, alors que le d=echo echofera.
XavierStuvw
7
Il y a un cas particulier où vous devez faire attention:
Cela fonctionne, mais cela donnera parfois des résultats imprévisibles car l'interpolation variable n'est pas protégée. Ainsi, vous ne pouvez pas compter sur ce formulaire pour tous les cas d'utilisation.
Anthony Rutledge
5
S'il s'agit de votre exemple d'ajout " World"à la chaîne d'origine, cela peut être:
Les erreurs indiquent que mon Bash a atteint 335,54432 Mo avant de planter. Vous pouvez changer le code de doubler les données à ajouter une constante pour obtenir un graphique plus précis et un point de défaillance. Mais je pense que cela devrait vous donner suffisamment d'informations pour décider si vous vous souciez. Personnellement, en dessous de 100 Mo, je n'en ai pas. Votre kilométrage peut varier.
cela se produit car le trait de soulignement est le caractère valide dans les noms de variable, donc bash voit foo_ comme une variable. Lorsqu'il est nécessaire de dire à bash les limites exactes du nom var, les accolades peuvent être utilisées: PREFIX _ $ {foo} _ $ bar
En 1ère ligne, vous pouvez supprimer une fourchette en utilisant:, date "+The current time is %a %b %d %Y +%T"au lieu de echo ...$(date). Sous bash récente, vous pouvez écrire: printf "The current time is %(%a %b %d %Y +%T)T\n" -1.
F.Hauri
1
À mon avis, la façon la plus simple de concaténer deux chaînes est d'écrire une fonction qui le fait pour vous, puis d'utiliser cette fonction.
foo="Hello"
foo=$foo" World"
echo $foo
cela a plutôt fonctionné pour "#! / bin / sh"foo1="World" foo2="Hello" foo3="$foo1$foo2"
Réponses:
En général, pour concaténer deux variables, vous pouvez simplement les écrire l'une après l'autre:
la source
$foo
des guillemets doubles, pour les moments où cela compte vraiment.foo="$fooworld"
? Je suppose que non ...fooworld
. Sans ambiguïté, cela se fait avec des accolades, comme dansfoo="${foo}world"
...Bash prend également en charge un
+=
opérateur comme indiqué dans ce code:la source
export A+="Z"
ou peut-être que laA
variable ne doit être exportée qu'une seule fois?export A+=Z
fonctionnent également très bien.#!/bin/sh
dans un script utilisant cette construction.bash
certains autres shell plus avancés. Il ne fonctionnera pas sousbusybox sh
oudash
(qui est/bin/sh
sur beaucoup de distributions), ou certains autres shells comme ceux/bin/sh
fournis sur FreeBSD.Bash first
Comme cette question concerne spécifiquement Bash , ma première partie de la réponse présenterait différentes façons de le faire correctement:
+=
: Ajouter à la variableLa syntaxe
+=
peut être utilisée de différentes manières:Ajouter à la chaîne
var+=...
(Parce que je suis frugal, je ne l' utilise deux variables
foo
eta
puis réutiliser le même dans toute la réponse. ;-)En utilisant la syntaxe de question Stack Overflow ,
fonctionne bien!
Ajouter à un entier
((var+=...))
variable
a
est une chaîne, mais aussi un entierAjouter à un tableau
var+=(...)
Notre
a
est également un tableau d'un seul élément.Notez qu'entre parenthèses, il y a un tableau séparé par des espaces . Si vous souhaitez stocker une chaîne contenant des espaces dans votre tableau, vous devez les entourer:
Hmm .. ce n'est pas un bug, mais une fonctionnalité ... Pour empêcher bash d'essayer de se développer
!"
, vous pourriez:printf
: Reconstruire la variable à l'aide de la commande intégréeLa commande
printf
intégrée donne un moyen puissant de dessiner le format de chaîne. Comme il s'agit d'un Bash intégré , il existe une option pour envoyer une chaîne formatée à une variable au lieu d'imprimer surstdout
:Il y a sept chaînes dans ce tableau. Nous pourrions donc construire une chaîne formatée contenant exactement sept arguments positionnels:
Ou nous pourrions utiliser une chaîne de format d'argument qui sera répétée autant d'arguments soumis ...
Notez que notre
a
est toujours un tableau! Seul le premier élément est modifié!Sous bash, lorsque vous accédez à un nom de variable sans spécifier d'index, vous n'adressez toujours que le premier élément!
Donc, pour récupérer notre tableau à sept champs, il suffit de réinitialiser le 1er élément:
Une chaîne de format d'argument avec plusieurs arguments passés à:
Utilisation de la syntaxe de question Stack Overflow :
Nota: L'utilisation des guillemets doubles peut être utile pour manipuler des chaînes qui contiennent
spaces
,tabulations
et / ounewlines
Shell maintenant
Sous le shell POSIX , vous ne pouviez pas utiliser de bashismes , il n'y a donc pas de fonction intégrée
printf
.Fondamentalement
Mais vous pourriez simplement faire:
Formaté, en utilisant fourchue
printf
Si vous souhaitez utiliser des constructions plus sophistiquées, vous devez utiliser un fork (nouveau processus enfant qui fait le travail et renvoie le résultat via
stdout
):Historiquement, vous pouviez utiliser des backticks pour récupérer le résultat d'un fork :
Mais ce n'est pas facile pour l' imbrication :
avec des contre-coups, vous devez échapper aux fourches intérieures avec des contre - obliques :
la source
+=
opérateur est également beaucoup plus rapide que$a="$a$b"
dans mes tests .. Ce qui est logique.var=${var}.sh
exemple des autres réponses, ce qui est très utile.bash
le seul shell avec+=
opérateur? Je veux voir s'il est suffisamment portable+=
opérateur, mais tous ces moyens sont des bashismes , donc pas portables! Même vous pourriez rencontrer un bug spécial en cas de mauvaise version bash!Vous pouvez le faire aussi:
la source
var=myscript;var=$var.sh;echo $var
auraient les mêmes effets (cela fonctionne sous bash, dash, busybox et autres).echo $var2
ne produit pasmyscript2
.
illégal dans le nom de variable. Sinonecho ${var}2
ou voir ma réponseSortira
Ceci est utile lorsque
$blaohai
conduit à une erreur de variable non trouvée. Ou si vous avez des espaces ou d'autres caractères spéciaux dans vos chaînes."${foo}"
échappe correctement tout ce que vous y mettez.la source
la source
La façon dont je résoudrais le problème est simplement
Par exemple,
qui produit
Si vous essayez de concaténer une chaîne avec une autre chaîne, par exemple,
puis
echo "$c"
produiraavec un espace supplémentaire.
ne fonctionne pas, comme vous pouvez l'imaginer, mais
produit
la source
${a}\ World
produitHello World
c=$a$b
ici à faire la même chose quec=$a World
(qui essaierait de fonctionnerWorld
comme une commande). Je suppose que cela signifie que l'affectation est analysée avant que les variables ne soient développées ..Voici un résumé concis de ce dont parlent la plupart des réponses.
Disons que nous avons deux variables et que $ 1 est réglé sur «un»:
Le tableau ci - dessous explique les différents contextes où l' on peut combiner les valeurs
a
etb
de créer une nouvelle variable,c
.Quelques notes:
+=
est meilleur du point de vue des performances si une grosse chaîne est construite en petits incréments, en particulier dans une boucle{}
autour des noms de variables pour lever l'ambiguïté de leur expansion (comme dans la ligne 2 du tableau ci-dessus). Comme on le voit sur les lignes 3 et 4, il n'est pas nécessaire{}
sauf si une variable est concaténée avec une chaîne qui commence par un caractère qui est un premier caractère valide dans le nom de la variable shell, c'est-à-dire l'alphabet ou le trait de soulignement.Voir également:
la source
la source
Encore une autre approche ...
... et encore un autre.
la source
Si vous souhaitez ajouter quelque chose comme un trait de soulignement, utilisez escape (\)
Cela ne fonctionne pas :
Cela fonctionne bien:
la source
echo $a\_$b
ferait l'affaire. Comme l'indique le commentaire de Nik O'Lai, le trait de soulignement est un personnage régulier. La gestion des espaces blancs est beaucoup plus sensible pour les chaînes, l'écho et la concaténation --- on peut utiliser\
et lire attentivement ce fil car ce problème revient de temps en temps.La manière la plus simple avec des guillemets:
la source
var=$B$b"a"; echo Hello\ $var
ferait, je croisVous pouvez concaténer sans les guillemets. Voici un exemple:
Cette dernière instruction afficherait "OpenSystems" (sans guillemets).
Voici un exemple de script Bash:
la source
Même si l'opérateur + = est désormais autorisé, il a été introduit dans Bash 3.1 en 2004.
Tout script utilisant cet opérateur sur les anciennes versions de Bash échouera avec une erreur "commande introuvable" si vous êtes chanceux, ou une "erreur de syntaxe près d'un jeton inattendu".
Pour ceux qui se soucient de la compatibilité descendante, respectez les anciennes méthodes de concaténation Bash standard, comme celles mentionnées dans la réponse choisie:
la source
Je préfère utiliser des accolades
${}
pour développer la variable dans la chaîne:Les accolades correspondent à l'utilisation continue de la chaîne:
Sinon, l'utilisation
foo = "$fooWorld"
ne fonctionnera pas.la source
Si ce que vous essayez de faire est de diviser une chaîne en plusieurs lignes, vous pouvez utiliser une barre oblique inverse:
Avec un espace entre les deux:
Celui-ci ajoute également un seul espace entre les deux:
la source
Moyen plus sûr:
Les chaînes contenant des espaces peuvent faire partie de la commande, utilisez "$ XXX" et "$ {XXX}" pour éviter ces erreurs.
De plus, jetez un œil à une autre réponse concernant + =
la source
d=DD DD
donneraitDD: command not found
--- note qui est la dernière DD plutôt d qu'on ne trouve pas. Si tous les opérandes sont correctement formatés et contiennent déjà les espaces requis, vous pouvez simplement concaténer avecs=${a}${b}${c}${d}; echo $s
, avec moins de guillemets. Vous pouvez également utiliser\
(espaces blancs échappés) pour éviter ces problèmes ---d=echo\ echo
ne lancera aucune invocation d'écho, alors que led=echo echo
fera.Il y a un cas particulier où vous devez faire attention:
Sortira
"daniel"san
, et nondanielsan
, comme vous l'auriez voulu. Dans ce cas, vous devez faire à la place:la source
Voici comment concaténer deux chaînes.
la source
S'il s'agit de votre exemple d'ajout
" World"
à la chaîne d'origine, cela peut être:Le résultat:
la source
la source
var3=$var1\ $var2
le même effetDes inquiétudes ont été exprimées concernant les performances, mais aucune donnée n'est proposée. Permettez-moi de suggérer un test simple.
(REMARQUE:
date
sur macOS n'offre pas de nanosecondes, donc cela doit être fait sur Linux.)J'ai créé append_test.sh sur GitHub avec le contenu:
Test 1:
Test 2:
Les erreurs indiquent que mon Bash a atteint 335,54432 Mo avant de planter. Vous pouvez changer le code de doubler les données à ajouter une constante pour obtenir un graphique plus précis et un point de défaillance. Mais je pense que cela devrait vous donner suffisamment d'informations pour décider si vous vous souciez. Personnellement, en dessous de 100 Mo, je n'en ai pas. Votre kilométrage peut varier.
la source
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"
(Essayez ceci sur un hôte non productif !!;)Je voulais construire une chaîne à partir d'une liste. Je n'ai pas trouvé de réponse à cela, alors je la poste ici. Voici ce que j'ai fait:
puis j'obtiens la sortie suivante:
la source
Malgré l'opérateur spécial
+=
, pour la concaténation, il existe un moyen plus simple de procéder:Les guillemets doubles prennent un temps de calcul supplémentaire pour l'interprétation des variables à l'intérieur. Évitez-le si possible.
la source
Notez que cela ne fonctionnera pas
car il semble laisser tomber $ foo et vous laisse avec:
mais cela fonctionnera:
et vous laisse avec la sortie correcte:
la source
Voici celui via AWK :
la source
Je le fais de cette façon quand c'est pratique: Utilisez une commande en ligne!
la source
date "+The current time is %a %b %d %Y +%T"
au lieu deecho ...$(date)
. Sous bash récente, vous pouvez écrire:printf "The current time is %(%a %b %d %Y +%T)T\n" -1
.À mon avis, la façon la plus simple de concaténer deux chaînes est d'écrire une fonction qui le fait pour vous, puis d'utiliser cette fonction.
la source
J'aime un peu faire une fonction rapide.
Encore une autre façon d'écorcher un chat. Cette fois avec des fonctions: D
la source
Je ne connais pas encore PHP, mais cela fonctionne dans Linux Bash. Si vous ne voulez pas l'affecter à une variable, vous pouvez essayer ceci:
Vous pouvez placer une autre variable au lieu de «Bonjour» ou «!». Vous pouvez également concaténer plus de chaînes.
la source