In PHP, le stringhe sono concatenate insieme come segue:
$foo = "Hello";
$foo .= " World";
Qui, $foo
diventa "Hello World".
Com'è fatto in Bash?
foo="Hello"
foo="$foo World"
echo $foo
> Hello World
In generale per concatenare due variabili puoi semplicemente scriverle una dopo l'altra:
a='hello'
b='world'
c="$a$b"
echo $c
> helloworld
Bash supporta anche un operatore +=
come mostrato in questo codice:
$ A="X Y"
$ A+=" Z"
$ echo "$A"
X Y Z
Poiché questa domanda è specifica per Bash , la mia prima parte della risposta presenterebbe diversi modi per farlo correttamente:
+=
: aggiungi alla variabileLa sintassi+=
può essere utilizzata in diversi modi:
var+=...
(Dato che sono parsimonioso, userò solo due variabili foo
e a
e quindi riutilizzerò lo stesso nell'intera risposta. ;-)
a=2
a+=4
echo $a
24
Utilizzando la sintassi della domanda Stack overflow,
foo="Hello"
foo+=" World"
echo $foo
Hello World
funziona bene!
((var+=...))
variable a
è una stringa, ma anche un intero
echo $a
24
((a+=12))
echo $a
36
var+=(...)
Il nostro a
è anche un array di un solo elemento.
echo ${a[@]}
36
a+=(18)
echo ${a[@]}
36 18
echo ${a[0]}
36
echo ${a[1]}
18
Si noti che tra parentesi, esiste un array spazio separato. Se si desidera memorizzare una stringa contenente spazi nell'array, è necessario includerli:
a+=(one Word "hello world!" )
bash: !": event not found
Hmm .. questo non è un bug, ma una funzione ... Per evitare che bash provi a sviluppare !"
, potresti:
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
: ricostruisci la variabile usando il comando builtinIl comando printf
builtin offre un modo efficace per disegnare il formato della stringa. Poiché questo è un Bash builtin, c'è un'opzione per inviare una stringa formattata a una variabile invece di stampare su stdout
:
echo ${a[@]}
36 18 one Word hello world! hello world! hello world!
Ci sono sette stringhe in questo array. Quindi potremmo costruire una stringa formattata contenente esattamente sette argomenti posizionali:
printf -v a "%s./.%s...'%s' '%s', '%s'=='%s'=='%s'" "${a[@]}"
echo $a
36./.18...'one' 'Word', 'hello world!'=='hello world!'=='hello world!'
Oppure potremmo usare un argomento format string che sarà ripetuto come molti argomenti inviati ...
Si noti che il nostro a
è ancora un array! Solo il primo elemento è cambiato!
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!")'
Sotto bash, quando si accede a un nome di variabile senza specificare l'indice, si rivolge sempre solo al primo elemento!
Quindi, per recuperare il nostro array di sette campi, dobbiamo solo reimpostare il primo elemento:
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!")'
Una stringa di formato di argomento con molti argomenti passati a:
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'uso di double-quotes può essere utile per manipolare stringhe che contengono spaces
, tabulations
e/o newlines
printf -v foo "%s World" "$foo"
Sotto POSIX Shell, non è possibile usare bashisms, quindi non esiste builtinprintf
.
Ma potresti semplicemente fare:
foo="Hello"
foo="$foo World"
echo $foo
Hello World
printf
Se si desidera utilizzare costruzioni più sofisticate, è necessario utilizzare fork (nuovo processo figlio che esegue il lavoro e restituisce il risultato tramite stdout
):
foo="Hello"
foo=$(printf "%s World" "$foo")
echo $foo
Hello World
Storicamente, è possibile utilizzare backticks per recuperare il risultato di un fork:
foo="Hello"
foo=`printf "%s World" "$foo"`
echo $foo
Hello World
Ma questo non è facile per nesting:
foo="Today is: "
foo=$(printf "%s %s" "$foo" "$(date)")
echo $foo
Today is: Sun Aug 4 11:58:23 CEST 2013
con i backtick, devi sfuggire alle forcelle interne con backslash:
foo="Today is: "
foo=`printf "%s %s" "$foo" "\`date\`"`
echo $foo
Today is: Sun Aug 4 11:59:10 CEST 2013
Puoi farlo anche tu:
$ var="myscript"
$ echo $var
myscript
$ var=${var}.sh
$ echo $var
myscript.sh
bla=hello
laber=kthx
echo "${bla}ohai${laber}bye"
Uscirà
helloohaikthxbye
Ciò è utile quando $blaohai
porta a un errore di variabile non trovata. O se hai spazi o altri caratteri speciali nelle tue corde. "${foo}"
evita correttamente qualsiasi cosa tu inserisca.
foo="Hello "
foo="$foo World"
Il modo in cui risolverei il problema è giusto
$a$b
Per esempio,
a="Hello"
b=" World"
c=$a$b
echo "$c"
che produce
Hello World
Se si tenta di concatenare una stringa con un'altra stringa, ad esempio,
a="Hello"
c="$a World"
allora produrrà echo "$c"
Hello World
con uno spazio extra.
$aWorld
non funziona, come puoi immaginare, ma
${a}World
produce
HelloWorld
$ a=hip
$ b=hop
$ ab=$a$b
$ echo $ab
hiphop
$ echo $a$b
hiphop
Ecco un breve riassunto di ciò di cui la maggior parte delle risposte sta parlando.
Diciamo che abbiamo due variabili:
a=hello
b=world
La tabella seguente spiega i diversi contesti in cui possiamo combinare i valori di a
e b
per creare una nuova variabile, 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, 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
Alcune note:
+=
è migliore dal punto di vista delle prestazioni se viene costruita una grande stringa in piccoli incrementi, specialmente in un ciclo{}
attorno ai nomi delle variabili per disambiguare la loro espansione (come nella riga 2 nella tabella sopra)Guarda anche:
Se vuoi aggiungere qualcosa come un trattino basso, usa escape (\)
FILEPATH=/opt/myfile
Questo fa not work:
echo $FILEPATH_$DATEX
Questo funziona bene:
echo $FILEPATH\\_$DATEX
Ancora un altro approccio ...
> H="Hello "
> U="$H""universe."
> echo $U
Hello universe.
... e ancora un altro.
> H="Hello "
> U=$H"universe."
> echo $U
Hello universe.
Il modo più semplice con le virgolette:
B=Bar
b=bar
var="$B""$b""a"
echo "Hello ""$var"
Puoi concatenare senza le virgolette. Ecco un esempio:
$Variable1 Open
$Variable2 Systems
$Variable3 $Variable1$Variable2
$echo $Variable3
Quest'ultima affermazione stamperebbe "OpenSystems" (senza virgolette).
Questo è un esempio di uno script Bash:
v1=hello
v2=world
v3="$v1 $v2"
echo $v3 # Output: hello world
echo "$v3" # Output: hello world
Anche se l'operatore + = è ora consentito, è stato introdotto in Bash 3.1 nel 2004.
Qualsiasi script che usi questo operatore nelle versioni precedenti di Bash fallirà con un errore "comando non trovato" se sei fortunato, o un "errore di sintassi vicino a un token imprevisto".
Per coloro che si preoccupano della compatibilità con le versioni precedenti, segui i vecchi metodi di concatenazione Bash standard, come quelli menzionati nella risposta scelta:
foo="Hello"
foo="$foo World"
echo $foo
> Hello World
Preferisco usare le parentesi graffe ${}
per la variabile espandibile nella stringa:
foo="Hello"
foo="${foo} World"
echo $foo
> Hello World
Le parentesi graffe si adattano all'utilizzo di stringhe continue:
foo="Hello"
foo="${foo}World"
echo $foo
> HelloWorld
Altrimenti usare foo = "$fooWorld"
non funzionerà.
Modo più sicuro:
a="AAAAAAAAAAAA"
b="BBBBBBBBBBBB"
c="CCCCCCCCCCCC"
d="DD DD"
s="${a}${b}${c}${d}"
echo "$s"
AAAAAAAAAAAABBBBBBBBBBBBCCCCCCCCCCCCDD DD
Le stringhe contenenti spazi possono diventare parte del comando, utilizzare "$ XXX" e "$ {XXX}" per evitare questi errori.
Inoltre dai un'occhiata ad altre risposte su + =
Se quello che stai cercando di fare è dividere una stringa in più righe, puoi usare una barra rovesciata:
$ a="hello\
> world"
$ echo $a
helloworld
Con uno spazio in mezzo:
$ a="hello \
> world"
$ echo $a
hello world
Questo aggiunge anche solo uno spazio in mezzo:
$ a="hello \
> world"
$ echo $a
hello world
C'è un caso particolare in cui dovresti fare attenzione:
user=daniel
cat > output.file << EOF
"$user"san
EOF
Produrrà "daniel"san
, e non danielsan
, come potresti aver desiderato. In questo caso dovresti fare invece:
user=daniel
cat > output.file << EOF
${user}san
EOF
Se è il tuo esempio di aggiungere " World"
alla stringa originale, allora può essere:
#!/bin/bash
foo="Hello"
foo=$foo" World"
echo $foo
L'output:
Hello World
var1='hello'
var2='world'
var3=$var1" "$var2
echo $var3
Ci sono preoccupazioni espresse sulle prestazioni, ma non vengono offerti dati. Lasciatemi suggerire un semplice test.
(NOTA: date
su macOS non offre nanosecondi, quindi questo deve essere fatto su Linux.)
Ho creato append_test.sh su GitHub con i contenuti:
#!/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
Gli errori indicano che il mio Bash è arrivato a 335.54432 MB prima che si arrestasse in modo anomalo. È possibile modificare il codice dal raddoppio dei dati all'aggiunta di una costante per ottenere un grafico più dettagliato e un punto di errore. Ma penso che questo dovrebbe darti abbastanza informazioni per decidere se ti interessa. Personalmente, sotto i 100 MB non lo faccio. Il tuo chilometraggio può variare.
a="Hello,"
a=$a" World!"
echo $a
Questo è il modo in cui si concatenano due stringhe.
Volevo costruire una stringa da una lista. Non ho trovato una risposta per questo, quindi la postò qui. Ecco cosa ho fatto:
list=(1 2 3 4 5)
string=''
for Elm in "${list[@]}"; do
string="${string} ${Elm}"
done
echo ${string}
e poi ottengo il seguente risultato:
1 2 3 4 5
Nota che questo non funzionerà
foo=HELLO
bar=WORLD
foobar=PREFIX_$foo_$bar
dato che sembra cadere $ pippo e ti lascia con:
PREFIX_WORLD
ma questo funzionerà:
foobar=PREFIX_"$foo"_"$bar"
e ti lascia con l'output corretto:
PREFIX_HELLO_WORLD
Lo faccio in questo modo quando conveniente: usa un comando in linea!
echo "The current time is `date`"
echo "Current User: `echo $USER`"
Ecco quello attraverso AWK :
$ foo="Hello"
$ foo=$(awk -v var=$foo 'BEGIN{print var" World"}')
$ echo $foo
Hello World