La cuestión:
- Necesito asignar a una variable un valor que sea decentemente largo.
- Todas las líneas de mi script deben estar bajo un cierto número de columnas.
Entonces, estoy tratando de asignarlo usando más de una línea.
Es fácil de hacer sin sangría:
VAR="This displays without \
any issues."
echo "${VAR}"
Resultado:
This displays without any issues.
Sin embargo con sangrías:
VAR="This displays with \
extra spaces."
echo "${VAR}"
Resultado:
This displays with extra spaces.
¿Cómo puedo asignarlo elegantemente sin estos espacios?
$IFS
es una herramienta poderosa y universal, pero el código escrito de esta manera nunca puede producir resultados confiables de ningún tipo.*
?
[]
).Las soluciones dadas por esuoxu y Mickaël Bucas son las formas más comunes y portátiles de hacerlo.
Aquí hay algunas
bash
soluciones (algunas de las cuales también deberían funcionar en otros shells, comozsh
). En primer lugar, con el+=
operador append (que funciona de forma ligeramente diferente para cada una de las variables enteras, una variable regular y una matriz).Si desea nuevas líneas (u otros espacios en blanco / escapes) en el texto, utilice
$''
comillas en su lugar:A continuación, use
printf -v
para asignar un valor formateado a una variableEl truco aquí es que hay más argumentos que especificadores de formato, por lo que, a diferencia de la mayoría de las
printf
funciones, bash reutiliza la cadena de formato hasta que se agota. Puede poner un\n
dentro de la cadena de formato, o usar $ '', (o ambos) para tratar con espacios en blanco.Luego, usando una matriz:
También puede usar
+=
para construir el texto línea por línea (tenga en cuenta lo siguiente()
):Aquí, sin embargo, debe recordar "aplanar" la matriz si desea todo el contenido del texto de una vez
(las matrices indexadas enteras están ordenadas implícitamente, a diferencia de las matrices asociativas) Esto le brinda un poco más de flexibilidad, ya que puede manipular líneas e incluso cortar y cortar si es necesario.
Finalmente, usando
read
oreadarray
y un "documento aquí":La forma de documento aquí
<<-
significa que todas las pestañas duras principales se eliminan de la entrada, por lo que debe usar pestañas para sangrar el texto. Las comillas alrededor"EOT"
evitan las funciones de expansión de shell, por lo que la entrada se usa textualmente. Conread
él utiliza la entrada delimitada por bytes NUL, de modo que leerá el texto delimitado por nueva línea de una vez. Conreadarray
(también conocido comomapfile
, disponible desde bash-4.0), se lee en una matriz y-t
elimina nuevas líneas en cada línea.fuente
read
opción conhere document
es muy bonita! Útil para incrustar scripts de python y ejecutar conpython -c
. Solía hacerloscript=$(cat <here document>)
antes, peroread -r -d '' script <here document>
es mucho mejor.Hay una sintaxis especial heredoc que elimina las pestañas al principio de todas las líneas: "<< -" (observe el guión agregado)
http://tldp.org/LDP/abs/html/here-docs.html
Ejemplo 19-4. Mensaje multilínea, con pestañas suprimidas
Puedes usarlo así:
Resultado:
Funciona solo con pestañas, no espacios.
fuente
\t
funciona muy bien si necesitas pestañas. Solo use enecho -e "$v"
lugar deecho "$v"
habilitar los caracteres de barra invertidaDeje que el caparazón coma los avances de línea no deseados y los siguientes espacios:
Entonces es posible ... pero seguro que es cuestión de gustos gustar o no esta solución ...
fuente
Quizás puedas probar esto.
fuente
Así te sugiero que lo hagas, y te explicaré por qué, pero primero quiero hablar de otra cosa ...
Muchas de las otras soluciones ofrecidas aquí parecen sugerir que de alguna manera puede afectar el contenido de una variable de shell al alterar sus métodos de expansión. Les puedo asegurar que este no es el caso.
SALIDA
Lo que ve arriba es primero una expansión dividida en campo, luego un informe sobre el conteo de bytes para la variable fuente de la expansión, luego una expansión delimitada por comillas y el mismo conteo de bytes. Si bien la salida puede diferir, el contenido de la variable de shell
$string
nunca cambia en absoluto, excepto en la asignación.Lo que es más, si no comprende por qué esto es así, seguramente encontrará sorpresas muy desagradables más temprano que tarde. Intentemos eso de nuevo, pero en condiciones ligeramente diferentes.
Mismo
$string
- ambiente diferente.SALIDA
La división de campos se produce en función de los delimitadores de campo definidos en
$IFS
. Hay dos tipos de delimitadores:$IFS
espacios en blanco y$IFS
cualquier otra cosa. Por defecto$IFS
se le asigna la nueva línea de la pestaña de espacio de valores , que son los tres posibles$IFS
valores de espacio en blanco. Sin embargo, se puede cambiar fácilmente, como puede ver arriba, y puede tener efectos drásticos en las expansiones divididas en campos.$IFS
los espacios en blanco se eluirán por secuencia a un solo campo, y es por eso queecho
una expansión que contenga cualquier secuencia de espacios cuando$IFS
contenga un espacio se evaluará a un solo espacio, porqueecho
concatena sus argumentos en los espacios. Pero cualquier valor que no sea un espacio en blanco no se eliminará de la misma manera, y cada delimitador que aparece siempre obtiene un campo en sí mismo, como se puede ver en la expansión de cosas anterior.Esto no es lo peor de todo. Considera este otro
$string
.SALIDA
Se ve bien, ¿verdad? Bueno, alteremos el medio ambiente nuevamente.
SALIDA
Woah
Por defecto, el shell expandirá los globos de nombre de archivo si puede coincidir con ellos. Esto ocurre después de la expansión de parámetros y la división de campos en su orden de análisis y, por lo tanto, cualquier cadena sin comillas es vulnerable de esta manera. Puede desactivar este comportamiento
set -f
si lo desea, pero cualquier shell compatible con POSIX siempre se bloqueará de forma predeterminada.Este es el tipo de cosas con las que te enfrentas cuando sueltas citas en expansiones para satisfacer tus preferencias de sangría. Y aun así, en todos los casos, independientemente de su comportamiento de expansión, el valor real de
$string
siempre es el que fue la última vez que lo asignó. Así que volvamos a lo primero.SALIDA
Creo que esta es una forma mucho más sensata de adaptar la sintaxis de shell a sus preferencias de sangría. Lo que estoy haciendo arriba es asignar cada cadena individual a un parámetro posicional, al que se puede hacer referencia por número como
$1
o${33}
, y luego asignar sus valores concatenados para$var
usar el parámetro de shell especial$*
.Este enfoque no es inmune
$IFS
, aun así. Aún así, considero su relación con$IFS
un beneficio adicional a este respecto. Considerar:SALIDA
Como puede ver,
$*
concatena cada arg en"$@"
el primer byte en$IFS
. Por lo tanto, guardar su valor mientras$IFS
está asignado de manera diferente obtiene delimitadores de campo diferentes para cada valor guardado. Lo que ves arriba es el valor literal de cada variable, por cierto. Si no quisieras delimitador, harías lo siguiente:SALIDA
fuente
Es posible que desee probar:
o
y también puedes ver esto .
fuente
Use una expansión de sustitución de bash
Si está usando Bash, puede usar una expansión de sustitución . Por ejemplo:
fuente
Esta es una variante para establecer variables de tipo ruta:
Uso de
set
sobrescrituras$@
, que se pueden guardar y usar más tarde de la siguiente manera:La
LD_LIBRARY_PATH=$(sed 's/ :/:/g' <<< $LD_LIBRARY_PATH)
línea elimina espacios antes de los dos puntos, así como posibles espacios en blanco al final. Si solo elimina los espacios finales, useLD_LIBRARY_PATH=${LD_LIBRARY_PATH%% }
en su lugar.Todo este enfoque es una variante de la excelente respuesta de mikeserv.
fuente
No tengas miedo de los espacios en blanco. Simplemente quítelos antes de imprimir su texto multilínea.
Salida:
No es necesario usar un
<<-
heredoc y romper su sangría de 4 espacios con caracteres de tabulación.fuente