In PHP, le stringhe sono concatenate insieme come segue:
$foo = "Hello";
$foo .= " World";
Qui, $foo
diventa "Hello World".
Come si ottiene questo risultato in Bash?
foo1="World" foo2="Hello" foo3="$foo1$foo2"
In PHP, le stringhe sono concatenate insieme come segue:
$foo = "Hello";
$foo .= " World";
Qui, $foo
diventa "Hello World".
Come si ottiene questo risultato in Bash?
foo1="World" foo2="Hello" foo3="$foo1$foo2"
Risposte:
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}"
> Hello World
$foo
dentro le doppie virgolette, per i momenti in cui conta davvero.
foo="$fooworld"
? Suppongo di no ...
fooworld
. Che chiarimento è fatto con le parentesi graffe, come in foo="${foo}world"
...
Bash supporta anche un +=
operatore come mostrato in questo codice:
$ A="X Y"
$ A+=" Z"
$ echo "$A"
X Y Z
export A+="Z"
o forse la A
variabile deve essere esportata una sola volta?
export A+=Z
funzionano altrettanto bene.
#!/bin/sh
una sceneggiatura usando questa costruzione.
bash
e alcune altre shell più avanzate. Non funzionerà sotto busybox sh
o dash
(che è /bin/sh
su molte distro), o su alcune altre shell come quelle /bin/sh
fornite su FreeBSD.
Poiché questa domanda è specifica per Bash , la mia prima parte della risposta presenterebbe diversi modi di farlo correttamente:
+=
: Aggiungi alla variabileLa sintassi +=
può essere utilizzata in diversi modi:
var+=...
(Perché io sono frugale, io uso solo due variabili foo
e a
poi ri-uso la stessa in tutta risposta ;-).
a=2
a+=4
echo $a
24
Utilizzando la sintassi della domanda StackTranslate.it,
foo="Hello"
foo+=" World"
echo $foo
Hello World
funziona bene!
((var+=...))
variabile a
è una stringa, ma anche un numero 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 c'è un array separato da spazi . Se si desidera memorizzare una stringa contenente spazi nell'array, è necessario racchiuderli:
a+=(one word "hello world!" )
bash: !": event not found
Hmm .. questo non è un bug, ma una funzionalità ... Per impedire a bash di provare a svilupparsi !"
, 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 incorporatoIl comando printf
incorporato offre un modo potente per disegnare il formato stringa. Poiché si tratta di un built-in di Bash , esiste 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 una stringa di formato argomento che verrà ripetuta come molti argomenti inviati ...
Nota che il nostro a
è ancora un array! Viene modificato solo il primo elemento!
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 accedi a un nome di variabile senza specificare l'indice, indirizzi sempre solo il primo elemento!
Quindi, per recuperare il nostro array di sette campi, dobbiamo solo reimpostare il 1 ° 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 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 virgolette doppie può essere utile per manipolare stringhe che contengono spaces
, tabulations
e / onewlines
printf -v foo "%s World" "$foo"
Nella shell POSIX , non è possibile utilizzare i bashismi , quindi non è incorporato printf
.
Ma potresti semplicemente fare:
foo="Hello"
foo="$foo World"
echo $foo
Hello World
printf
Se si desidera utilizzare costruzioni più sofisticate, è necessario utilizzare una forcella (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 i backtick per recuperare il risultato di un fork :
foo="Hello"
foo=`printf "%s World" "$foo"`
echo $foo
Hello World
Ma questo non è facile per la nidificazione :
foo="Today is: "
foo=$(printf "%s %s" "$foo" "$(date)")
echo $foo
Today is: Sun Aug 4 11:58:23 CEST 2013
con le punte posteriori , devi sfuggire alle forcelle interne con barre rovesciate :
foo="Today is: "
foo=`printf "%s %s" "$foo" "\`date\`"`
echo $foo
Today is: Sun Aug 4 11:59:10 CEST 2013
+=
operatore è anche molto più veloce rispetto $a="$a$b"
ai miei test .. Il che ha senso.
var=${var}.sh
esempio di altre risposte, il che è molto utile.
bash
l'unica shell con +=
operatore? Voglio vedere se è abbastanza portatile
+=
operatore, ma tutti questi modi sono basismi , quindi non portatili! Anche tu potresti riscontrare un bug speciale in caso di versione bash sbagliata!
Puoi farlo anche tu:
$ var="myscript"
$ echo $var
myscript
$ var=${var}.sh
$ echo $var
myscript.sh
var=myscript;var=$var.sh;echo $var
avrebbero gli stessi effetti (Questo lavoro sotto bash, dash, busybox e altri).
echo $var2
Non producemyscript2
.
illegale nel nome della variabile. Se altro echo ${var}2
o vedi la mia risposta
bla=hello
laber=kthx
echo "${bla}ohai${laber}bye"
Verrà emesso
helloohaikthxbye
Ciò è utile quando
$blaohai
si verifica un errore variabile non trovato. O se hai spazi o altri caratteri speciali nelle tue stringhe. "${foo}"
sfugge correttamente a qualsiasi cosa tu ci 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 provi a concatenare una stringa con un'altra stringa, ad esempio,
a="Hello"
c="$a World"
allora echo "$c"
produrrà
Hello World
con uno spazio extra.
$aWorld
non funziona, come puoi immaginare, ma
${a}World
produce
HelloWorld
${a}\ World
produceHello World
c=$a$b
qui facessi la stessa cosa c=$a World
(che proverebbe a funzionare World
come comando). Immagino che ciò significhi che l'assegnazione viene analizzata prima che le variabili vengano espanse ..
Ecco un breve riassunto di ciò di cui parla la maggior parte delle risposte.
Diciamo che abbiamo due variabili e $ 1 è impostato su 'uno':
set one two
a=hello
b=world
La tabella che segue illustra i diversi contesti in cui siamo in grado di 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 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
Alcune note:
+=
è migliore dal punto di vista delle prestazioni se una stringa grande viene costruita in piccoli incrementi, specialmente in un ciclo{}
attorno ai nomi delle variabili per chiarire la loro espansione (come nella riga 2 nella tabella sopra). Come si vede nelle righe 3 e 4, non è necessario a {}
meno che una variabile non sia concatenata con una stringa che inizia con un carattere che è un primo carattere valido nel nome della variabile di shell, ovvero alfabeto o carattere di sottolineatura.Guarda anche:
Ancora un altro approccio ...
> H="Hello "
> U="$H""universe."
> echo $U
Hello universe.
... e ancora un altro ancora.
> H="Hello "
> U=$H"universe."
> echo $U
Hello universe.
Se vuoi aggiungere qualcosa come un trattino basso, usa escape (\)
FILEPATH=/opt/myfile
Questo non funziona:
echo $FILEPATH_$DATEX
Funziona bene:
echo $FILEPATH\\_$DATEX
echo $a\_$b
farebbe. Come accennato nel commento di Nik O'Lai il carattere di sottolineatura è un personaggio regolare. La gestione degli spazi bianchi è molto più sensibile alle stringhe, all'eco e alla concatenazione --- si può usare \
e leggere attentamente questa discussione poiché questo problema ritorna di tanto in tanto.
Il modo più semplice con le virgolette:
B=Bar
b=bar
var="$B""$b""a"
echo "Hello ""$var"
var=$B$b"a"; echo Hello\ $var
farei, credo
Puoi concatenare senza virgolette. Ecco un esempio:
$Variable1 Open
$Variable2 Systems
$Variable3 $Variable1$Variable2
$echo $Variable3
Quest'ultima affermazione stampa "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 utilizza questo operatore su versioni precedenti di Bash fallirà con un errore "comando non trovato" se sei fortunato, o un "errore di sintassi vicino a token imprevisto".
Per coloro a cui interessa la compatibilità con le versioni precedenti, attenersi ai metodi di concatenazione Bash standard più vecchi, come quelli menzionati nella risposta scelta:
foo="Hello"
foo="$foo World"
echo $foo
> Hello World
Preferisco usare parentesi graffe ${}
per espandere la variabile nella stringa:
foo="Hello"
foo="${foo} World"
echo $foo
> Hello World
Le parentesi graffe si adatteranno all'utilizzo continuo di stringhe:
foo="Hello"
foo="${foo}World"
echo $foo
> HelloWorld
Altrimenti l'utilizzo foo = "$fooWorld"
non funzionerà.
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 tra:
$ a="hello \
> world"
$ echo $a
hello world
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 + =
d=DD DD
darei DD: command not found
--- nota che è l'ultimo DD, piuttosto d che non viene trovato. Se tutti gli operandi sono formattati correttamente e contengono già gli spazi richiesti, puoi semplicemente concatenarli s=${a}${b}${c}${d}; echo $s
, con meno virgolette. Inoltre, è possibile utilizzare \
(spazi bianchi di escape) per evitare questi problemi --- d=echo\ echo
non avvierà alcuna invocazione di eco, mentre lo d=echo echo
farà.
a="Hello,"
a=$a" World!"
echo $a
Ecco come concatenare due stringhe.
Se è come il tuo esempio di aggiunta " World"
alla stringa originale, allora può essere:
#!/bin/bash
foo="Hello"
foo=$foo" World"
echo $foo
Il risultato:
Hello World
var1='hello'
var2='world'
var3=$var1" "$var2
echo $var3
var3=$var1\ $var2
lo stesso effetto
Esistono preoccupazioni espresse in merito alle prestazioni, ma non vengono offerti dati. Lasciami 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 schiantasse. È possibile modificare il codice dal raddoppio dei dati all'aggiunta di una costante per ottenere un grafico più granulare 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.
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"
(Prova questo su host non produttivo !!;)
Nota che questo non funzionerà
foo=HELLO
bar=WORLD
foobar=PREFIX_$foo_$bar
come sembra far cadere $ foo e ti lascia con:
PREFIX_WORLD
ma questo funzionerà:
foobar=PREFIX_"$foo"_"$bar"
e lasciarti con l'output corretto:
PREFIX_HELLO_WORLD
Lo faccio in questo modo quando comodo: usa un comando in linea!
echo "The current time is `date`"
echo "Current User: `echo $USER`"
date "+The current time is %a %b %d %Y +%T"
anziché echo ...$(date)
. Sotto recente bash, si potrebbe scrivere: printf "The current time is %(%a %b %d %Y +%T)T\n" -1
.
Secondo me, il modo più semplice per concatenare due stringhe è scrivere una funzione che lo fa per te, quindi utilizzare quella funzione.
function concat ()
{
prefix=$1
suffix=$2
echo "${prefix}${suffix}"
}
foo="Super"
bar="man"
concat $foo $bar # Superman
alien=$(concat $foo $bar)
echo $alien # Superman
Mi piace fare una funzione veloce.
#! /bin/sh -f
function combo() {
echo $@
}
echo $(combo 'foo''bar')
Ancora un altro modo di scuoiare un gatto. Questa volta con funzioni: D
Non conosco ancora PHP, ma funziona con Linux Bash. Se non si desidera influire su una variabile, è possibile provare questo:
read pp; *# Assumes I will affect Hello to pp*
pp=$( printf $pp ;printf ' World'; printf '!');
echo $pp;
>Hello World!
È possibile posizionare un'altra variabile anziché "Ciao" o "!". Potresti concatenare anche più stringhe.
foo="Hello"
foo=$foo" World"
echo $foo
questo piuttosto ha funzionato per "#! / bin / sh"