Un shell es el intérprete de comandos para el sistema operativo. Bash es mi shell favorito, pero cada shell de Linux interpreta los comandos escritos por el usuario o el administrador del sistema en una forma que el sistema operativo puede usar. Cuando los resultados se devuelven al programa shell, los envía a STDOUT que, de forma predeterminada, los muestra en la terminal. Todos los shells con los que estoy familiarizado también son lenguajes de programación.
Las características como la finalización de pestañas, la recuperación y edición de la línea de comandos y los accesos directos como los alias contribuyen a su valor como un shell poderoso. Su modo de edición de línea de comandos predeterminado usa Emacs, pero una de mis características favoritas de Bash es que puedo cambiarlo al modo Vi para usar comandos de edición que ya son parte de mi memoria muscular.
Sin embargo, si piensas en Bash únicamente como un caparazón, te perderás gran parte de su verdadero poder. Mientras investigaba mi curso de autoaprendizaje de Linux de tres volúmenes (en el que se basa esta serie de artículos), aprendí cosas sobre Bash que nunca había sabido en más de 20 años de trabajo con Linux. Algunos de estos nuevos conocimientos se relacionan con su uso como lenguaje de programación. Bash es un poderoso lenguaje de programación, perfectamente diseñado para usar en la línea de comandos y en scripts de shell.
Esta serie de tres partes explora el uso de Bash como lenguaje de programación de interfaz de línea de comandos (CLI). Este primer artículo analiza un poco de programación simple de línea de comandos con Bash, variables y operadores de control. Los otros artículos exploran tipos de archivos Bash; operadores lógicos de cadena, numéricos y misceláneos que proporcionan lógica de control de flujo de ejecución; diferentes tipos de expansiones de caparazón; y el para , mientras y hasta bucles que permiten operaciones repetitivas. También verán algunos comandos que simplifican y respaldan el uso de estas herramientas.
La concha
Un shell es el intérprete de comandos para el sistema operativo. Bash es mi shell favorito, pero cada shell de Linux interpreta los comandos escritos por el usuario o el administrador del sistema en una forma que el sistema operativo puede usar. Cuando los resultados se devuelven al programa shell, los muestra en la terminal. Todos los shells con los que estoy familiarizado también son lenguajes de programación.
Bash significa Bourne Again Shell porque el shell Bash se basa en el shell Bourne más antiguo que fue escrito por Steven Bourne en 1977. Hay muchos otros shells disponibles, pero estos son los cuatro que encuentro con más frecuencia:
- csh: El shell C para programadores a los que les gusta la sintaxis del lenguaje C
- ksh: El shell Korn, escrito por David Korn y popular entre los usuarios de Unix
- tcsh: Una versión de csh con funciones más fáciles de usar
- zsh: El caparazón Z, que combina muchas características de otros caparazones populares
Todos los shells tienen comandos incorporados que complementan o reemplazan los proporcionados por las utilidades principales. Abra la página de manual del shell y busque la sección "INTEGRADORES" para ver los comandos que proporciona.
Cada shell tiene su propia personalidad y sintaxis. Algunos funcionarán mejor para usted que otros. He usado el shell C, el shell Korn y el shell Z. Todavía me gusta el caparazón Bash más que cualquiera de ellos. Use el que funcione mejor para usted, aunque eso puede requerir que pruebe algunos de los otros. Afortunadamente, es bastante fácil cambiar los caparazones.
Todos estos shells son lenguajes de programación, así como intérpretes de comandos. Aquí hay un recorrido rápido por algunas construcciones y herramientas de programación que son partes integrales de Bash.
Bash como lenguaje de programación
La mayoría de los administradores de sistemas han utilizado Bash para emitir comandos que suelen ser bastante simples y directos. Pero Bash puede ir más allá de ingresar comandos únicos, y muchos administradores de sistemas crean programas simples de línea de comandos para realizar una serie de tareas. Estos programas son herramientas comunes que pueden ahorrar tiempo y esfuerzo.
Mi objetivo al escribir programas CLI es ahorrar tiempo y esfuerzo (es decir, ser el administrador del sistema perezoso). Los programas CLI admiten esto al enumerar varios comandos en una secuencia específica que se ejecutan uno tras otro, por lo que no necesita observar el progreso de un comando y escribir el siguiente comando cuando finaliza el primero. Puede ir a hacer otras cosas y no tener que monitorear continuamente el progreso de cada comando.
¿Qué es "un programa"?
El Diccionario gratuito en línea de computación (FOLDOC) define un programa como:"Las instrucciones ejecutadas por una computadora, a diferencia del dispositivo físico en el que se ejecutan". WordNet de la Universidad de Princeton define un programa como:"...una secuencia de instrucciones que una computadora puede interpretar y ejecutar..." Wikipedia también tiene una buena entrada sobre programas de computadora.
Por lo tanto, un programa puede constar de una o más instrucciones que realizan una tarea relacionada específica. La instrucción de un programa de computadora también se denomina declaración de programa. Para los administradores de sistemas, un programa suele ser una secuencia de comandos de shell. Todos los shells disponibles para Linux, al menos aquellos con los que estoy familiarizado, tienen al menos una forma básica de capacidad de programación, y Bash, el shell predeterminado para la mayoría de las distribuciones de Linux, no es una excepción.
Si bien esta serie usa Bash (porque es tan omnipresente), si usa un shell diferente, los conceptos generales de programación serán los mismos, aunque las construcciones y la sintaxis pueden diferir un poco. Algunos shells pueden admitir algunas funciones que otros no, pero todos brindan alguna capacidad de programación. Los programas de shell se pueden almacenar en un archivo para uso repetido, o se pueden crear en la línea de comandos según sea necesario.
Programas CLI simples
Los programas de línea de comandos más simples son una o dos instrucciones de programa consecutivas, que pueden estar relacionadas o no, que se ingresan en la línea de comandos antes de Enter. se presiona la tecla. La segunda instrucción en un programa, si existe, podría depender de las acciones de la primera, pero no es necesario.
También hay un poco de puntuación sintáctica que debe establecerse claramente. Al ingresar un solo comando en la línea de comandos, al presionar Enter key termina el comando con un punto y coma implícito (; ). Cuando se usa en un programa de shell CLI ingresado como una sola línea en la línea de comando, se debe usar el punto y coma para terminar cada declaración y separarla de la siguiente. La última declaración en un programa de shell CLI puede usar un punto y coma explícito o implícito.
Alguna sintaxis básica
Los siguientes ejemplos aclararán esta sintaxis. Este programa consta de un solo comando con un terminador explícito:
[student@studentvm1 ~]$ echo "Hello world." ;
Hello world.
Puede que no parezca un gran programa, pero es el primer programa que encuentro con cada nuevo lenguaje de programación que aprendo. La sintaxis puede ser un poco diferente para cada idioma, pero el resultado es el mismo.
Ampliemos un poco este programa trivial pero omnipresente. Sus resultados serán diferentes a los míos porque he realizado otros experimentos, aunque es posible que solo tenga los directorios y archivos predeterminados que se crean en el directorio de inicio de la cuenta la primera vez que inicia sesión en una cuenta a través del escritorio de la GUI.
[student@studentvm1 ~]$ echo "My home directory." ; ls ;
My home directory.
chapter25 TestFile1.Linux dmesg2.txt Downloads newfile.txt softlink1 testdir6
chapter26 TestFile1.mac dmesg3.txt file005 Pictures Templates testdir
TestFile1 Desktop dmesg.txt link3 Public testdir Videos
TestFile1.dos dmesg1.txt Documents Music random.txt testdir1
Eso tiene un poco más de sentido. Los resultados están relacionados, pero las declaraciones de programa individuales son independientes entre sí. Tenga en cuenta que me gusta poner espacios antes y después del punto y coma porque hace que el código sea un poco más fácil de leer. Intente ese pequeño programa CLI nuevamente sin un punto y coma explícito al final:
[student@studentvm1 ~]$ echo "My home directory." ; ls
No hay diferencia en la salida.
Algo sobre variables
Como todos los lenguajes de programación, el shell Bash puede manejar variables. Una variable es un nombre simbólico que se refiere a una ubicación específica en la memoria que contiene algún tipo de valor. El valor de una variable es modificable, es decir, es variable.
Bash no escribe variables como C y lenguajes relacionados, definiéndolos como enteros, puntos flotantes o tipos de cadena. En Bash, todas las variables son cadenas. Una cadena que es un número entero se puede usar en la aritmética de números enteros, que es el único tipo de matemática que Bash es capaz de hacer. Si se requieren matemáticas más complejas, el bc El comando se puede usar en scripts y programas CLI.
A las variables se les asignan valores y se pueden usar para hacer referencia a esos valores en los programas y scripts CLI. El valor de una variable se establece usando su nombre pero no precedido por un $ señal. La tarea VAR=10 establece el valor de la variable VAR en 10. Para imprimir el valor de la variable, puede usar la sentencia echo $VAR . Comience con variables de texto (es decir, no numéricas).
Las variables de Bash pasan a formar parte del entorno de shell hasta que se desarman.
Consultar el valor inicial de una variable que no ha sido asignada; debe ser nulo. Luego asigne un valor a la variable e imprímalo para verificar su valor. Puede hacer todo esto en un solo programa CLI:
[student@studentvm1 ~]$ echo $MyVar ; MyVar="Hello World" ; echo $MyVar ;
Hello World
[student@studentvm1 ~]$
Nota:La sintaxis de la asignación de variables es muy estricta. No debe haber espacios a ambos lados del igual (= ) firmar en la declaración de asignación.
La línea vacía indica que el valor inicial de MyVar es nulo. Cambiar y establecer el valor de una variable se hace de la misma manera. Este ejemplo muestra tanto el valor original como el nuevo.
Como se mencionó, Bash puede realizar cálculos aritméticos de enteros, lo cual es útil para calcular una referencia a la ubicación de un elemento en una matriz o resolver problemas matemáticos simples. No es adecuado para la computación científica ni para nada que requiera decimales, como los cálculos financieros. Hay herramientas mucho mejores para ese tipo de cálculos.
He aquí un cálculo simple:
[student@studentvm1 ~]$ Var1="7" ; Var2="9" ; echo "Result = $((Var1*Var2))"
Result = 63
¿Qué sucede cuando realiza una operación matemática que da como resultado un número de coma flotante?
[student@studentvm1 ~]$ Var1="7" ; Var2="9" ; echo "Result = $((Var1/Var2))"
Result = 0
[student@studentvm1 ~]$ Var1="7" ; Var2="9" ; echo "Result = $((Var2/Var1))"
Result = 1
[student@studentvm1 ~]$
El resultado es el entero más cercano. Observe que el cálculo se realizó como parte del eco declaración. El cálculo se realiza antes del comando de eco adjunto debido al orden de precedencia de Bash. Para obtener más información, consulte la página de manual de Bash y busque "precedencia".
Operadores de control
Los operadores de control de shell son uno de los operadores sintácticos para crear fácilmente algunos programas de línea de comandos interesantes. La forma más simple de programa CLI es simplemente encadenar varios comandos en una secuencia en la línea de comando:
command1 ; command2 ; command3 ; command4 ; . . . ; etc. ;
Todos esos comandos se ejecutan sin problemas siempre que no se produzcan errores. Pero, ¿qué sucede cuando se produce un error? Puede anticipar y permitir errores usando el && integrado y || Operadores de control de bash. Estos dos operadores de control proporcionan cierto control de flujo y le permiten modificar la secuencia de ejecución del código. El punto y coma también se considera un operador de control Bash, al igual que el carácter de nueva línea.
El && El operador simplemente dice:"si el comando 1 tiene éxito, entonces ejecute el comando 2. Si el comando 1 falla por algún motivo, entonces el comando 2 se omite". Esa sintaxis se ve así:
command1 && command2
Ahora, mire algunos comandos que crearán un nuevo directorio y, si tiene éxito, lo convertirán en el directorio de trabajo actual (PWD). Asegúrese de que su directorio de inicio (~ ) es la PCD. Prueba esto primero en /root , un directorio al que no tienes acceso:
[student@studentvm1 ~]$ Dir=/root/testdir ; mkdir $Dir/ && cd $Dir
mkdir: cannot create directory '/root/testdir/': Permission denied
[student@studentvm1 ~]$
El error fue emitido por mkdir dominio. No recibió un error que indica que el archivo no se pudo crear porque la creación del directorio falló. El && El operador de control detectó el código de retorno distinto de cero, por lo que el toque se omitió el comando. Uso de && operador de control evita el toque comando se ejecute porque hubo un error al crear el directorio. Este tipo de control de flujo del programa de línea de comandos puede evitar que los errores se agraven y se conviertan en un verdadero lío. Pero es hora de complicarse un poco más.
El || El operador de control le permite agregar otra instrucción de programa que se ejecuta cuando la instrucción de programa inicial devuelve un código mayor que cero. La sintaxis básica se ve así:
command1 || command2
Esta sintaxis dice:"Si el comando1 falla, ejecute el comando2". Eso implica que si el comando 1 tiene éxito, el comando 2 se omite. Pruebe esto intentando crear un nuevo directorio:
[student@studentvm1 ~]$ Dir=/root/testdir ; mkdir $Dir || echo "$Dir was not created."
mkdir: cannot create directory '/root/testdir': Permission denied
/root/testdir was not created.
[student@studentvm1 ~]$
Esto es exactamente lo que esperarías. Debido a que no se pudo crear el nuevo directorio, el primer comando falló, lo que resultó en la ejecución del segundo comando.
La combinación de estos dos operadores proporciona lo mejor de ambos. La sintaxis del operador de control que usa algún control de flujo toma esta forma general cuando && y || Se utilizan operadores de control:
preceding commands ; command1 && command2 || command3 ; following commands
Esta sintaxis se puede establecer así:"Si comando1 sale con un código de retorno de 0, entonces ejecute comando2, de lo contrario, ejecute comando3". Pruébalo:
[student@studentvm1 ~]$ Dir=/root/testdir ; mkdir $Dir && cd $Dir || echo "$Dir was not created."
mkdir: cannot create directory '/root/testdir': Permission denied
/root/testdir was not created.
[student@studentvm1 ~]$
Ahora intente el último comando nuevamente usando su directorio de inicio en lugar de /root directorio. Tendrá permiso para crear este directorio:
[student@studentvm1 ~]$ Dir=~/testdir ; mkdir $Dir && cd $Dir || echo "$Dir was not created."
[student@studentvm1 testdir]$
La sintaxis del operador de control, como comando1 &&comando2 , funciona porque cada comando envía un código de retorno (RC) al shell que indica si se completó con éxito o si hubo algún tipo de falla durante la ejecución. Por convención, un RC de cero (0) indica éxito y cualquier número positivo indica algún tipo de falla. Algunas de las herramientas que usan los administradores de sistemas solo devuelven un uno (1) para indicar una falla, pero muchas usan otros códigos para indicar el tipo de falla que ocurrió.
La variable de shell Bash $? contiene el RC del último comando. Este RC se puede verificar muy fácilmente mediante un script, el siguiente comando en una lista de comandos o incluso el administrador del sistema directamente. Comience ejecutando un comando simple e inmediatamente verificando el RC. El RC siempre será para el último comando que se ejecutó antes de mirarlo.
[student@studentvm1 testdir]$ ll ; echo "RC = $?"
total 1264
drwxrwxr-x 2 student student 4096 Mar 2 08:21 chapter25
drwxrwxr-x 2 student student 4096 Mar 21 15:27 chapter26
-rwxr-xr-x 1 student student 92 Mar 20 15:53 TestFile1
<snip>
drwxrwxr-x. 2 student student 663552 Feb 21 14:12 testdir
drwxr-xr-x. 2 student student 4096 Dec 22 13:15 Videos
RC = 0
[student@studentvm1 testdir]$
El RC, en este caso, es cero, lo que significa que el comando se completó con éxito. Ahora pruebe el mismo comando en el directorio de inicio de root, un directorio para el que no tiene permisos:
[student@studentvm1 testdir]$ ll /root ; echo "RC = $?"
ls: cannot open directory '/root': Permission denied
RC = 2
[student@studentvm1 testdir]$
En este caso, el RC es dos; esto significa que se denegó el permiso para que un usuario no raíz acceda a un directorio al que no se le permite el acceso al usuario. Los operadores de control usan estos RC para permitirle alterar la secuencia de ejecución del programa.
Resumen
Este artículo analizó Bash como lenguaje de programación y exploró su sintaxis básica, así como algunas herramientas básicas. Mostró cómo imprimir datos en STDOUT y cómo usar variables y operadores de control. El siguiente artículo de esta serie analiza algunos de los muchos operadores lógicos de Bash que controlan el flujo de ejecución de instrucciones.