Esto funciona perfectamente en OSX
#!/bin/bash
chars=( {a..z} )
n=3
for ((i=0; i<n; i++))
do
echo "${chars[i]}"
done
Pero cuando lo ejecuto en Ubuntu, aparece el siguiente error.
ForLoopAlphabetTest.sh: 2: ForLoopAlphabetTest.sh: Syntax error: "(" unexpected
Parece que no puedo resolver el problema. ¿Alguna sugerencia?
Respuestas:
Presumiblemente, está ejecutando el script como:
En Ubuntu,
sh
está vinculado adash
; comodash
no tiene concepto de matrices, está obteniendo el error de sintaxis para(
.El script funciona perfectamente
bash
, por lo que estaría bien si lo estuviera ejecutando comobash
argumento:Ahora, tiene el
bash
shebang en el script, por lo que puede hacer que el script sea ejecutable (chmod u+x ForLoopAlphabetTest.sh
) y ejecutarlo como:o desde el directorio del script:
También tenga en cuenta que su script contiene expansión de llaves
{a..z}
yfor
construcción de estilo C :for (( ... ))
que tampoco son compatibles condash
; así que si su objetivo es la portabilidad, debe mirarsh
solo las sintaxis POSIX .fuente
/bin/sh
en cualquier sistema operativo tipo Unix, entonces no podrá usar matrices. Bash (y algunos otros shells) los han agregado porque son muy convenientes y no siempre se pueden reemplazar fácilmente con un código más portátil. Sin embargo, para su script en particular, puede hacerlo sin problemas y sin usar ninguna característica específica de bash. ¿Estás interesado en cómo hacer eso?sh
Su script utiliza tres características del shell Bash que no son provistas por todos los shells de estilo Bourne. Como dice heemayl , simplemente puede ejecutar ese script con en
bash
lugar desh
. Su línea hashbang en la parte superior (#!/bin/bash
) especificabash
pero solo es efectiva si ejecuta el script, como explicó heemayl . Si pasa el nombre del script ash
,sh
no llamará automáticamentebash
, sino que simplemente ejecutará el script. Esto se debe a que una vez que su script se está ejecutando, la línea hashbang no tiene ningún efecto .Su otra alternativa, si necesita escribir scripts totalmente portátiles que no dependan de las funciones de Bash, es cambiar su script para que funcione sin ellos. Las características de Bash que usa son:
( {a..z} )
, que asignachars
, crea una matriz y${chars[i]}
, que aparece en su bucle, se indexa en ella.{a..z}
se expande aa b c d e f g h i j k l m n o p q r s t u v w x y z
. Sin embargo, esta no es una característica universal (o estandarizada) de los shells de estilo Bourne, y Dash no lo admite.for
sintaxis -loop . Aunque se basa en la expansión aritmética , que no es específica de Bash (aunque algunos shells muy antiguos y no compatibles con POSIX tampoco lo tienen), elfor
bucle de estilo C es un Bash-ism y no es ampliamente portátil para otras conchasBash está ampliamente disponible, especialmente en sistemas GNU / Linux como Ubuntu, y (como ha visto) también está disponible en macOS y muchos otros sistemas. Teniendo en cuenta cuánto está usando las funciones específicas de Bash, es posible que solo desee usarlas, y simplemente asegúrese de estar usando Bash (o algún otro shell que admita las funciones que está usando) cuando ejecuta sus scripts.
Sin embargo, puede reemplazarlos con construcciones portátiles si lo desea. La matriz y el estilo C
for
bucle de son fáciles de reemplazar; Generar el rango de letras sin expansión de llaves (y sin codificarlas en su script) es la parte que es un poco complicada.Primero, aquí hay un script que imprime todas las letras latinas en minúsculas:
seq
comando genera secuencias numéricas.$(
)
realiza la sustitución de comandos , por lo que$(seq 97 122)
se reemplaza con la salida deseq 97 122
. Estos son los códigos de caracteres paraa
travész
.printf
comando puede convertir los códigos de caracteres en letras (p. Ej.,printf '\141'
Impresionesa
, seguidas de una nueva línea ), pero los códigos deben estar en octal , mientras queseq
solo se muestran en decimal . Así que he usadoprintf
dos veces: el internoprintf %o $i
convierte los números decimales (proporcionados porseq
) a octal, y se sustituye en elprintf
comando externo . (Aunque también es posible usar hexadecimal , no es más simple y parece ser menos portátil ).printf
interpreta\
seguido de un número octal como el carácter con ese código y\n
como una nueva línea. Pero el caparazón también se usa\
como un personaje de escape. Un\
frente$
impedirá$
a partir causando una expansión que se produzca (en este caso, la sustitución de comandos ), pero no quiero para evitar que, por lo que he escapado con otro\
; Ese es el motivo\\
. El segundo\
antesn
no necesita escapar porque, a diferencia\$
,\n
no tiene un significado especial para el shell en una cadena entre comillas dobles.'
) también son una parte importante de la sintaxis de comillas de shell, simplemente no las he usado en ese script.Esto es portátil para la mayoría de los sistemas tipo Unix y no depende de qué shell Bourne use. Sin embargo, algunos sistemas similares a Unix no se han
seq
instalado por defecto (tienden a usarjot
en su lugar, que no está instalado por defecto en la mayoría de los sistemas GNU / Linux). Puedes usar un bucle conexpr
o una sustitución aritmética para aumentar aún más la portabilidad, si necesita:Eso usa un
while
bucle con el[
comando para continuar haciendo bucles solo cuando$i
está dentro del rango.En lugar de imprimir todo el alfabeto, su script define una variable
n
e imprime las primeras$n
letras minúsculas. Aquí hay una versión de su script que no se basa en características específicas de Bash y funciona en Dash, pero requiereseq
:Ajustar el valor de los
n
cambios cuántas letras se imprimen, como en su secuencia de comandos.Aquí hay una versión que no requiere
seq
:Hay
$stop
uno más alto que el código de caracteres de la última letra que debe imprimirse, por lo que uso-lt
(menor que) en lugar de-le
(menor o igual) con el[
comando. (También habría funcionado para hacerstop=$((i + n - 1))
y usar[ $i -le $stop ]
).fuente