Los scripts de shell son ampliamente utilizados en el mundo UNIX. Son excelentes para acelerar tareas repetitivas y simplificar la lógica de ejecución compleja. Pueden ser tan simples como un conjunto de comandos, o pueden organizar tareas complejas. En este tutorial, aprenderemos más sobre el lenguaje de script Bash escribiendo un script de ejemplo paso a paso.
Una de las mejores maneras de aprender sobre un nuevo idioma es con un ejemplo. Vamos a empezar con uno.
El problema de Fizz-Buzz es muy simple. Se hizo famoso después de que un programador, llamado Imran, lo utilizara como prueba de entrevista. Resulta que el 90-99.5% de los candidatos para un trabajo de programación simplemente no pueden escribir el programa más simple. Imran tomó este sencillo juego de Fizz-Buzz y pidió a los candidatos que lo resolvieran. Muchos siguieron el ejemplo de Imran y, hoy, es una de las preguntas más frecuentes para un trabajo de programación. Si está contratando y necesita una forma de filtrar a través del 90% de los candidatos, este es un gran problema para presentar.
Estas son las reglas:
Eso es todo al respecto. Estoy seguro de que la mayoría de ustedes ya puede visualizar los dos o tres Si
Declaraciones para resolver esto. Vamos a trabajar a través de esto usando el lenguaje de scripts Bash.
Un shebang se refiere a la combinación de los caracteres hash y de exclamación: #!
. El cargador de programas buscará un shebang en la primera línea del script y usará el intérprete especificado en él. Un shebang consiste en la siguiente sintaxis: #!intérprete [parámetros]
. El intérprete es el programa que se utiliza para interpretar nuestro idioma. Para bash scripting, eso sería / bin / bash
. Por ejemplo, si desea crear un script en PHP y ejecutarlo en la consola, probablemente quiera usar / usr / bin / php
(o la ruta al ejecutable de PHP en su máquina) como intérprete.
#! / usr / bin / phpSí, eso realmente funcionará! ¿No es simple? Solo asegúrese de hacer su archivo ejecutable primero. Una vez que lo haga, esta secuencia de comandos generará su información PHP como cabría esperar..
Propina: Para asegurarse de que su script funcione en tantos sistemas como sea posible, puede usar
/ bin / env
en el shebang. Como tal, en lugar de/ bin / bash
, podrías usar/ bin / env bash
, que funcionará en sistemas donde el ejecutable de bash no está dentro/compartimiento
.
Salida de texto
La salida de una secuencia de comandos será igual a, como es de esperar, lo que se obtenga de su comando. Sin embargo, si queremos explícitamente escribir algo en la pantalla, podemos usar
eco
.#! / bin / bash echo "Hello World"Al ejecutar este script se imprimirá "Hello World" en la consola..
csaba @ csaba ~ $ ./helloWorld.sh Hola mundo csaba @ csaba ~ $
Introduciendo Variables
Al igual que con cualquier lenguaje de programación, al escribir scripts de shell, puede utilizar variables.
#! / bin / bash message = "Hello World" echo $ messageEste código produce exactamente el mismo mensaje "Hello World". Como puede ver, para asignar un valor a una variable, simplemente escriba su nombre - excluya el signo de dólar que está delante de ella. Además, ten cuidado con los espacios; no puede haber espacios entre el nombre de la variable y el signo igual. Asi que
mensaje = "Hola"
en lugar demensaje = 'Hola'
Cuando desee utilizar una variable, puede tomar el valor de ella tal como lo hicimos en el
eco
mando. Preponer unPS
al nombre de la variable devolverá su valor.Propina: No se requieren puntos y coma en las secuencias de comandos de bash. Puede usarlos en la mayoría de los casos, pero tenga cuidado: pueden tener un significado diferente al que usted espera..
Imprimiendo los números entre 1 y 100
Continuando con nuestro proyecto de demostración, necesitamos recorrer todos los números entre 1 y 100. Para esto, necesitamos usar un
para
lazo.#! / bin / bash para el número en 1… 100; hacer eco $ numero hechoHay varias cosas nuevas que vale la pena destacar en este ejemplo, que por cierto imprime todos los números del 1 al 100, un número a la vez..
para
La sintaxis en Bash es: para VARIABLE en RANGO; hacer el comando hecho
.1… 100
en un rango en nuestro ejemplo. También se utilizan en otros contextos, que revisaremos en breve..hacer
y para
En realidad son dos comandos separados. Si desea colocar dos comandos en una sola línea, deberá separarlos de alguna manera. Una forma es usar el punto y coma. Alternativamente, puede escribir el código sin un punto y coma moviendo hacer
a la siguiente linea.#! / bin / bash para el número en 1… 100 do echo $ número finalizado
Ahora que sabemos cómo imprimir todos los números entre 1 y 100, es hora de tomar nuestra primera decisión.
#! / bin / bash para el número en 1… 100; hacer si [$ ((número% 3)) -eq 0]; luego echo "Fizz" más echo $ número fi hecho
Este ejemplo mostrará "Fizz" para los números divisibles entre 3. Una vez más, tenemos que lidiar con un poco de nueva sintaxis. Vamos a tomarlos uno por uno.
si ... entonces ... otra cosa ... fi
- Esta es la sintaxis clásica para una Si
Declaración en Bash. Por supuesto, el más
La parte es opcional, pero es necesaria para nuestra lógica en este caso..si COMMAND-RETURN-VALUE; entonces…
- Si
se ejecutará si el valor de retorno del comando es cero. Sí, la lógica en Bash se basa en cero, lo que significa que los comandos que se ejecutan con éxito salen con un código de 0. Si algo sale mal, por otro lado, se devolverá un entero positivo. Para simplificar las cosas: cualquier otra cosa que no sea 0 es considerada falso
.$ ((número% 3))
devolverá el valor restante de dividir la variable, número
, por 3. Tenga en cuenta que no usamos PS
Dentro del paréntesis, sólo delante de ellos..Quizás se esté preguntando dónde está el comando en nuestro ejemplo. ¿No hay solo un corchete con una expresión extraña en él? Bueno, resulta que El
Es en realidad un comando ejecutable. Para jugar con esto, pruebe los siguientes comandos en su consola.
csaba @ csaba ~ $ el cual [/ usr / bin / [csaba @ csaba ~ $ [0 -eq 1] csaba @ csaba ~ $ echo $? 1 csaba @ csaba ~ $ [0 -eq 0] csaba @ csaba ~ $ echo $? 0
Propina: El valor de salida de un comando siempre se devuelve a la variable,
?
(signo de interrogación). Se sobrescribe después de la ejecución de cada nuevo comando..
Lo estamos haciendo bien hasta ahora. Tenemos "Fizz"; Ahora vamos a hacer la parte "Buzz".
#! / bin / bash para el número en 1… 100; hacer si [$ ((número% 3)) -eq 0]; luego haga eco en elif "Fizz" [$ ((número% 5)) -eq 0]; luego echo "Buzz" más echo $ número fi hecho
Anteriormente, hemos introducido otra condición para la divisibilidad por 5: la elif
declaración. Esto, por supuesto, se traduce en si no, y se ejecutará si el comando siguiente vuelve cierto
(o 0
). Como se puede observar, las declaraciones condicionales dentro de []
Usualmente son evaluados con la ayuda de parámetros, tales como -eq
, que significa "iguales".
Por la sintaxis,
arg1 OP arg2
,OP
es uno de-eq
,-Nebraska
,-es
,-le
,-gt
, o-ge
. Estos operadores binarios aritméticos vuelven.cierto
Siarg1
es igual a, no igual a, menor que, menor o igual que, mayor que, o mayor o igual quearg2
, respectivamente.arg1
yarg2
pueden ser enteros positivos o negativos. - Manual de Bash
Cuando intente comparar cadenas, puede utilizar el conocido ==
Signo, o incluso un solo signo igual hará. !=
devoluciones cierto
cuando las cuerdas son diferentes.
Hasta ahora, el código se ejecuta, pero la lógica no es correcta. Cuando el número es divisible entre 3 y 5, nuestra lógica solo hará eco en "Fizz". Modifiquemos nuestro Código para satisfacer el último requisito de FizzBuzz..
#! / bin / bash para el número en 1… 100; hacer si [$ ((número% 3)) -eq 0]; luego output = "Fizz" fi si [$ ((número% 5)) -eq 0]; luego output = "$ output Buzz" fi si [-z $ output]; luego echo $ número o echo $ salida; fi hecho
Una vez más, hemos tenido que hacer un puñado de cambios. La más notable es la introducción de una variable, y luego la concatenación de "Buzz" a ella, si es necesario. Las cadenas en bash normalmente se definen entre comillas dobles ("). Las comillas simples también se pueden usar, pero para una concatenación más fácil, las dobles son la mejor opción. Dentro de estas comillas dobles, puede hacer referencia a las variables: algún texto $ variable otro texto
"reemplazará $ variable
con sus contenidos. Cuando desee concatenar variables con cadenas sin espacios entre ellas, puede preferir poner el nombre de la variable entre llaves. En la mayoría de los casos, como PHP, no está obligado a hacerlo, pero ayuda mucho cuando se trata de la legibilidad del código..
Propina: No puedes comparar cuerdas vacías. Eso devolvería un parámetro faltante.
Porque los argumentos dentro []
son tratados como parámetros, por "["
, deben ser diferentes de una cadena vacía. Entonces esta expresión, aunque lógica, producirá un error: [$ output! = ""]
. Por eso hemos usado [-z $ salida]
, que devuelve cierto
si la cadena tiene una longitud de cero.
Una forma de mejorar nuestro ejemplo es extraer en funciones la expresión matemática del Si
declaraciones, como así:
La función #! / bin / bash es DivisibleBy return $ (($ 1% $ 2)) para el número en 1 ... 100; do si es divisible por $ número 3; luego output = "Fizz" fi si es DivisibleBy $ número 5; luego output = "$ output Buzz" fi si [-z $ output]; luego echo $ número o echo $ salida; fi hecho
Tomamos las expresiones comparando el resto con cero y las movimos a una función. Aún más, eliminamos la comparación con cero, porque cero significa verdadero para nosotros. Solo tenemos que devolver el valor de la expresión matemática - muy simple!
Propina: La definición de una función debe preceder a su llamada..
En Bash, puedes definir un método como función func_name comandos;
. Opcionalmente, hay una segunda sintaxis para declarar funciones: func_name () comandos;
. Entonces, podemos soltar la cuerda., función
y añadir "()"
después de su nombre. Personalmente prefiero esta opción, como se ejemplifica en el ejemplo anterior. Es más explícito y se asemeja a los lenguajes de programación tradicionales..
No es necesario especificar los parámetros para una función en Bash. El envío de parámetros a una función se realiza simplemente enumerando sobre ellos después de la llamada a la función separada por espacios en blanco. No coloque comas ni paréntesis en la llamada de función, no funcionará.
Los parámetros recibidos se asignan automáticamente a las variables por número. El primer parámetro va a $ 1
, el segundo para $ 2
, y así. La variable especial, $ 0
refiere el nombre del archivo del script actual.
#! / bin / bash function exampleFunc echo $ 1 echo $ 0 IFS = "X" echo "$ @" echo "$ *" exampleFunc "one" "two" "three"
Este código producirá la siguiente salida:
csaba @ csaba ~ $ ./parametersExamples.sh one ./parametersExamples.sh one two thre oneXtwoXthre
Analicemos la fuente, línea por línea..
PS
. Representa todos los parámetros como una sola palabra, exactamente como se especifica en la llamada a la función.PS
. Representa todos los parámetros, tomados uno por uno y concatenados con la primera letra de la variable IFS. Por eso el resultado es. oneXtwoXthre
.Como señalé anteriormente, las funciones en Bash solo pueden devolver enteros. Como tal, escribiendo devuelve "una cadena"
sería un código inválido Aún así, en muchas situaciones, necesita más que solo un cero o uno. Podemos refactorizar nuestro ejemplo de FizzBuzz para que, en el para
declaración, sólo haremos una llamada de función.
La función #! / bin / bash isDivisibleBy return $ (($ 1% $ 2)) fizzOrBuzz if isDivisibleBy $ 1 3; luego output = "Fizz" fi si es DivisibleBy $ 1 5; luego output = "$ output Buzz" fi si [-z $ output]; luego echo $ 1 en caso contrario echo $ salida; fi para el número en 1 ... 100; hacer fizzOrBuzz $ número hecho
Bueno, este es el primer paso. Acabamos de extraer todo el código en una función, llamada FizzOrBuzz
, y luego reemplazado $ numero
con $ 1
. Sin embargo, todos los resultados se producen en el FizzOrBuzz
función. Queremos salir de la para
bucle con un eco
instrucción, de modo que podamos anteponer cada línea con otra cadena. Tenemos que capturar el FizzOrBuzz
salida de la función.
# […] Para el número en 1… 100; do echo "-'fizzOrBuzz $ number '" fizzBuzzer = $ (fizzOrBuzz $ number) echo "- $ fizzBuzzer" hecho
Hemos actualizado nuestro para
bucle sólo un poco (no hay otros cambios). Ahora hemos repetido todo dos veces de dos maneras diferentes para ejemplificar las diferencias entre las dos soluciones al mismo problema.
La primera solución para capturar la salida de una función u otro comando es usar backticks. En el 99% de los casos, esto funcionará bien. Simplemente puede hacer referencia a una variable dentro de backticks por sus nombres, como hicimos con $ numero
. Las primeras líneas de la salida ahora deberían verse como:
csaba @ csaba ~ / Personal / Programming / NetTuts / Lo básico de BASH Scripting / Sources $ ./fizzBuzz.sh -1 -1 -2 -2 -Fizz -Fizz -4 -4 -Buzz -Buzz -Fizz -Fizz -7 -7
Como puedes ver, todo está duplicado. Misma salida.
Para la segunda solución, hemos elegido asignar primero el valor de retorno a una variable. En esa tarea, usamos PS
, el cual, en este caso, divide el script, ejecuta el código y devuelve su salida.
¿Recuerdas que usamos punto y coma aquí y allá? Se pueden utilizar para ejecutar varios comandos escritos en la misma línea. Si los separas por punto y coma, simplemente se ejecutarán.
Un caso más sofisticado es usar &&
entre dos órdenes. Sí, eso es un AND lógico; significa que el segundo comando se ejecutará solo si el primero devuelve cierto
(sale con 0). Esto es útil; podemos simplificar el Si
declaraciones en estos taquigrafes:
#! / bin / bash function isDivisibleBy return $ (($ 1% $ 2)) function fizzOrBuzz isDivisibleBy $ 1 3 && output = "Fizz" isDivisibleBy $ 1 5 && output = "$ output Buzz" si [-z $ output ]; luego echo $ 1 en caso contrario echo $ salida; fi para el número en 1 ... 100; hacer eco "-'fizzOrBuzz $ number '" hecho
Como nuestra funcion, isDivisibleBy
devuelve un valor de retorno adecuado, entonces podemos usar &&
para establecer la variable que queremos. Que hay despues &&
será ejecutado sólo si la condición es cierto
. De la misma manera, podemos utilizar ||
(carácter de doble canalización) como un OR lógico. Aquí hay un ejemplo rápido a continuación.
csaba @ csaba ~ $ echo "bubu" || echo "bibi" bubu csaba @ csaba ~ $ echo false || echo "bibi" false csaba @ csaba ~ $
Así que eso lo hace para este tutorial! Espero que hayas aprendido algunos consejos y técnicas nuevas para escribir tus propios scripts de Bash. Gracias por leer y estad atentos para artículos más avanzados sobre este tema..