unir - variables en bash




Cómo concatenar variables de cadena en Bash (19)

Bash primero

Como esta pregunta representa específicamente a Bash , mi primera parte de la respuesta presentaría diferentes formas de hacerlo correctamente:

+= : Añadir a la variable

La sintaxis += se puede utilizar de diferentes maneras:

Añadir a la cadena var+=...

(Debido a que soy frugal, solo usaré dos variables foo y a y luego reutilizaré lo mismo en toda la respuesta ;-)

a=2
a+=4
echo $a
24

Usando la sintaxis de pregunta de desbordamiento de pila ,

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

¡funciona bien!

Anexar a un entero ((var+=...))

la variable a es una cadena, pero también un entero

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

Anexar a una matriz var+=(...)

Nuestro a es también una matriz de un solo elemento.

echo ${a[@]}
36

a+=(18)

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

Tenga en cuenta que entre paréntesis, hay una matriz separada por espacios . Si desea almacenar una cadena que contiene espacios en su matriz, tiene que incluirlos:

a+=(one word "hello world!" )
bash: !": event not found

Hmm ... esto no es un error, sino una característica ... ¡Para evitar que bash intente desarrollar !" , Podrías:

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 : reconstruir la variable usando el comando incorporado

El comando incorporado printf proporciona una forma poderosa de dibujar formato de cadena. Como este es un Bash incorporado , hay una opción para enviar una cadena con formato a una variable en lugar de imprimir en la stdout :

echo ${a[@]}
36 18 one word hello world! hello world! hello world!

Hay siete cadenas en esta matriz. Entonces podríamos construir una cadena formateada que contenga exactamente siete argumentos posicionales:

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

O podríamos usar una cadena de formato de argumento que se repetirá a medida que muchos argumentos se presenten ...

Tenga en cuenta que nuestro a es todavía una matriz! ¡Solo se cambia el primer 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!")'

Bajo bash, cuando accede a un nombre de variable sin especificar el índice, ¡siempre direcciona solo el primer elemento!

Así que para recuperar nuestra matriz de siete campos, solo necesitamos restablecer el primer 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 cadena de formato de argumento con muchos argumentos pasados ​​a:

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

Usando la sintaxis de la pregunta de desbordamiento de pila :

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

Nota: El uso de comillas dobles puede ser útil para manipular cadenas que contienen spaces , tabulations y / o newlines

printf -v foo "%s World" "$foo"

Shell ahora

Bajo el shell POSIX , no se podían usar bashismos , por lo que no hay printf incorporado .

Básicamente

Pero simplemente podrías hacer:

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

Formato, utilizando printf bifurcado.

Si desea usar construcciones más sofisticadas, tiene que usar una bifurcación (nuevo proceso secundario que hace el trabajo y devuelve el resultado a través de la stdout ):

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

Históricamente, podría usar backticks para recuperar el resultado de una bifurcación :

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

Pero esto no es fácil para anidar :

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

con backticks, tienes que escapar de las horquillas internas con barras invertidas :

foo="Today is: "
foo=`printf "%s %s" "$foo" "\`date\`"`
echo $foo
Today is: Sun Aug 4 11:59:10 CEST 2013

En PHP, las cadenas se concatenan de la siguiente manera:

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

Aquí, $foo convierte en "Hello World".

¿Cómo se logra esto en Bash?


Aquí está el uno a través de AWK :

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

Bash también admite un operador + = como se muestra en la siguiente transcripción:

$ A="X Y"
$ A+="Z"
$ echo "$A"
X YZ

Hay un caso particular en el que debes tener cuidado:

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

danielsan "daniel"san , y no danielsan , como podrías haber deseado. En este caso deberías hacer en su lugar:

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

La forma en que solucionaría el problema es simplemente

$a$b

Por ejemplo,

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

que produce

Hello World

Si intenta concatenar una cadena con otra cadena, por ejemplo,

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

entonces echo "$c" producirá

Hello World

Con un espacio extra.

$aWorld

no funciona, como puedes imaginar, pero

${a}World

produce

HelloWorld

La forma más sencilla con comillas:

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

Manera más segura:

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

Las cadenas que contienen espacios pueden convertirse en parte del comando, use "$ XXX" y "$ {XXX}" para evitar estos errores.

Además, echa un vistazo a otra respuesta sobre + =


Me gusta hacer una función rápida.

#! /bin/sh -f
function combo() {
    echo [email protected]
}

echo $(combo 'foo''bar')

Otra forma de pelar a un gato. Esta vez con funciones: D


Puedes concatenar sin las comillas. Aquí hay un ejemplo:

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

Esta última declaración imprimiría "OpenSystems" (sin comillas).

Este es un ejemplo de un script Bash:

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

Puedes probar el siguiente camino. Cuando tiene lugar la sustitución, las comillas dobles mantendrán los espacios.

var1="Ram "    
var2="Lakshmana" 
echo $var1$var2
or 
echo var1+=$var2 "bash support += operation.

bcsmc2rtese001 [/tmp]$ var1="Ram "  
bcsmc2rtese001 [/tmp]$ var2="Lakshmana"  
bcsmc2rtese001 [/tmp]$ echo $var1$var2  
Ram Lakshmana  

bcsmc2rtese001 [/tmp]$ var1+=$var2  
bcsmc2rtese001 [/tmp]$ echo $var1  
Ram Lakshmana

Se expresan preocupaciones sobre el rendimiento, pero no se ofrecen datos. Déjame sugerir una prueba simple.

(NOTA: la date en macOS no ofrece nanosegundos, por lo que esto debe hacerse en Linux).

He creado append_test.sh en GitHub con el contenido:

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

Prueba 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

Prueba 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

Los errores indican que mi Bash llegó a 335.54432 MB antes de que se estrellara. Podría cambiar el código de duplicar los datos a agregar una constante para obtener un gráfico más detallado y un punto de falla. Pero creo que esto debería darte suficiente información para decidir si te importa. Personalmente, por debajo de 100 MB no lo hago. Su experiencia puede ser diferente.


Si desea agregar algo como un guión bajo, use escape (\)

FILEPATH=/opt/myfile

Esto no funciona:

echo $FILEPATH_$DATEX

Esto funciona bien:

echo $FILEPATH\\_$DATEX

Si lo que intentas hacer es dividir una cadena en varias líneas, puedes usar una barra invertida:

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

Con un espacio en el medio:

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

Este también agrega solo un espacio en medio:

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

Sin embargo, otro enfoque ...

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

... y aún otro más.

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

Tenga en cuenta que esto no funcionará

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

Como parece caer $ foo y te deja con:

PREFIX_WORLD

pero esto funcionará:

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

y te dejo con la salida correcta:

PREFIX_HELLO_WORLD


Todavía no sé sobre PHP, pero esto funciona en Linux Bash. Si no quieres afectarlo a una variable, puedes intentar esto:

read pp;  *# Assumes I will affect Hello to pp*
pp=$( printf $pp ;printf ' World'; printf '!');
echo $pp;

>Hello World!

Podría colocar otra variable en lugar de 'Hola' o '!'. Usted podría concatenar más cadenas también.


bla=hello
laber=kthx
echo "${bla}ohai${laber}bye"

Saldrá

helloohaikthxbye

Esto es útil cuando $blaohai conduce a un error de variable no encontrada. O si tiene espacios u otros caracteres especiales en sus cadenas. "${foo}" escapa adecuadamente a todo lo que le pongas.


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


var1='hello'
var2='world'
var3=$var1" "$var2 
echo $var3




string-concatenation