it-swarm.com.de

So verketten Sie Zeichenfolgenvariablen in Bash

In PHP werden Zeichenfolgen wie folgt miteinander verkettet:

$foo = "Hello";
$foo .= " World";

Hier wird $foo zu "Hello World".

Wie wird das in Bash erreicht?

2519
Strawberry
foo="Hello"
foo="$foo World"
echo $foo
> Hello World

Im Allgemeinen können Sie zwei Variablen hintereinander schreiben, um sie zu verketten:

a='hello'
b='world'
c="$a$b"
echo $c
> helloworld
3406
codaddict

Bash unterstützt auch einen += -Operator, wie in diesem Code gezeigt:

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

Bash zuerst

Da diese Frage speziell für Bash steht, würde mein erster Teil der Antwort verschiedene Möglichkeiten aufzeigen, dies richtig zu tun:

_+=_: An Variable anhängen

Die Syntax += kann auf verschiedene Arten verwendet werden:

An String anhängen _var+=..._

(Da ich sparsam bin, verwende ich nur zwei Variablen foo und a und verwende sie dann in der gesamten Antwort erneut. ;-)

_a=2
a+=4
echo $a
24
_

Verwenden Sie die Syntax Stack Overflow question,

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

funktioniert gut!

An eine Ganzzahl anhängen _((var+=...))_

variable a ist eine Zeichenfolge, aber auch eine Ganzzahl

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

An ein Array anhängen var+=(...)

Unser a ist auch ein Array von nur einem Element.

_echo ${a[@]}
36

a+=(18)

echo ${a[@]}
36 18
echo ${a[0]}
36
echo ${a[1]}
18
_

Beachten Sie, dass zwischen Klammern ein durch Leerzeichen getrenntes Array steht. Wenn Sie eine Zeichenfolge mit Leerzeichen in Ihrem Array speichern möchten, müssen Sie sie einschließen:

_a+=(one Word "hello world!" )
bash: !": event not found
_

Hmm .. dies ist kein Fehler, sondern eine Funktion ... Um zu verhindern, dass Bash versucht, _!"_ zu entwickeln, können Sie:

_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: Erstellen Sie die Variable mit dem Befehl builtin neu

Der Befehl printfbuiltin bietet eine leistungsstarke Methode zum Zeichnen von Zeichenfolgen. Da dies ein Bash builtin ist, gibt es eine Option zum Senden eines formatierten Strings an eine Variable, anstatt auf stdout zu drucken:

_echo ${a[@]}
36 18 one Word hello world! hello world! hello world!
_

Es gibt sieben Strings in diesem Array. Wir könnten also eine formatierte Zeichenfolge mit genau sieben Positionsargumenten erstellen:

_printf -v a "%s./.%s...'%s' '%s', '%s'=='%s'=='%s'" "${a[@]}"
echo $a
36./.18...'one' 'Word', 'hello world!'=='hello world!'=='hello world!'
_

Oder wir könnten ein Argument-Format-String verwenden, der so oft wiederholt wird, wie viele Argumente eingereicht wurden ...

Beachten Sie, dass unser a immer noch ein Array ist! Nur das erste Element wird geändert!

_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!")'
_

Wenn Sie unter bash auf einen Variablennamen zugreifen, ohne den Index anzugeben, sprechen Sie immer nur das erste Element an!

Um unser Sieben-Felder-Array abzurufen, müssen wir nur das erste Element zurücksetzen:

_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!")'
_

Ein Argumentformatstring mit vielen Argumenten, die übergeben werden an:

_printf -v a[0] '<%s>\n' "${a[@]}"
echo "$a"
<36>
<18>
<one>
<Word>
<hello world!>
<hello world!>
<hello world!>
_

Verwenden der Stapelüberlauf-Frage -Syntax:

_foo="Hello"
printf -v foo "%s World" $foo
echo $foo
Hello World
_

Hinweis: Die Verwendung von Anführungszeichen kann nützlich sein, um Zeichenfolgen zu bearbeiten, die spaces, tabulations und/oder newlines enthalten.

_printf -v foo "%s World" "$foo"
_

Shell jetzt

Unter POSIX Shell konnten Sie bashisms nicht verwenden, daher gibt es kein builtinprintf.

Grundsätzlich gilt

Aber Sie könnten einfach tun:

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

Formatiert mit forkedprintf

Wenn Sie komplexere Konstruktionen verwenden möchten, müssen Sie einen fork (neuen untergeordneten Prozess verwenden, der den Job erstellt und das Ergebnis über stdout zurückgibt):

_foo="Hello"
foo=$(printf "%s World" "$foo")
echo $foo
Hello World
_

Historisch gesehen können Sie backticks verwenden, um das Ergebnis eines fork abzurufen:

