En PHP, les chaînes sont concaténées comme suit:
$foo = "Hello";
$foo .= " World";
Ici, $foo
devient "Hello World".
Comment est-ce accompli dans Bash?
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
> helloworld
Bash prend également en charge un opérateur +=
, comme indiqué dans ce code:
$ A="X Y"
$ A+=" Z"
$ echo "$A"
X Y Z
Comme cette question concerne spécifiquement Bash , ma première partie de la réponse présenterait différentes manières de le faire correctement:
+=
_: Ajouter à la variableLa syntaxe +=
peut être utilisée de différentes manières:
var+=...
_(Étant donné que je suis frugal, je n’utiliserai que deux variables foo
et a
, puis je l’utiliserai de nouveau dans toute la réponse. ;-)
_a=2
a+=4
echo $a
24
_
Utilisation de la syntaxe Stack Overflow question,
_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 inclure:
_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 développer _!"
_, vous pouvez:
_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 une variable à l'aide de la commande builtinLa commande printf
builtin donne un moyen puissant de dessiner le format de chaîne. Comme il s'agit d'un Bash builtin, 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 de position:
_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 chaîne d'un format d'argument qui sera répété autant d'arguments soumis ...
Notez que notre a
est toujours un tableau! Seul le premier élément est changé!
_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 adressez toujours le premier élément uniquement!
Donc, pour récupérer notre tableau de sept champs, il suffit de redéfinir 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 de nombreux 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
_
Note: L'utilisation de guillemets doubles peut être utile pour manipuler des chaînes contenant spaces
, tabulations
et/ou newlines
_printf -v foo "%s World" "$foo"
_
Sous POSIX Shell, vous ne pouvez pas utiliser bashisms, il n'y a donc pas commande intégréeprintf
.
Mais vous pouvez 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 effectue le travail et renvoie le résultat via stdout
):
_foo="Hello"
foo=$(printf "%s World" "$foo")
echo $foo
Hello World
_
Historiquement, vous pouviez utiliser 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 imbrication:
_foo="Today is: "
foo=$(printf "%s %s" "$foo" "$(date)")
echo $foo
Today is: Sun Aug 4 11:58:23 CEST 2013
_
avec des backticks, vous devez sortir de la fourche intérieure avec backslashes:
_foo="Today is: "
foo=`printf "%s %s" "$foo" "\`date\`"`
echo $foo
Today is: Sun Aug 4 11:59:10 CEST 2013
_
Vous pouvez le faire aussi:
$ var="myscript"
$ echo $var
myscript
$ var=${var}.sh
$ echo $var
myscript.sh
bla=hello
laber=kthx
echo "${bla}ohai${laber}bye"
Sortie
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 juste
$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"
alors 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=hip
$ b=hop
$ ab=$a$b
$ echo $ab
hiphop
$ echo $a$b
hiphop
Voici un résumé concis de ce dont la plupart des réponses parlent.
Disons que nous avons deux variables et que $ 1 a la valeur 'un':
set one two
a=hello
b=world
Le tableau ci-dessous explique les différents contextes dans lesquels nous pouvons combiner les valeurs de a
et b
pour 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 par petits incréments, en particulier dans une boucle{}
autour des noms de variables pour comprendre leur développement (comme dans la ligne 2 du tableau ci-dessus). Comme indiqué aux lignes 3 et 4, {}
n'est pas nécessaire, sauf si une variable est concaténée avec une chaîne commençant par un caractère qui est un premier caractère valide dans le nom de la variable Shell, c'est-à-dire un alphabet ou un trait de soulignement.Voir également:
Si vous souhaitez ajouter quelque chose comme un trait de soulignement, utilisez échap (\)
FILEPATH=/opt/myfile
Ceci ( ne fonctionne pas :
echo $FILEPATH_$DATEX
Cela fonctionne bien:
echo $FILEPATH\\_$DATEX
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.
La manière la plus simple avec des guillemets:
B=Bar
b=bar
var="$B""$b""a"
echo "Hello ""$var"
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 d'anciennes versions de Bash échouera avec une erreur "commande introuvable" si vous avez de la chance, ou une "erreur de syntaxe proche du jeton inattendu".
Pour ceux qui se soucient de la compatibilité ascendante, 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
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 les guillemets).
Voici un exemple de script Bash:
v1=hello
v2=world
v3="$v1 $v2"
echo $v3 # Output: hello world
echo "$v3" # Output: hello world
Je préfère utiliser les accolades ${}
pour développer la variable dans la chaîne:
foo="Hello"
foo="${foo} World"
echo $foo
> Hello World
Les accolades s’adaptent à l’utilisation continue de la chaîne:
foo="Hello"
foo="${foo}World"
echo $foo
> HelloWorld
Sinon, utiliser foo = "$fooWorld"
ne fonctionnera pas.
Si vous essayez 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:
$ a="hello \
> world"
$ echo $a
hello world
Celui-ci ajoute également un seul espace entre:
$ a="hello \
> world"
$ echo $a
hello world
Manière plus sûre:
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 devenir partie intégrante de la commande, utilisez "$ XXX" et "$ {XXX}" pour éviter ces erreurs.
De plus, jetez un oeil à une autre réponse à propos de + =
Il y a un cas particulier où vous devriez faire attention:
user=daniel
cat > output.file << EOF
"$user"san
EOF
La sortie "daniel"san
, et non danielsan
, comme vous auriez pu le souhaiter. Dans ce cas, vous devriez plutôt faire:
user=daniel
cat > output.file << EOF
${user}san
EOF
Si c'est comme exemple d'ajouter " World"
à la chaîne d'origine, alors 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
Des inquiétudes ont été exprimées concernant les performances, mais aucune donnée n’est proposée. Laissez-moi vous suggérer un test simple.
(REMARQUE: date
sur macOS n'offre pas de nanosecondes, cela doit donc être fait sous 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 son crash. Vous pouvez changer le code en doublant les données et en ajoutant une constante pour obtenir un graphique plus granulaire et un point d'échec. Mais je pense que cela devrait vous donner suffisamment d’informations pour décider si vous vous en souciez ou non. Personnellement, moins de 100 Mo, je ne le fais pas. Votre kilométrage peut varier.
a="Hello,"
a=$a" World!"
echo $a
Voici comment concaténer deux chaînes.
Je voulais construire une chaîne à partir d'une liste. Impossible de trouver une réponse à cette question, 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}
et 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
comme il semble tomber $ foo et vous laisse avec:
PREFIX_WORLD
mais cela fonctionnera:
foobar=PREFIX_"$foo"_"$bar"
et vous laisser avec la sortie correcte:
PREFIX_HELLO_WORLD
Je le fais de cette façon quand cela convient: Utilisez une commande en ligne!
echo "The current time is `date`"
echo "Current User: `echo $USER`"
À mon avis, le moyen le plus simple de concaténer deux chaînes est d’écrire une fonction qui le fait pour vous, puis de l’utiliser.
function concat ()
{
prefix=$1
suffix=$2
echo "${prefix}${suffix}"
}
foo="Super"
bar="man"
concat $foo $bar # Superman
alien=$(concat $foo $bar)
echo $alien # Superman
Voici celui à travers AWK :
$ foo="Hello"
$ foo=$(awk -v var=$foo 'BEGIN{print var" World"}')
$ echo $foo
Hello World