En PHP, les chaînes sont concaténées comme suit:
$foo = "Hello";
$foo .= " World";
Ici, $foo
devient "Hello World".
Comment cela se fait-il dans Bash?
foo1="World" foo2="Hello" foo3="$foo1$foo2"
En PHP, les chaînes sont concaténées comme suit:
$foo = "Hello";
$foo .= " World";
Ici, $foo
devient "Hello World".
Comment cela se fait-il dans Bash?
foo1="World" foo2="Hello" foo3="$foo1$foo2"
Réponses:
foo="Hello"
foo="${foo} World"
echo "${foo}"
> Hello World
En général, pour concaténer deux variables, vous pouvez simplement les écrire l'une après l'autre:
a='Hello'
b='World'
c="${a} ${b}"
echo "${c}"
> Hello World
$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 dans foo="${foo}world"
...
Bash prend également en charge un +=
opérateur comme indiqué dans ce code:
$ A="X Y"
$ A+=" Z"
$ echo "$A"
X Y Z
export A+="Z"
ou peut-être que la A
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 sous busybox sh
ou dash
(qui est /bin/sh
sur beaucoup de distributions), ou certains autres shells comme ceux /bin/sh
fournis sur FreeBSD.
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:
var+=...
(Parce que je suis frugal, je ne l' utilise deux variables foo
et a
puis réutiliser le même dans toute la réponse. ;-)
a=2
a+=4
echo $a
24
En utilisant la syntaxe de question Stack Overflow ,
foo="Hello"
foo+=" World"
echo $foo
Hello World
fonctionne bien!
((var+=...))
variable a
est une chaîne, mais aussi un entier
echo $a
24
((a+=12))
echo $a
36
var+=(...)
Notre a
est également un tableau d'un seul élément.
echo ${a[@]}
36
a+=(18)
echo ${a[@]}
36 18
echo ${a[0]}
36
echo ${a[1]}
18
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
Hmm .. ce n'est pas un bug, mais une fonctionnalité ... Pour empêcher bash d'essayer de se développer !"
, vous pourriez:
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é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 sur stdout
:
echo ${a[@]}
36 18 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:
printf -v a "%s./.%s...'%s' '%s', '%s'=='%s'=='%s'" "${a[@]}"
echo $a
36./.18...'one' 'word', 'hello world!'=='hello world!'=='hello world!'
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é!
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!")'
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:
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!")'
Une chaîne de format d'argument avec plusieurs arguments passés à:
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: L'utilisation des guillemets doubles peut être utile pour manipuler des chaînes qui contiennent spaces
, tabulations
et / ounewlines
printf -v foo "%s World" "$foo"
Sous le shell POSIX , vous ne pouviez pas utiliser de bashismes , il n'y a donc pas de fonction intégrée printf
.
Mais vous pourriez simplement faire:
foo="Hello"
foo="$foo World"
echo $foo
Hello World
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
):
foo="Hello"
foo=$(printf "%s World" "$foo")
echo $foo
Hello World
Historiquement, vous pouviez utiliser des backticks pour récupérer le résultat d'un fork :
foo="Hello"
foo=`printf "%s World" "$foo"`
echo $foo
Hello World
Mais ce n'est pas facile pour l' imbrication :
foo="Today is: "
foo=$(printf "%s %s" "$foo" "$(date)")
echo $foo
Today is: Sun Aug 4 11:58:23 CEST 2013
avec des contre-coups, vous devez échapper aux fourches intérieures avec des contre - obliques :
foo="Today is: "
foo=`printf "%s %s" "$foo" "\`date\`"`
echo $foo
Today is: Sun Aug 4 11:59:10 CEST 2013
+=
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:
$ var="myscript"
$ echo $var
myscript
$ var=${var}.sh
$ echo $var
myscript.sh
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. Sinon echo ${var}2
ou voir ma réponse
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.
foo="Hello "
foo="$foo World"
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
Hello World
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
Hello World
avec un espace supplémentaire.
$aWorld
ne fonctionne pas, comme vous pouvez l'imaginer, mais
${a}World
produit
HelloWorld
${a}\ World
produitHello World
c=$a$b
ici à faire la même chose que c=$a World
(qui essaierait de fonctionner World
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»:
set one two
a=hello
b=world
Le tableau ci - dessous explique les différents contextes où l' on peut combiner les valeurs a
et b
de 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:
+=
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:
Encore une autre approche ...
> H="Hello "
> U="$H""universe."
> echo $U
Hello universe.
... et encore un autre.
> H="Hello "
> U=$H"universe."
> echo $U
Hello universe.
Si vous souhaitez ajouter quelque chose comme un trait de soulignement, utilisez escape (\)
FILEPATH=/opt/myfile
Cela ne fonctionne pas :
echo $FILEPATH_$DATEX
Cela fonctionne bien:
echo $FILEPATH\\_$DATEX
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:
B=Bar
b=bar
var="$B""$b""a"
echo "Hello ""$var"
var=$B$b"a"; echo Hello\ $var
ferait, je crois
Vous pouvez concaténer sans les guillemets. Voici un exemple:
$Variable1 Open
$Variable2 Systems
$Variable3 $Variable1$Variable2
$echo $Variable3
Cette dernière instruction afficherait "OpenSystems" (sans guillemets).
Voici un exemple de script Bash:
v1=hello
v2=world
v3="$v1 $v2"
echo $v3 # Output: hello world
echo "$v3" # Output: hello world
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:
foo="Hello"
foo="$foo World"
echo $foo
> Hello World
Je préfère utiliser des accolades ${}
pour développer la variable dans la chaîne:
foo="Hello"
foo="${foo} World"
echo $foo
> Hello World
Les accolades correspondent à l'utilisation continue de la chaîne:
foo="Hello"
foo="${foo}World"
echo $foo
> HelloWorld
Sinon, l'utilisation foo = "$fooWorld"
ne fonctionnera pas.
Si ce que vous essayez de faire est de diviser une chaîne en plusieurs lignes, vous pouvez utiliser une barre oblique inverse:
$ a="hello\
> world"
$ echo $a
helloworld
Avec un espace entre les deux:
$ a="hello \
> world"
$ echo $a
hello world
Celui-ci ajoute également un seul espace entre les deux:
$ a="hello \
> world"
$ echo $a
hello world
Moyen plus sûr:
a="AAAAAAAAAAAA"
b="BBBBBBBBBBBB"
c="CCCCCCCCCCCC"
d="DD DD"
s="${a}${b}${c}${d}"
echo "$s"
AAAAAAAAAAAABBBBBBBBBBBBCCCCCCCCCCCCDD DD
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 + =
d=DD DD
donnerait 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\ echo
ne lancera aucune invocation d'écho, alors que le d=echo echo
fera.
a="Hello,"
a=$a" World!"
echo $a
Voici comment concaténer deux chaînes.
S'il s'agit de votre exemple d'ajout " World"
à la chaîne d'origine, cela peut être:
#!/bin/bash
foo="Hello"
foo=$foo" World"
echo $foo
Le résultat:
Hello World
var1='hello'
var2='world'
var3=$var1" "$var2
echo $var3
var3=$var1\ $var2
le même effet
Des 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:
#!/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
Test 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
Test 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
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.
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:
list=(1 2 3 4 5)
string=''
for elm in "${list[@]}"; do
string="${string} ${elm}"
done
echo ${string}
puis j'obtiens la sortie suivante:
1 2 3 4 5
Notez que cela ne fonctionnera pas
foo=HELLO
bar=WORLD
foobar=PREFIX_$foo_$bar
car il semble laisser tomber $ foo et vous laisse avec:
PREFIX_WORLD
mais cela fonctionnera:
foobar=PREFIX_"$foo"_"$bar"
et vous laisse avec la sortie correcte:
PREFIX_HELLO_WORLD
Je le fais de cette façon quand c'est pratique: Utilisez une commande en ligne!
echo "The current time is `date`"
echo "Current User: `echo $USER`"
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
.
À 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.
function concat ()
{
prefix=$1
suffix=$2
echo "${prefix}${suffix}"
}
foo="Super"
bar="man"
concat $foo $bar # Superman
alien=$(concat $foo $bar)
echo $alien # Superman
J'aime un peu faire une fonction rapide.
#! /bin/sh -f
function combo() {
echo $@
}
echo $(combo 'foo''bar')
Encore une autre façon d'écorcher un chat. Cette fois avec des fonctions: D
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:
read pp; *# Assumes I will affect Hello to pp*
pp=$( printf $pp ;printf ' World'; printf '!');
echo $pp;
>Hello World!
Vous pouvez placer une autre variable au lieu de «Bonjour» ou «!». Vous pouvez également concaténer plus de chaînes.
foo="Hello"
foo=$foo" World"
echo $foo
cela a plutôt fonctionné pour "#! / bin / sh"