En PHP, las cadenas se concatenan juntas de la siguiente manera:
$foo = "Hello";
$foo .= " World";
Aquí, se $foo
convierte en "Hola Mundo".
¿Cómo se logra esto en Bash?
foo1="World" foo2="Hello" foo3="$foo1$foo2"
En PHP, las cadenas se concatenan juntas de la siguiente manera:
$foo = "Hello";
$foo .= " World";
Aquí, se $foo
convierte en "Hola Mundo".
¿Cómo se logra esto en Bash?
foo1="World" foo2="Hello" foo3="$foo1$foo2"
Respuestas:
foo="Hello"
foo="${foo} World"
echo "${foo}"
> Hello World
En general, para concatenar dos variables, puede escribirlas una tras otra:
a='Hello'
b='World'
c="${a} ${b}"
echo "${c}"
> Hello World
$foo
dentro de las comillas dobles, para los momentos en que realmente importa.
foo="$fooworld"
? Supongo que no ...
fooworld
. Disambiguating que se hace con llaves, como en foo="${foo}world"
...
Bash también admite un +=
operador como se muestra en este código:
$ A="X Y"
$ A+=" Z"
$ echo "$A"
X Y Z
export A+="Z"
o tal vez la A
variable solo necesita exportarse una vez?
export A+=Z
funcionan bastante bien.
#!/bin/sh
en un script que use esta construcción.
bash
ciertos shells más avanzados. No funcionará bajo busybox sh
o dash
(que está /bin/sh
en muchas distribuciones), o ciertos otros shells como el /bin/sh
proporcionado en FreeBSD.
Como esta pregunta se refiere específicamente a Bash , mi primera parte de la respuesta presentaría diferentes formas de hacerlo correctamente:
+=
: Añadir a variableLa sintaxis +=
se puede usar de diferentes maneras:
var+=...
(Porque soy frugal, que sólo utilizará dos variables foo
y a
y luego volver a utilizar la misma en toda la respuesta. ;-)
a=2
a+=4
echo $a
24
Usando la sintaxis de preguntas de desbordamiento de pila ,
foo="Hello"
foo+=" World"
echo $foo
Hello World
¡funciona bien!
((var+=...))
variable a
es una cadena, pero también un número entero
echo $a
24
((a+=12))
echo $a
36
var+=(...)
El nuestro a
también es un conjunto 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, debe encerrarlos:
a+=(one word "hello world!" )
bash: !": event not found
Hmm ... esto no es un error, sino una característica ... Para evitar que bash intente desarrollarse !"
, podría:
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 variable usando el comando incorporadoEl comando printf
incorporado ofrece una forma poderosa de dibujar el formato de cadena. Como se trata de un Bash incorporado , hay una opción para enviar cadenas formateadas a una variable en lugar de imprimir en 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á como muchos argumentos enviados ...
Tenga en cuenta que nuestra a
sigue siendo 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!")'
En bash, cuando accede a un nombre de variable sin especificar el índice, ¡siempre se dirige al primer elemento solamente!
Entonces, 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!>
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 / onewlines
printf -v foo "%s World" "$foo"
En el shell POSIX , no puede usar bashisms , por lo que no hay incorporado printf
.
Pero simplemente podrías hacer:
foo="Hello"
foo="$foo World"
echo $foo
Hello World
printf
Si desea usar construcciones más sofisticadas, debe usar una bifurcación (nuevo proceso secundario que hace el trabajo y devuelve el resultado a través de stdout
):
foo="Hello"
foo=$(printf "%s World" "$foo")
echo $foo
Hello World
Históricamente, podría usar los 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, debes 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
+=
operador también es mucho más rápido que $a="$a$b"
en mis pruebas. Lo cual tiene sentido.
var=${var}.sh
ejemplo de otras respuestas, lo cual es muy útil.
bash
el único shell con +=
operador? Quiero ver si es lo suficientemente portátil
+=
operador, pero todas estas formas son bashismos , ¡así que no son portátiles! ¡Incluso podría encontrar un error especial en caso de una versión incorrecta de bash!
También puedes hacer esto:
$ var="myscript"
$ echo $var
myscript
$ var=${var}.sh
$ echo $var
myscript.sh
var=myscript;var=$var.sh;echo $var
tendrían los mismos efectos (esto funciona en bash, dash, busybox y otros).
echo $var2
, no producemyscript2
.
ilegal en el nombre de la variable. Si más echo ${var}2
o ver mi respuesta
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 correctamente de todo lo que pones en él.
foo="Hello "
foo="$foo World"
La forma en que resolverí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 te puedes imaginar, pero
${a}World
produce
HelloWorld
${a}\ World
produceHello World
c=$a$b
que hiciera lo mismo que c=$a World
(que intentaría ejecutarse World
como un comando). Supongo que eso significa que la cesión se procesadas antes que se expanden las variables ..
Aquí hay un resumen conciso de lo que están hablando la mayoría de las respuestas.
Digamos que tenemos dos variables y $ 1 se establece en 'uno':
set one two
a=hello
b=world
La siguiente tabla explica los diferentes contextos en los que podemos combinar los valores de a
y b
para crear una nueva variable, 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
Algunas notas
+=
es mejor desde el punto de vista del rendimiento si se construye una cadena grande en pequeños incrementos, especialmente en un bucle{}
alrededor de nombres de variables para desambiguar su expansión (como en la fila 2 de la tabla anterior). Como se ve en las filas 3 y 4, no es necesario a {}
menos que una variable se concatene con una cadena que comienza con un carácter que es un primer carácter válido en el nombre de la variable de shell, es decir, alfabeto o guión bajo.Ver también:
Otro enfoque más ...
> H="Hello "
> U="$H""universe."
> echo $U
Hello universe.
... y otro más.
> H="Hello "
> U=$H"universe."
> echo $U
Hello universe.
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
echo $a\_$b
lo haría. Como se insinuó en el comentario de Nik O'Lai, el guión bajo es un personaje normal. El manejo de los espacios en blanco es mucho más sensible para las cadenas, el eco y la concatenación: se puede usar \
y leer este hilo a fondo a medida que este problema vuelve de vez en cuando.
La forma más simple con comillas:
B=Bar
b=bar
var="$B""$b""a"
echo "Hello ""$var"
var=$B$b"a"; echo Hello\ $var
haría, creo
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
Incluso si el operador + = ahora está permitido, se introdujo en Bash 3.1 en 2004.
Cualquier script que use este operador en versiones anteriores de Bash fallará con un error de "comando no encontrado" si tiene suerte, o un "error de sintaxis cerca de un token inesperado".
Para aquellos que se preocupan por la compatibilidad con versiones anteriores, quédese con los métodos de concatenación Bash estándar más antiguos, como los mencionados en la respuesta elegida:
foo="Hello"
foo="$foo World"
echo $foo
> Hello World
Si lo que intenta hacer es dividir una cadena en varias líneas, puede 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 intermedio:
$ a="hello \
> world"
$ echo $a
hello world
Forma 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 formar parte del comando, use "$ XXX" y "$ {XXX}" para evitar estos errores.
Además, mira otra respuesta sobre + =
d=DD DD
daría DD: command not found
--- nota que es el último DD, más bien d que no se encuentra. Si todos los operandos están formateados correctamente y ya contienen los espacios requeridos, simplemente puede concatenar s=${a}${b}${c}${d}; echo $s
con menos comillas. También podría usar \
(espacios en blanco escapados) para evitar estos problemas --- d=echo\ echo
no lanzará ninguna invocación de eco, mientras que lo d=echo echo
hará.
a="Hello,"
a=$a" World!"
echo $a
Así es como se concatenan dos cadenas.
Si es como su ejemplo de agregar " World"
a la cadena original, entonces puede ser:
#!/bin/bash
foo="Hello"
foo=$foo" World"
echo $foo
La salida:
Hello World
var1='hello'
var2='world'
var3=$var1" "$var2
echo $var3
var3=$var1\ $var2
tiene el mismo efecto
Hay preocupaciones expresadas sobre el rendimiento, pero no se ofrecen datos. Déjame sugerirte una prueba simple.
(NOTA: date
en macOS no ofrece nanosegundos, por lo que 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 bloqueara . Puede 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 darle suficiente información para decidir si le importa. Personalmente, menos de 100 MB no. Su experiencia puede ser diferente.
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"
(¡Pruebe esto en un host no productivo
Tenga en cuenta que esto no funcionará
foo=HELLO
bar=WORLD
foobar=PREFIX_$foo_$bar
ya que 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
Lo hago de esta manera cuando sea conveniente: ¡use un comando en línea!
echo "The current time is `date`"
echo "Current User: `echo $USER`"
date "+The current time is %a %b %d %Y +%T"
lugar de echo ...$(date)
. Bajo reciente fiesta, se podría escribir: printf "The current time is %(%a %b %d %Y +%T)T\n" -1
.
En mi opinión, la forma más sencilla de concatenar dos cadenas es escribir una función que lo haga por usted y luego usar esa función.
function concat ()
{
prefix=$1
suffix=$2
echo "${prefix}${suffix}"
}
foo="Super"
bar="man"
concat $foo $bar # Superman
alien=$(concat $foo $bar)
echo $alien # Superman
Me gusta hacer una función rápida.
#! /bin/sh -f
function combo() {
echo $@
}
echo $(combo 'foo''bar')
Otra forma más de pelar un gato. Esta vez con funciones: D
Todavía no sé sobre PHP, pero esto funciona en Linux Bash. Si no desea afectarlo a una variable, puede 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 '!'. También podría concatenar más cadenas.
foo="Hello"
foo=$foo" World"
echo $foo
esto funcionó más bien para "#! / bin / sh"