Probablemente sea bueno tener el hábito de poner $foodentro de las comillas dobles, para los momentos en que realmente importa.
Cascabel
104
Se nos enseña a hacerlo siempre porque cuando se realiza la sustitución, los espacios serán ignorados por el shell, pero las comillas dobles siempre protegerán esos espacios.
Fresa
6262
¿Tiene que haber un espacio en su primer ejemplo? ¿Es posible hacer algo así foo="$fooworld"? Supongo que no ...
nonsensickle
341
@nonsensickle Eso buscaría una variable llamada fooworld. Disambiguating que se hace con llaves, como en foo="${foo}world"...
twalberg
44
@ JVE999 Sí, eso también funciona, aunque en mi opinión no es tan bueno para la claridad del código ... Pero esa puede ser mi preferencia ... También hay un par de otras formas en que se puede hacer: el punto es asegurándose de que el nombre de la variable esté separado de las partes que no son de nombre variable para que se analice correctamente.
twalberg
1128
Bash también admite un +=operador como se muestra en este código:
¿Puedo usar esta sintaxis con la palabra clave exportar? por ejemplo, ¿ export A+="Z"o tal vez la Avariable solo necesita exportarse una vez?
Levesque
3
@levesque: Ambos :-). Las variables solo necesitan exportarse una vez, pero también export A+=Zfuncionan bastante bien.
thkala
38
Como se trata de un bashism, creo que vale la pena mencionar que nunca deberías usar #!/bin/shen un script que use esta construcción.
Score_Under
2
Es específicamente y solo un operador más-igual. Es decir, a diferencia de Javascript, en Bash, echo $ A + $ B imprime "X Y + Z"
phpguru
66
Un bashism es una función de shell que solo es compatible con bashciertos shells más avanzados. No funcionará bajo busybox sho dash(que está /bin/shen muchas distribuciones), o ciertos otros shells como el /bin/shproporcionado en FreeBSD.
Score_Under
960
Bash primero
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 variable
La sintaxis +=se puede usar de diferentes maneras:
Añadir a cadena var+=...
(Porque soy frugal, que sólo utilizará dos variables fooy ay 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
HelloWorld
¡funciona bien!
Agregar a un entero ((var+=...))
variable aes una cadena, pero también un número entero
echo $a
24((a+=12))
echo $a
36
Agregar a una matriz var+=(...)
El nuestro atambién es un conjunto de un solo elemento.
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
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 incorporado
El comando printfincorporado 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[@]}3618 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:
Nota: El uso de comillas dobles puede ser útil para manipular cadenas que contienen spaces, tabulationsy / onewlines
printf -v foo "%s World""$foo"
Shell ahora
En el shell POSIX , no puede usar bashisms , por lo que no hay incorporadoprintf .
Básicamente
Pero simplemente podrías hacer:
foo="Hello"
foo="$foo World"
echo $foo
HelloWorld
Formateado, utilizando bifurcadoprintf
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):
El +=operador también es mucho más rápido que $a="$a$b"en mis pruebas. Lo cual tiene sentido.
Matt
77
Esta respuesta es increíble, pero creo que le falta el var=${var}.shejemplo de otras respuestas, lo cual es muy útil.
geneorama
1
¿Es bashel único shell con +=operador? Quiero ver si es lo suficientemente portátil
guioneso
1
@dashesy no. seguramente no es el único shell con +=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!
Si bien no se utilizan caracteres especiales ni espacios, las comillas dobles, las comillas y las llaves son inútiles: var=myscript;var=$var.sh;echo $vartendrían los mismos efectos (esto funciona en bash, dash, busybox y otros).
F. Hauri
@ F.Hauri gracias por señalar eso. Pero si tuviera que agregar un número, no funcionaría: por ejemplo echo $var2, no producemyscript2
Pynchia
@Pynchia Esto funciona debido al punto .ilegal en el nombre de la variable. Si más echo ${var}2o ver mi respuesta
F. Hauri
119
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.
Esta es la respuesta más útil para los scripts de shell. ¡¡Me encontré los últimos 30 minutos porque tuve un espacio antes y después del signo igual !!
Stefan
8
foo = "$ {foo} Mundo"
XXL
@XXL seguramente preferiría usar corchetes para encapsular el nombre de var. Muy recomendable
Sergio A.
33
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
HelloWorld
Si intenta concatenar una cadena con otra cadena, por ejemplo,
Esto me sorprende Hubiera esperado c=$a$bque hiciera lo mismo que c=$a World(que intentaría ejecutarse Worldcomo un comando). Supongo que eso significa que la cesión se procesadas antes que se expanden las variables ..
mwfearnley
31
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 ay bpara 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
encerrar el RHS de una tarea entre comillas dobles es generalmente una buena práctica, aunque es bastante opcional en muchos casos
+= es mejor desde el punto de vista del rendimiento si se construye una cadena grande en pequeños incrementos, especialmente en un bucle
use {}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.
Eso es lo que hice, y lo encontré mucho más simple y directo que las otras respuestas. ¿Hay alguna razón por la cual nadie en las respuestas más votadas señaló esta opción?
quimnuss
1
@quimnuss El hecho de que las cadenas no coincidan con las utilizadas en la pregunta OP podría ser una buena razón.
jlliagre el
20
Si desea agregar algo como un guión bajo, use escape (\)
O, alternativamente, $ {FILEPATH} _ $ DATEX. Aquí {} se utilizan para indicar los límites del nombre de la variable. Esto es apropiado porque el guión bajo es un carácter legal en los nombres de variables, por lo que en su fragmento de código intenta realmente resolver FILEPATH_, no solo $ FILEPATH
Nik O'Lai
1
para mí tenía una variable, es decir, $ var1 y constante al lado de esto, por lo que echo $ var1_costant_traling_part funciona para mí
YouAreAwesome
2
Supongo que uno solo necesita una reacción violenta para escapar: echo $a\_$blo 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 sintaxis del primer bloque es confusa. ¿Qué significan estos signos $?
XavierStuvw
15
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:
El punto de las cadenas con un espacio que se lee como un comando aparece en el punto de definición. Entonces d=DD DDdarí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 $scon menos comillas. También podría usar \ (espacios en blanco escapados) para evitar estos problemas --- d=echo\ echono lanzará ninguna invocación de eco, mientras que lo d=echo echohará.
XavierStuvw
7
Hay un caso particular en el que debes tener cuidado:
Esto funciona, pero a veces arrojará resultados impredecibles porque la interpolación variable no está protegida. Por lo tanto, no puede confiar en este formulario para todos los casos de uso.
Anthony Rutledge
5
Si es como su ejemplo de agregar " World"a la cadena original, entonces puede ser:
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.
Esto sucede porque el guión bajo es el carácter válido en los nombres de las variables, por lo que bash ve a foo_ como una variable. Cuando es necesario decirle a bash los límites exactos del nombre de var, se pueden usar las llaves: PREFIJO _ $ {foo} _ $ bar
En la primera línea, puede soltar un tenedor usando:, en 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.
F. Hauri
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.
foo="Hello"
foo=$foo" World"
echo $foo
esto funcionó más bien para "#! / bin / sh"foo1="World" foo2="Hello" foo3="$foo1$foo2"
Respuestas:
En general, para concatenar dos variables, puede escribirlas una tras otra:
fuente
$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 enfoo="${foo}world"
...Bash también admite un
+=
operador como se muestra en este código:fuente
export A+="Z"
o tal vez laA
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á bajobusybox sh
odash
(que está/bin/sh
en muchas distribuciones), o ciertos otros shells como el/bin/sh
proporcionado en FreeBSD.Bash primero
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:Añadir a cadena
var+=...
(Porque soy frugal, que sólo utilizará dos variables
foo
ya
y luego volver a utilizar la misma en toda la respuesta. ;-)Usando la sintaxis de preguntas de desbordamiento de pila ,
¡funciona bien!
Agregar a un entero
((var+=...))
variable
a
es una cadena, pero también un número enteroAgregar a una matriz
var+=(...)
El nuestro
a
también es un conjunto de un solo elemento.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:
Hmm ... esto no es un error, sino una característica ... Para evitar que bash intente desarrollarse
!"
, podría: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 enstdout
:Hay siete cadenas en esta matriz. Entonces podríamos construir una cadena formateada que contenga exactamente siete argumentos posicionales:
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!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:
Una cadena de formato de argumento con muchos argumentos pasados a:
Usando la sintaxis de preguntas de desbordamiento de pila :
Nota: El uso de comillas dobles puede ser útil para manipular cadenas que contienen
spaces
,tabulations
y / onewlines
Shell ahora
En el shell POSIX , no puede usar bashisms , por lo que no hay incorporado
printf
.Básicamente
Pero simplemente podrías hacer:
Formateado, utilizando bifurcado
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
):Históricamente, podría usar los backticks para recuperar el resultado de una bifurcación :
Pero esto no es fácil para anidar :
con backticks, debes escapar de las horquillas internas con barras invertidas :
fuente
+=
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:
fuente
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ásecho ${var}2
o ver mi respuestaSaldrá
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.fuente
fuente
La forma en que resolvería el problema es simplemente
Por ejemplo,
que produce
Si intenta concatenar una cadena con otra cadena, por ejemplo,
entonces
echo "$c"
produciráCon un espacio extra.
no funciona, como te puedes imaginar, pero
produce
fuente
${a}\ World
produceHello World
c=$a$b
que hiciera lo mismo quec=$a World
(que intentaría ejecutarseWorld
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':
La siguiente tabla explica los diferentes contextos en los que podemos combinar los valores de
a
yb
para crear una nueva variable,c
.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:
fuente
fuente
Otro enfoque más ...
... y otro más.
fuente
Si desea agregar algo como un guión bajo, use escape (\)
Esto no funciona:
Esto funciona bien:
fuente
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:
fuente
var=$B$b"a"; echo Hello\ $var
haría, creoPuedes concatenar sin las comillas. Aquí hay un ejemplo:
Esta última declaración imprimiría "OpenSystems" (sin comillas).
Este es un ejemplo de un script Bash:
fuente
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:
fuente
Prefiero usar llaves
${}
para expandir la variable en cadena:Las llaves se ajustarán al uso continuo de cadenas:
De lo contrario, el uso
foo = "$fooWorld"
no funcionará.fuente
Si lo que intenta hacer es dividir una cadena en varias líneas, puede usar una barra invertida:
Con un espacio en el medio:
Este también agrega solo un espacio intermedio:
fuente
Forma más segura:
Las cadenas que contienen espacios pueden formar parte del comando, use "$ XXX" y "$ {XXX}" para evitar estos errores.
Además, mira otra respuesta sobre + =
fuente
d=DD DD
daríaDD: 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 concatenars=${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 lod=echo echo
hará.Hay un caso particular en el que debes tener cuidado:
Saldrá
"daniel"san
, y nodanielsan
, como podría haber querido. En este caso, deberías hacer en su lugar:fuente
Así es como se concatenan dos cadenas.
fuente
Si es como su ejemplo de agregar
" World"
a la cadena original, entonces puede ser:La salida:
fuente
fuente
var3=$var1\ $var2
tiene el mismo efectoHay 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:
Prueba 1:
Prueba 2:
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.
fuente
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 productivoQuería construir una cadena de una lista. No pude encontrar una respuesta para eso, así que lo publico aquí. Aquí esta lo que hice:
y luego obtengo el siguiente resultado:
fuente
A pesar del operador especial
+=
, para la concatenación, hay un camino más simple:Las comillas dobles requieren un tiempo de cálculo adicional para la interpretación de las variables internas. Evítalo si es posible.
fuente
Tenga en cuenta que esto no funcionará
ya que parece caer $ foo y te deja con:
pero esto funcionará:
y te dejo con la salida correcta:
fuente
Aquí está el de AWK :
fuente
Lo hago de esta manera cuando sea conveniente: ¡use un comando en línea!
fuente
date "+The current time is %a %b %d %Y +%T"
lugar deecho ...$(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.
fuente
Me gusta hacer una función rápida.
Otra forma más de pelar un gato. Esta vez con funciones: D
fuente
Todavía no sé sobre PHP, pero esto funciona en Linux Bash. Si no desea afectarlo a una variable, puede intentar esto:
Podría colocar otra variable en lugar de 'Hola' o '!'. También podría concatenar más cadenas.
fuente