Es muy fácil de usar split()
en JavaScript para dividir una cadena en una matriz.
¿Qué pasa con el script de shell?
Digamos que quiero hacer esto:
$ script.sh var1_var2_var3
Cuando el usuario le da dicha cadena var1_var2_var3
al script.sh, dentro del script convertirá la cadena en una matriz como
array=( var1 var2 var3 )
for name in ${array[@]}; do
# some code
done
shell
shell-script
string
AGamePlayer
fuente
fuente
shell
estás usando, con lobash
que puedes hacerIFS='_' read -a array <<< "${string}"
perl
puede hacer eso también No es un caparazón "puro", pero es bastante común.Respuestas:
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 hacerlofor 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
$IFS
pará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-f
opción de deshabilitar (set -f
) o habilitar (set +f
) laglob
parte.También tenga en cuenta que si bien el
S
in$IFS
era originalmente (en el shell Bourne de donde$IFS
proviene) para el Sseparador, en los shells POSIX, los caracteres en$IFS
deberían verse como delimitadores o terminadores (ver a continuación un ejemplo).Entonces para dividir
_
:Para ver la distinción entre separador y delimitador , pruebe:
Eso lo dividirá en
var1
yvar2
solo (sin elemento vacío adicional).Entonces, para que sea similar a JavaScript
split()
, necesitarías un paso adicional:(tenga en cuenta que dividiría un elemento vacío
$string
en 1 (no 0 ), como JavaScriptsplit()
).Para ver la pestaña de tratamientos especiales, recibir espacio y nueva línea, compare:
(donde consigues
var1
yvar2
) condonde se obtiene:
''
,var1
,''
,var2
,''
.Tenga en cuenta que el
zsh
shell no invoca ese operador split + glob implícitamente así, a menos que esté ensh
oksh
emulación. Allí, debes invocarlo explícitamente.$=string
para la parte dividida,$~string
para la parte glob ($=~string
para ambos), y también tiene un operador dividido donde puede especificar el separador:o para preservar los elementos vacíos:
Tenga en cuenta que existe
s
para dividir , no delimitar (también con$IFS
una no conformidad POSIX conocida dezsh
). Es diferente de JavaScriptsplit()
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 laabc
cadena, mientras que conIFS=abc
, se dividiría ena
,b
oc
.Con
zsh
yksh93
, 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 ejemploIFS=_; set -f; set -- $@
, no sería equivalente aIFS=_; 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,
awk
tiene unsplit
operador 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).El
zsh
shell tiene soporte incorporado para expresiones regulares compatibles con Perl (en suzsh/pcre
módulo), pero usarlo para dividir una cadena, aunque es posible, es relativamente engorroso.fuente
$PATH
en:
) por el contrario, generalmente se desea conservar los elementos vacíos. Tenga en cuenta que en el shell Bourne, todos los personajes estaban recibiendo el tratamiento especial, loksh
cambiaron para que solo los en blanco (solo el espacio, la pestaña y la nueva línea) se trataran especialmente.zsh
tratamiento con cadena que contiene 2 o más caracteres${(s:string:)var}
? Si se agrega, puedo eliminar mi respuesta :)S
significa Separador , no delimitador . Al menos, eso es lo que dice el manual de mi bash.$IFS
proviene del shell Bourne donde estaba el separador , ksh cambió el comportamiento sin cambiar el nombre. Menciono eso para enfatizar quesplit+glob
(excepto en zsh o pdksh) ya no se divide simplemente.Sí, utilícelo
IFS
y configúrelo en_
. Luego, useread -a
para almacenar en una matriz (-r
desactiva la expansión de barra invertida). Tenga en cuenta que esto es específico de bash; ksh y zsh tienen características similares con una sintaxis ligeramente diferente, y sh simple no tiene variables de matriz en absoluto.De
man bash
:Tenga en cuenta que se
read
detiene en la primera línea nueva. Pase-d ''
aread
para evitar eso, pero en ese caso, habrá una nueva línea adicional al final debido al<<<
operador. Puedes eliminarlo manualmente:fuente
$r
que no contiene caracteres de nueva línea o barras invertidas. También tenga en cuenta que solo funcionará en versiones recientes delbash
shell.bash
,read -a
se introdujo en bash 4, ¿verdad?<<<
se agregó recientemente,bash
pero parece que ha estado allí desde 2.05b (2002).read -a
es incluso más viejo que eso.<<<
provienezsh
y es compatible conksh93
(y mksh y yash) también, peroread -a
es específico de bash (está-A
en ksh93, yash y zsh).