V PHP jsou řetězce zřetězeny následovně:
$foo = "Hello";
$foo .= " World";
Zde se $foo
stává "Hello World".
Jak se toho dosahuje v Bash?
foo="Hello"
foo="$foo World"
echo $foo
> Hello World
Obecně lze zřetěžit dvě proměnné, stačí je zapsat jeden po druhém:
a='hello'
b='world'
c="$a$b"
echo $c
> helloworld
Bash také podporuje operátora +=
, jak je ukázáno v tomto kódu:
$ A="X Y"
$ A+=" Z"
$ echo "$A"
X Y Z
Jak tato otázka stojí konkrétně pro Bash , moje první část odpovědi by představovala různé způsoby, jak toho dosáhnout:
+=
: Připojit k proměnnéSyntaxe+=
může být použita různými způsoby:
var+=...
(Protože jsem skromný, použiju pouze dvě proměnné foo
a a
a pak znovu použiji totéž v celé odpovědi. ;-)
a=2
a+=4
echo $a
24
Použití syntaxe Stack Overflow otázka,
foo="Hello"
foo+=" World"
echo $foo
Hello World
funguje dobře!
((var+=...))
proměnná a
je řetězec, ale také celé číslo
echo $a
24
((a+=12))
echo $a
36
var+=(...)
Naše a
je také pole pouze jednoho prvku.
echo ${a[@]}
36
a+=(18)
echo ${a[@]}
36 18
echo ${a[0]}
36
echo ${a[1]}
18
Všimněte si, že mezi závorkami je mezera oddělená mezerou. Pokud chcete uložit řetězec obsahující mezery ve vašem poli, musíte je uzavřít:
a+=(one Word "hello world!" )
bash: !": event not found
Hmm .. to není chyba, ale funkce ... Chcete-li zabránit bash pokusit se vytvořit !"
, můžete:
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
: Znovu sestavte proměnnou pomocí příkazu builtinPříkaz printf
builtin poskytuje mocný způsob formátování řetězce kreslení. Jelikož se jedná o Bash builtin, existuje možnost odesílání formátovaného řetězce do proměnné namísto tisku na stdout
:
echo ${a[@]}
36 18 one Word hello world! hello world! hello world!
V tomto poli je sedm řetězců. Můžeme tedy vytvořit formátovaný řetězec obsahující přesně sedm argumentů polohy:
printf -v a "%s./.%s...'%s' '%s', '%s'=='%s'=='%s'" "${a[@]}"
echo $a
36./.18...'one' 'Word', 'hello world!'=='hello world!'=='hello world!'
Nebo bychom mohli použít jeden řetězec ve formátu argumentu, který bude opakován, jak mnoho předložených argumentů ...
Naše a
je stále pole! Změní se pouze první prvek!
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!")'
V případě bash, když přistupujete k názvu proměnné, aniž byste určili index, vždy adresujete pouze první prvek!
Abychom mohli získat sedm polí pole, musíme znovu nastavit první prvek:
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!")'
Jeden řetězec formátu argumentu s mnoha argumenty předán:
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
Poznámka: Použití double-quotes může být užitečné pro manipulaci s řetězci, které obsahují spaces
, tabulations
a/nebo newlines
printf -v foo "%s World" "$foo"
Ve skupinovém rámečku POSIX Shell nemůžete použít bashisms, takže neexistuje žádné vestavěnéprintf
.
Ale mohli byste prostě udělat:
foo="Hello"
foo="$foo World"
echo $foo
Hello World
printf
Pokud chcete použít sofistikovanější konstrukce, musíte použít vidličku (nový podřízený proces, který provede úlohu a vrátí výsledek pomocí stdout
):
foo="Hello"
foo=$(printf "%s World" "$foo")
echo $foo
Hello World
Historicky jste mohli použít backticks pro načtení výsledku z vidlice:
foo="Hello"
foo=`printf "%s World" "$foo"`
echo $foo
Hello World
Ale to není snadné pro vnoření:
foo="Today is: "
foo=$(printf "%s %s" "$foo" "$(date)")
echo $foo
Today is: Sun Aug 4 11:58:23 CEST 2013
s backticks, musíte uniknout vnitřní vidlice s zpětná lomítka:
foo="Today is: "
foo=`printf "%s %s" "$foo" "\`date\`"`
echo $foo
Today is: Sun Aug 4 11:59:10 CEST 2013
Můžete to udělat také:
$ var="myscript"
$ echo $var
myscript
$ var=${var}.sh
$ echo $var
myscript.sh
bla=hello
laber=kthx
echo "${bla}ohai${laber}bye"
Bude výstup
helloohaikthxbye
To je užitečné, když $blaohai
vede k chybě, která nebyla nalezena. Nebo pokud máte v řetězcích mezery nebo jiné speciální znaky. "${foo}"
správně unikne cokoliv, co do něj vložíte.
foo="Hello "
foo="$foo World"
Způsob, jakým bych problém vyřešil, je prostě
$a$b
Například,
a="Hello"
b=" World"
c=$a$b
echo "$c"
který produkuje
Hello World
Pokud se pokusíte spojit řetězec s jiným řetězcem, například
a="Hello"
c="$a World"
pak echo "$c"
bude produkovat
Hello World
s více prostoru.
$aWorld
nefunguje, jak si můžete představit, ale
${a}World
vyrábí
HelloWorld
$ a=hip
$ b=hop
$ ab=$a$b
$ echo $ab
hiphop
$ echo $a$b
hiphop
Zde je stručné shrnutí toho, o čem většina odpovědí mluví.
Řekněme, že máme dvě proměnné:
a=hello
b=world
Níže uvedená tabulka vysvětluje různé kontexty, ve kterých můžeme kombinovat hodnoty a
a b
a vytvořit novou proměnnou 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
Několik poznámek:
+=
je lepší z hlediska výkonu, pokud je velký řetězec konstruován v malých krocích, zejména ve smyčce{}
kolem názvů proměnných, aby se jejich rozšíření rozložilo (jako v řádku 2 v tabulce výše)Viz také:
Pokud chcete připojit něco jako podtržítko, použijte příkaz escape (\ t
FILEPATH=/opt/myfile
Toto dělá ne práce:
echo $FILEPATH_$DATEX
Funguje to dobře:
echo $FILEPATH\\_$DATEX
Ještě další přístup ...
> H="Hello "
> U="$H""universe."
> echo $U
Hello universe.
... a ještě další.
> H="Hello "
> U=$H"universe."
> echo $U
Hello universe.
Nejjednodušší způsob uvozovek:
B=Bar
b=bar
var="$B""$b""a"
echo "Hello ""$var"
Můžete zřetězit bez uvozovek. Zde je příklad:
$Variable1 Open
$Variable2 Systems
$Variable3 $Variable1$Variable2
$echo $Variable3
Toto poslední prohlášení by vytisklo "OpenSystems" (bez uvozovek).
Toto je příklad skriptu Bash:
v1=hello
v2=world
v3="$v1 $v2"
echo $v3 # Output: hello world
echo "$v3" # Output: hello world
I když je operátor + = nyní povolen, byl zaveden v Bash 3.1 v roce 2004.
Jakýkoliv skript používající tento operátor na starších verzích Bash se nezdaří s chybou "příkaz nebyl nalezen", pokud máte štěstí, nebo "syntaktickou chybou poblíž neočekávaného tokenu".
Pro ty, kteří se starají o zpětnou kompatibilitu, se držte starších standardních metod Bash concatenation, jako jsou ty, které jsou uvedeny ve zvolené odpovědi:
foo="Hello"
foo="$foo World"
echo $foo
> Hello World
Dávám přednost použití složených závorek ${}
pro rozšíření proměnné v řetězci:
foo="Hello"
foo="${foo} World"
echo $foo
> Hello World
Kudrnaté závorky se hodí k použití spojitého řetězce:
foo="Hello"
foo="${foo}World"
echo $foo
> HelloWorld
Jinak nebude fungovat foo = "$fooWorld"
.
Bezpečnější způsob:
a="AAAAAAAAAAAA"
b="BBBBBBBBBBBB"
c="CCCCCCCCCCCC"
d="DD DD"
s="${a}${b}${c}${d}"
echo "$s"
AAAAAAAAAAAABBBBBBBBBBBBCCCCCCCCCCCCDD DD
Řetězy obsahující mezery se mohou stát součástí příkazu, pomocí „$ XXX“ a „$ {XXX}“ se těmto chybám vyhnout.
Plus se podívejte na další odpověď o + =
Pokud to, co se snažíte udělat, je rozdělit řetězec do několika řádků, můžete použít zpětné lomítko:
$ a="hello\
> world"
$ echo $a
helloworld
S jedním mezerou mezi:
$ a="hello \
> world"
$ echo $a
hello world
Ten také přidává pouze jeden prostor mezi:
$ a="hello \
> world"
$ echo $a
hello world
Existuje jeden konkrétní případ, kdy byste měli dbát:
user=daniel
cat > output.file << EOF
"$user"san
EOF
Bude výstup "daniel"san
, a ne danielsan
, jak jste možná chtěli. V tomto případě byste měli udělat:
user=daniel
cat > output.file << EOF
${user}san
EOF
Pokud je to jako příklad přidání " World"
do původního řetězce, pak to může být:
#!/bin/bash
foo="Hello"
foo=$foo" World"
echo $foo
Výstup:
Hello World
var1='hello'
var2='world'
var3=$var1" "$var2
echo $var3
Existují vyjádřené obavy o výkonnost, ale žádná data nejsou nabízena. Dovolte mi navrhnout jednoduchý test.
(POZNÁMKA: date
na makrech nenabízí nanosekundy, takže to musí být provedeno v Linuxu.)
Vytvořil jsem append_test.sh na GitHub s obsahem:
#!/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
Chyby ukazují, že můj Bash se dostal do 335,54432 MB před tím, než havaroval. Dalo by se změnit kód z zdvojení dat, aby se připojila konstanta, aby se získal podrobnější graf a bod selhání. Ale myslím, že by vám to mělo poskytnout dostatek informací, abyste se mohli rozhodnout, zda vám záleží. Osobně pod 100 MB nemám. Počet najetých kilometrů se může lišit.
a="Hello,"
a=$a" World!"
echo $a
Takto spojíte dva řetězce.
Chtěl jsem vytvořit seznam ze seznamu. Nemohl jsem na to najít odpověď, takže ji sem pošlu. Tady je to, co jsem udělal:
list=(1 2 3 4 5)
string=''
for Elm in "${list[@]}"; do
string="${string} ${Elm}"
done
echo ${string}
a pak dostanu následující výstup:
1 2 3 4 5
Všimněte si, že to nebude fungovat
foo=HELLO
bar=WORLD
foobar=PREFIX_$foo_$bar
jak to vypadá, že upustí $ foo a nechá vás:
PREFIX_WORLD
ale bude to fungovat:
foobar=PREFIX_"$foo"_"$bar"
a ponechte si správný výstup:
PREFIX_HELLO_WORLD
Udělám to tímto způsobem, když je to vhodné: Použijte inline příkaz!
echo "The current time is `date`"
echo "Current User: `echo $USER`"
Zde je jeden z AWK :
$ foo="Hello"
$ foo=$(awk -v var=$foo 'BEGIN{print var" World"}')
$ echo $foo
Hello World