it-swarm-eu.dev

Jak spojit proměnné řetězce v Bash

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?

2423
Strawberry
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
3285
codaddict

Bash také podporuje operátora +=, jak je ukázáno v tomto kódu:

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

Bash první

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:

Připojit ke řetězci 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!

Připojit k celému číslu ((var+=...))

proměnná a je řetězec, ale také celé číslo

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

Připojit k poli 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 builtin

Příkaz printfbuiltin 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!>

Použití syntaxe Stack Overflow otázka:

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"

Shell

Ve skupinovém rámečku POSIX Shell nemůžete použít bashisms, takže neexistuje žádné vestavěnéprintf.

V podstatě

Ale mohli byste prostě udělat:

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

Formátováno pomocí vidliceprintf

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
885
F. Hauri

Můžete to udělat také:

$ var="myscript"

$ echo $var

myscript


$ var=${var}.sh

$ echo $var

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

115
orkoden
foo="Hello "
foo="$foo World"

41
vinothkr

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

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:

  • uzavření RHS přiřazení ve dvojitých uvozovkách je obecně dobrou praxí, i když v mnoha případech je to zcela volitelné
  • += je lepší z hlediska výkonu, pokud je velký řetězec konstruován v malých krocích, zejména ve smyčce
  • použít {} kolem názvů proměnných, aby se jejich rozšíření rozložilo (jako v řádku 2 v tabulce výše)

Viz také:

20
codeforester

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

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

Nejjednodušší způsob uvozovek:

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

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

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

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

13
Nick Tsai

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

7
Bohdan

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

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

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

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.

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

Takto spojíte dva řetězce.

4
CodeNinjaPI

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

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

3
Dss

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

Zde je jeden z AWK :

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