web-dev-qa-db-fra.com

Comment concaténer des variables de chaîne dans Bash

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?

2519
Strawberry
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
3406
codaddict

Bash prend également en charge un opérateur +=, comme indiqué dans ce code:

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

Bash premier

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 variable

La syntaxe += peut être utilisée de différentes manières:

Ajouter à la chaîne _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!

Ajouter à un entier _((var+=...))_

variable a est une chaîne, mais aussi un entier

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

Ajouter à un tableau 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 builtin

La commande printfbuiltin 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!>
_

Utilisation de la syntaxe Stack Overflow question:

_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"
_

Shell maintenant

Sous POSIX Shell, vous ne pouvez pas utiliser bashisms, il n'y a donc pas commande intégréeprintf.

Fondamentalement

Mais vous pouvez simplement faire:

_foo="Hello"
foo="$foo World"
echo $foo
Hello World
_

Formaté en utilisant forkedprintf

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
_
910
F. Hauri

Vous pouvez le faire aussi:

$ var="myscript"

$ echo $var

myscript


$ var=${var}.sh

$ echo $var

myscript.sh
130
userend
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.

117
orkoden
foo="Hello "
foo="$foo World"

42
vinothkr

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
32
Chris Smith
$ a=hip
$ b=hop
$ ab=$a$b
$ echo $ab
hiphop
$ echo $a$b
hiphop
29
bcosca

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:

  • mettre entre guillemets l'ERS d'une assignation est généralement une bonne pratique, bien qu'il soit assez facultatif dans de nombreux cas
  • += est meilleur du point de vue des performances si une grosse chaîne est construite par petits incréments, en particulier dans une boucle
  • utilisez {} 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:

23
codeforester

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
20
user2800471

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.
19
Akseli Palén

La manière la plus simple avec des guillemets:

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

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
15
Louis-Félix

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
15
mariana soffer

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.

13
Nick Tsai

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
8
jcarballo

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 + =

7
Bohdan

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
7
diogovk

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
5
var1='hello'
var2='world'
var3=$var1" "$var2 
echo $var3
5
hari

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.

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

Voici comment concaténer deux chaînes.

4
CodeNinjaPI

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
4
Simon Bachmann

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

3
Dss

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`"
1
Marty

À 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
1
Anthony Rutledge

Voici celui à travers AWK :

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