_foo="Hello"
foo=`printf "%s World" "$foo"`
echo $foo
Hello World
_

Dies ist jedoch nicht einfach für nesting:

_foo="Today is: "
foo=$(printf "%s %s" "$foo" "$(date)")
echo $foo
Today is: Sun Aug 4 11:58:23 CEST 2013
_

bei Backticks muss man mit Backslashes den inneren Gabeln entkommen:

_foo="Today is: "
foo=`printf "%s %s" "$foo" "\`date\`"`
echo $foo
Today is: Sun Aug 4 11:59:10 CEST 2013
_
910
F. Hauri

Sie können dies auch tun:

$ var="myscript"

$ echo $var

myscript


$ var=${var}.sh

$ echo $var

myscript.sh
130
userend
bla=hello
laber=kthx
echo "${bla}ohai${laber}bye"

Wird ausgegeben

helloohaikthxbye

Dies ist nützlich, wenn $blaohai zu einem Fehler "Variable nicht gefunden" führt. Oder wenn Sie Leerzeichen oder andere Sonderzeichen in Ihren Zeichenfolgen haben. "${foo}" entzieht sich richtig allem, was Sie hineingesteckt haben.

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

42
vinothkr

Die Art und Weise, wie ich das Problem lösen würde, ist einfach

$a$b

Zum Beispiel,

a="Hello"
b=" World"
c=$a$b
echo "$c"

was produziert

Hello World

Wenn Sie versuchen, eine Zeichenfolge mit einer anderen Zeichenfolge zu verketten, z. B.

a="Hello"
c="$a World"

dann wird echo "$c" produzieren

Hello World

mit einem zusätzlichen Raum.

$aWorld

funktioniert nicht, wie Sie sich vorstellen können, aber

${a}World

produziert

HelloWorld
32
Chris Smith
$ a=hip
$ b=hop
$ ab=$a$b
$ echo $ab
hiphop
$ echo $a$b
hiphop
29
bcosca

Hier ist eine kurze Zusammenfassung dessen, worüber die meisten Antworten sprechen.

Nehmen wir an, wir haben zwei Variablen und $ 1 ist auf 'Eins' gesetzt:

set one two
a=hello
b=world

In der folgenden Tabelle werden die verschiedenen Kontexte erläutert, in denen die Werte von a und b kombiniert werden können, um die neue Variable c zu erstellen.

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

Ein paar Anmerkungen:

  • das Einschließen des RHS einer Zuweisung in doppelte Anführungszeichen ist im Allgemeinen eine gute Praxis, obwohl es in vielen Fällen durchaus optional ist
  • += ist vom Standpunkt der Leistung aus besser, wenn eine große Zeichenfolge in kleinen Schritten erstellt wird, insbesondere in einer Schleife
  • verwenden Sie {} um Variablennamen, um deren Erweiterung zu disambiguieren (wie in Zeile 2 in der obigen Tabelle). Wie in den Zeilen 3 und 4 zu sehen ist, ist {} nur erforderlich, wenn eine Variable mit einer Zeichenfolge verkettet wird, die mit einem Zeichen beginnt, das ein gültiges erstes Zeichen im Namen der Shell-Variablen ist, dh Alphabet oder Unterstrich.

Siehe auch:

23
codeforester

Wenn Sie so etwas wie einen Unterstrich anhängen möchten, verwenden Sie escape (\)

FILEPATH=/opt/myfile

Dies funktioniert nicht

echo $FILEPATH_$DATEX

Das funktioniert gut:

echo $FILEPATH\\_$DATEX
20
user2800471

Noch ein anderer Ansatz ...

> H="Hello "
> U="$H""universe."
> echo $U
Hello universe.

... und noch eine.

> H="Hello "
> U=$H"universe."
> echo $U
Hello universe.
19
Akseli Palén

Der einfachste Weg mit Anführungszeichen:

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

Auch wenn der Operator + = jetzt zulässig ist, wurde er 2004 in Bash 3.1 eingeführt.

Jedes Skript, das diesen Operator in älteren Bash-Versionen verwendet, schlägt mit dem Fehler "Befehl nicht gefunden" fehl, wenn Sie Glück haben, oder mit einem "Syntaxfehler in der Nähe eines unerwarteten Tokens".

Wenn Sie sich für die Abwärtskompatibilität interessieren, sollten Sie sich an die älteren Standard-Bash-Verkettungsmethoden halten, wie sie in der gewählten Antwort aufgeführt sind:

foo="Hello"
foo="$foo World"
echo $foo
> Hello World
15
Louis-Félix

Sie können ohne die Anführungszeichen verketten. Hier ist ein Beispiel:

$Variable1 Open
$Variable2 Systems
$Variable3 $Variable1$Variable2
$echo $Variable3

