Los shells tipo Bourne / POSIX tienen un operador split + glob y se invoca cada vez que deja una expansión de parámetro ( $var, $-...), una sustitución de comando ( $(...)) o una expansión aritmética ( $((...))) sin comillas en el contexto de la lista.
En realidad, lo invocaste por error cuando lo hiciste en for name in ${array[@]}lugar de hacerlo for name in "${array[@]}". (En realidad, debe tener cuidado de que invocar a ese operador por error es fuente de muchos errores y vulnerabilidades de seguridad ).
Ese operador está configurado con el $IFSparámetro especial (para indicar en qué caracteres dividir (aunque tenga cuidado con que el espacio, la pestaña y la nueva línea reciban un tratamiento especial allí)) y la -fopción de deshabilitar ( set -f) o habilitar ( set +f) la globparte.
También tenga en cuenta que si bien el Sin $IFSera originalmente (en el shell Bourne de donde $IFSproviene) para el Sseparador, en los shells POSIX, los caracteres en $IFSdeberían verse como delimitadores o terminadores (ver a continuación un ejemplo).
Entonces para dividir _:
string='var1_var2_var3'
IFS=_ # delimit on _
set -f # disable the glob part
array=($string) # invoke the split+glob operator
for i in "${array[@]}"; do # loop over the array elements.
Para ver la distinción entre separador y delimitador , pruebe:
string='var1_var2_'
Eso lo dividirá en var1y var2solo (sin elemento vacío adicional).
Entonces, para que sea similar a JavaScript split(), necesitarías un paso adicional:
string='var1_var2_var3'
IFS=_ # delimit on _
set -f # disable the glob part
temp=${string}_ # add an extra delimiter
array=($temp) # invoke the split+glob operator
(tenga en cuenta que dividiría un elemento vacío $stringen 1 (no 0 ), como JavaScript split()).
Para ver la pestaña de tratamientos especiales, recibir espacio y nueva línea, compare:
IFS=' '; string=' var1 var2 '
(donde consigues var1y var2) con
IFS='_'; string='_var1__var2__'
donde se obtiene: '', var1, '', var2, ''.
Tenga en cuenta que el zshshell no invoca ese operador split + glob implícitamente así, a menos que esté en sho kshemulación. Allí, debes invocarlo explícitamente. $=stringpara la parte dividida, $~stringpara la parte glob ( $=~stringpara ambos), y también tiene un operador dividido donde puede especificar el separador:
array=(${(s:_:)string})
o para preservar los elementos vacíos:
array=("${(@s:_:)string}")
Tenga en cuenta que existe spara dividir , no delimitar (también con $IFSuna no conformidad POSIX conocida de zsh). Es diferente de JavaScript split()en que una cadena vacía se divide en 0 (no 1) elemento.
Una diferencia notable con $IFS-splitting es que se ${(s:abc:)string}divide en la abccadena, mientras que con IFS=abc, se dividiría en a, bo c.
Con zshy ksh93, el tratamiento especial que recibe el espacio, la pestaña o la nueva línea se puede eliminar al duplicarlos $IFS.
Como nota histórica, el shell Bourne (el ancestro o los shell POSIX modernos) siempre despojó a los elementos vacíos. También tenía una serie de errores relacionados con la división y expansión de $ @ con valores no predeterminados de $IFS. Por ejemplo IFS=_; set -f; set -- $@, no sería equivalente a IFS=_; set -f; set -- $1 $2 $3....
División en expresiones regulares
Ahora, para algo más cercano a JavaScript split()que puede dividirse en expresiones regulares, necesitaría confiar en utilidades externas.
En el cofre de herramientas POSIX, awktiene un splitoperador que puede dividirse en expresiones regulares extendidas (que son más o menos un subconjunto de las expresiones regulares similares a Perl compatibles con JavaScript).
split() {
awk -v q="'" '
function quote(s) {
gsub(q, q "\\" q q, s)
return q s q
}
BEGIN {
n = split(ARGV[1], a, ARGV[2])
for (i = 1; i <= n; i++) printf " %s", quote(a[i])
exit
}' "$@"
}
string=a__b_+c
eval "array=($(split "$string" '[_+]+'))"
El zshshell tiene soporte incorporado para expresiones regulares compatibles con Perl (en su zsh/pcremódulo), pero usarlo para dividir una cadena, aunque es posible, es relativamente engorroso.
shellestás usando, con lobashque puedes hacerIFS='_' read -a array <<< "${string}"