arrays - into - Convertir una matriz Bash en una cadena delimitada
split line by delimiter bash (3)
Me gustaría saber lo siguiente;
- Por qué el ejemplo que no funciona no funciona.
- Si hay otros métodos más limpios que los dados en el ejemplo de trabajo.
Ejemplo no funcional
> ids=(1 2 3 4);echo ${ids[*]// /|}
1 2 3 4
> ids=(1 2 3 4);echo ${${ids[*]}// /|}
-bash: ${${ids[*]}// /|}: bad substitution
> ids=(1 2 3 4);echo ${"${ids[*]}"// /|}
-bash: ${"${ids[*]}"// /|}: bad substitution
Ejemplo de trabajo
> ids=(1 2 3 4);id="${ids[@]}";echo ${id// /|}
1|2|3|4
> ids=(1 2 3 4); lst=$( IFS=''|''; echo "${ids[*]}" ); echo $lst
1|2|3|4
En contexto, la cadena delimitada que se utilizará en un comando sed para un análisis posterior.
También puede usar printf
, sin comandos externos o la necesidad de manipular IFS:
ids=(1 2 3 4) # create array
printf -v ids_d ''|%s'' "${ids[@]}" # yields "|1|2|3|4"
ids_d=${ids_d:1} # remove the leading ''|''
Tu primera pregunta ya está abordada en la respuesta de F. Hauri. Aquí hay una forma canónica de unir los elementos de una matriz:
ids=( 1 2 3 4 )
IFS=/| eval ''lst="${ids[*]}"''
Algunas personas gritarán en voz alta que eval
es malvado, sin embargo, es perfectamente seguro aquí, gracias a las comillas simples. Esto solo tiene ventajas: no hay subshells, IFS
no se modifica globalmente, no recortará las nuevas líneas finales y es muy simple.
# REVISION: 2017-03-14
# Use of read and other bash specific features (bashisms)
Como los paréntesis se utilizan para delimitar una matriz , no una cadena:
ids="1 2 3 4";echo ${ids// /|}
1|2|3|4
Algunas muestras: Poblando $ids
con dos cadenas: ab
y cd
ids=("a b" "c d")
echo ${ids[*]// /|}
a|b c|d
IFS=''|'';echo "${ids[*]}";IFS=$'' /t/n''
a b|c d
... y finalmente:
IFS=''|'';echo "${ids[*]// /|}";IFS=$'' /t/n''
a|b|c|d
Donde se ensambla la matriz, separados por 1er carácter de $IFS
, pero con espacio reemplazado por |
en cada elemento de la matriz.
Cuando tu lo hagas:
id="${ids[@]}"
transfiere la construcción de cadena de la fusión de los ids
matriz por un espacio a una nueva variable de tipo cadena .
Nota: cuando "${ids[@]}"
proporcione una cadena separada por espacios , "${ids[*]}"
(con una estrella *
lugar del signo @
) representará una cadena separada por el primer carácter de $IFS
.
lo que el man bash
dice:
man -Len -Pcol/ -b bash | sed -ne ''/^ *IFS /{N;N;p;q}''
IFS The Internal Field Separator that is used for word splitting
after expansion and to split lines into words with the read
builtin command. The default value is ``<space><tab><newline>''''.
Jugando con $IFS
:
set | grep ^IFS=
IFS=$'' /t/n''
declare -p IFS
declare -- IFS="
"
printf "%q/n" "$IFS"
$'' /t/n''
Literalmente un space
, una tabulation
y (significado o) un line-feed
. Entonces, mientras que el primer personaje es un espacio. el uso de *
hará lo mismo que @
.
Pero
{
# OIFS="$IFS"
# IFS=$'': /t/n''
# unset array
# declare -a array=($(echo root:x:0:0:root:/root:/bin/bash))
IFS=: read -a array < <(echo root:x:0:0:root:/root:/bin/bash)
echo 1 "${array[@]}"
echo 2 "${array[*]}"
OIFS="$IFS" IFS=:
echo 3 "${array[@]}"
echo 4 "${array[*]}"
IFS="$OIFS"
}
1 root x 0 0 root /root /bin/bash
2 root x 0 0 root /root /bin/bash
3 root x 0 0 root /root /bin/bash
4 root:x:0:0:root:/root:/bin/bash
Nota: La línea IFS=: read -a array < <(...)
usará :
como separador, sin establecer $IFS
permanentemente. Esto se debe a que la línea de salida #2
presenta espacios como separadores.