Diese letzte Anweisung würde "OpenSystems" (ohne Anführungszeichen) drucken.

Dies ist ein Beispiel für ein Bash-Skript:

v1=hello
v2=world
v3="$v1       $v2"
echo $v3            # Output: hello world
echo "$v3"          # Output: hello       world
15
mariana soffer

Ich bevorzuge geschweifte Klammern ${} zum Erweitern von Variablen in Zeichenfolgen:

foo="Hello"
foo="${foo} World"
echo $foo
> Hello World

Geschweifte Klammern passen zur fortlaufenden Verwendung von Zeichenfolgen:

foo="Hello"
foo="${foo}World"
echo $foo
> HelloWorld

Andernfalls funktioniert die Verwendung von foo = "$fooWorld" nicht.

13
Nick Tsai

Wenn Sie versuchen, einen String in mehrere Zeilen aufzuteilen , können Sie einen Backslash verwenden:

$ a="hello\
> world"
$ echo $a
helloworld

Mit einem Leerzeichen dazwischen:

$ a="hello \
> world"
$ echo $a
hello world

Dieser fügt auch nur ein Leerzeichen dazwischen hinzu:

$ a="hello \
>      world"
$ echo $a
hello world
8
jcarballo

Sicherer Weg:

a="AAAAAAAAAAAA"
b="BBBBBBBBBBBB"
c="CCCCCCCCCCCC"
d="DD DD"
s="${a}${b}${c}${d}"
echo "$s"
AAAAAAAAAAAABBBBBBBBBBBBCCCCCCCCCCCCDD DD

Zeichenfolgen, die Leerzeichen enthalten, können Teil des Befehls werden. Verwenden Sie "$ XXX" und "$ {XXX}", um diese Fehler zu vermeiden.

Schauen Sie sich auch eine andere Antwort zu + = an

7
Bohdan

Es gibt einen besonderen Fall, in dem Sie aufpassen sollten:

user=daniel
cat > output.file << EOF
"$user"san
EOF

Gibt "daniel"san und nicht danielsan aus, wie Sie es vielleicht wollten. In diesem Fall sollten Sie stattdessen Folgendes tun:

user=daniel
cat > output.file << EOF
${user}san
EOF
7
diogovk

Wenn Sie beispielsweise " World" zur ursprünglichen Zeichenfolge hinzufügen, kann dies sein:

#!/bin/bash

foo="Hello"
foo=$foo" World"
echo $foo

Die Ausgabe:

Hello World
var1='hello'
var2='world'
var3=$var1" "$var2 
echo $var3
5
hari

Es gibt Bedenken hinsichtlich der Leistung, aber es werden keine Daten angeboten. Lassen Sie mich einen einfachen Test vorschlagen.

(HINWEIS: date unter macOS bietet keine Nanosekunden, daher muss dies unter Linux erfolgen.)

Ich habe append_test.sh auf GitHub mit dem Inhalt erstellt:

#!/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

Die Fehler deuten darauf hin, dass mein Bash vor dem Absturz auf 335.54432 MB gestiegen ist. Sie können den Code ändern, indem Sie die Daten verdoppeln und eine Konstante anhängen, um ein detaillierteres Diagramm und einen Fehlerpunkt zu erhalten. Aber ich denke, das sollte dir genug Informationen geben, um zu entscheiden, ob es dich interessiert. Persönlich unter 100 MB weiß ich nicht. Ihr Kilometerstand kann variieren.

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

So verketten Sie zwei Zeichenfolgen.

4
CodeNinjaPI

Ich wollte eine Zeichenfolge aus einer Liste erstellen. Konnte keine Antwort dafür finden, also poste ich es hier. Folgendes habe ich getan:

list=(1 2 3 4 5)
string=''

for Elm in "${list[@]}"; do
    string="${string} ${Elm}"
done

echo ${string}

und dann bekomme ich folgende Ausgabe:

1 2 3 4 5
4
Simon Bachmann

Beachten Sie, dass dies nicht funktioniert

foo=HELLO
bar=WORLD
foobar=PREFIX_$foo_$bar

wie es scheint, $ foo fallen zu lassen und Sie mit lässt:

PREFIX_WORLD

aber das wird funktionieren:

foobar=PREFIX_"$foo"_"$bar"

und lassen Sie mit der richtigen Ausgabe:

PREFIX_HELLO_WORLD

3
Dss

Ich mache es so, wenn es bequem ist: Verwende einen Inline-Befehl!

echo "The current time is `date`"
echo "Current User: `echo $USER`"
1
Marty

Meiner Meinung nach besteht der einfachste Weg, zwei Zeichenfolgen zu verketten, darin, eine Funktion zu schreiben, die dies für Sie erledigt, und diese Funktion dann zu verwenden.

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

Hier ist der durch AWK :

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