Lenguaje de comandos de shell. Conceptos básicos de programación de shell

    Los sistemas operativos de la familia Linux, así como cualquier otro sistema operativo, requieren la presencia de una interfaz de interacción entre los componentes del sistema informático y el usuario final, es decir, la presencia de un nivel de software que proporciona entrada de comandos. y parámetros para obtener los resultados deseados. Este nivel de programa se llama "caparazón" o, en inglés - caparazón.

¿Qué es una concha?

Shell de comando ( caparazón) proporciona interacción entre el usuario y el entorno del sistema operativo Linux. Es un producto de software especializado que asegura la ejecución de comandos y la obtención de los resultados de su ejecución o, en pocas palabras, un shell es un programa que está diseñado para asegurar la ejecución de otros programas a petición del usuario. Un ejemplo de shell podría ser, por ejemplo, un intérprete de comandos. comando.com sistema operativo MS DOS o shell intento Sistemas operativos Unix/Linux.

Todos los shells tienen funciones y propiedades similares, de acuerdo con su objetivo principal: ejecutar comandos del usuario y mostrar los resultados de su ejecución:

Interpretación de la línea de comando.

Acceso a comandos y resultados de su ejecución.

Soporte para variables, caracteres especiales y palabras reservadas.

Procesamiento de archivos, operaciones estándar de entrada y salida.

Implementación de un lenguaje de programación de shell especial.

    Para los sistemas operativos de la familia Unix / Linux, es posible utilizar varios shells diferentes que difieren en propiedades y métodos de interacción con el sistema. Las conchas más comunes son

sh- caparazón Bourne, shell clásico para sistema operativo Unix

intento caparazón Bourne otra vez(GNU Bourne-Again SHell). Quizás el shell más común en este momento en el entorno del sistema operativo Linux.

ksh- caparazón Korn, diseñado como un desarrollo de shell Bourne con historial de línea de comandos y la capacidad de editar comandos.

csh- caparazón do, utilizando la sintaxis de un lenguaje de programación popular. do

tcsh- versión shell do con edición interactiva de línea de comando.

Se pueden instalar varios shells diferentes en el sistema y cada usuario puede usar su propio shell predeterminado. Todo esto, por supuesto, se hace de forma automática durante el proceso de descarga y registro del usuario.

    Durante el proceso de carga de los sistemas operativos de la familia Linux, después de cargar el kernel del sistema, el sistema cambia al modo interactivo, el modo de interacción entre el usuario y el sistema operativo. En Linux, el primer proceso que se inicia durante el arranque es el programa init. inicio, que lee el contenido del archivo de configuración /etc/inittab, determina la lista y características de los terminales disponibles en el sistema y llama al programa de inicio de sesión interactivo getty, que le solicita que ingrese su nombre de usuario. Después de ingresar el nombre de usuario y la contraseña, el programa getty llama al programa acceso, que verifica la validez de la cuenta, navega al directorio de inicio del usuario y pasa el control al programa de inicio inicial de la sesión, que normalmente es el programa shell del usuario, cuyo tipo específico está determinado por el contenido del archivo. /etc/contraseña para esta cuenta. Por ejemplo:

usuario1:x:508:511::/home/usuario1:/bin/sh
interbase:x:510:511::/home/interbase:/bin/csh
apb:x:511:513:apb:/home/apb:/bin/bash

Como se puede ver en el contenido del archivo. /etc/contraseña, para el usuario usuario1 el shell será lanzado sh(Bourne shell), para usuario interbase- caparazón csh(C shell) y para el usuario orden de busca y captura- caparazón intento(Bourne otra vez) Después de que se inicia el shell, se muestra un símbolo del sistema en la pantalla (generalmente en forma de signo de dólar $ si el trabajo se realiza en el contexto de una cuenta de usuario normal, o libra # , si el shell se utiliza con una cuenta de usuario root ( raíz).

Al salir del shell, el núcleo del sistema devuelve el control al programa. inicio, que reinicia el proceso de inicio de sesión y muestra un mensaje de nombre de usuario en el terminal. Salir del shell se puede hacer de dos maneras:

A través del equipo salida realizado por el usuario

Cuando un proceso de shell recibe una señal matar, enviado por el kernel, por ejemplo cuando se reinicia el sistema.

Interpretación de la línea de comando.

    La entrada del usuario en respuesta a un mensaje de shell generalmente se llama línea de comando o equipo. Un comando de Linux es una cadena de caracteres del nombre del comando y los argumentos, separados por espacios. Los argumentos proporcionan al comando parámetros adicionales que determinan su comportamiento. Se utiliza con mayor frecuencia como argumento. opciones Y nombres archivos y directorios. Por ejemplo, línea de comando

ls -l archivo01 archivo02

Contiene el comando ls, la opción -l y dos nombres de archivo archivo01 archivo02.

Cuando se utilizan varias opciones, se pueden combinar. Por ejemplo, las siguientes opciones de comando son idénticas:

ls-l-d
ls-ld

Los comandos que forman parte del shell se llaman incorporado. Dichos comandos incluyen, por ejemplo, cd, if, case, etc. Naturalmente, los comandos integrados pueden diferir para diferentes opciones de shell. Además de los comandos integrados, es posible utilizar módulos de programa, que son archivos ejecutables independientes o archivos guiones o escenarios- archivos de texto ordinarios que contienen líneas ejecutadas secuencialmente con comandos de shell. Algunos scripts (scripts) pueden ser ejecutados por procesos de Linux, como el programador de tareas. cron. El programador de tareas suele estar diseñado para realizar automáticamente tareas de administración del sistema según una programación. Tareas cron Son comandos o scripts y se ejecutan automáticamente, sin ninguna intervención humana, y pueden ejecutarse en el contexto de diferentes cuentas de usuario. En el caso de que la tarea del programador implique la ejecución de un script, surge el problema de elegir un shell que debe iniciarse como proceso hijo. cron para procesar comandos desde un archivo de script; después de todo, el shell puede ser cualquiera y la sintaxis de un script, por regla general, requiere el uso de un shell específico para el que está escrito. Para eliminar este problema, en los sistemas operativos Linux se acostumbra indicar en la primera línea del script el tipo de shell requerido para su ejecución, en el formulario:

#!/bin/bash- para concha intento

#!/bin/sh- para concha sh

Firmar # es una señal de un comentario y los caracteres que le siguen no se interpretan como un comando. Esta técnica le permite especificar explícitamente qué shell debe usarse para procesar el contenido de los archivos posteriores. Si el script no contiene una entrada que defina explícitamente el shell requerido, se utilizarán las configuraciones de la cuenta en cuyo contexto se ejecuta el script. En este caso, es posible que un script escrito para el shell, por ejemplo, tch se pasará al shell para su ejecución intento, lo que hará imposible su ejecución.

Al ejecutar comandos o scripts, utilice variables de entorno(en Inglés - ambiente, cuyos valores caracterizan el entorno de software en el que se ejecutan los comandos. Dichas variables pueden contener configuraciones generales del sistema, parámetros gráficos o del shell de comandos, rutas de archivos ejecutables, etc. Los valores de las variables de entorno se establecen a nivel del sistema (para todos los usuarios) y a nivel de usuario específico. Para configurar variables de entorno a nivel del sistema, se utiliza el contenido de los archivos:

/etc/perfil- establece variables sólo para shells de comandos. Puede ejecutar cualquier script en shells compatibles con el shell Bourne.

/etc/bash.bashrc- establece variables sólo para shells interactivos. También ejecuta scripts bash.

/etc/entorno- utilizado por el módulo PAM-env. Sólo se pueden especificar pares en este archivo. nombre=valor.

Cada uno de estos archivos tiene su propia aplicación, por lo que deberás elegir cuidadosamente aquella que se adapte a tus propósitos. Por ejemplo, si necesita agregar un directorio personalizado ~/contenedor en una variable CAMINO para todos los usuarios, coloque el siguiente código en uno de los archivos de inicialización del entorno del sistema (/etc/profile o /etc/bash.bashrc):

# Si el ID de usuario es mayor o igual a 1000 y hay un directorio ~/bin y

# no se ha agregado previamente a la variable PATH,

# exportar ~/bin a $PATH.

Si [[ $UID -ge 1000 && -d $HOME/bin && -z $(echo $PATH | grep -o $HOME/bin)

Exportar RUTA=$HOME/bin:$(RUTA)

Normalmente, en los sistemas operativos Linux, se utiliza un ID de usuario inferior a 1000 o inferior a 500 para las cuentas de servicio. En este ejemplo, la variable de entorno se configurará para todos los usuarios locales del sistema con un ID de 1000 o mayor.

Si necesita cambiar el entorno de un usuario específico, modifique el contenido del entorno del usuario:

- ~/.bash_profile, ~/.bash_login etc. - archivos de inicialización de shell desde el directorio de inicio del usuario.

- ~/.perfil- archivo de inicialización del perfil de usuario. Utilizado por muchos shells para definir variables de entorno.

~/.pam_environment- un análogo personalizado del archivo /etc/environment, que utiliza el módulo PAM-env.

Por ejemplo, para agregar el directorio de usuario ~/bin a la ruta de búsqueda de archivos ejecutables especificada por la variable CAMINO, por ejemplo, a un archivo ~/.perfil pon la linea:

exportar RUTA="$(RUTA):/home/usuario/bin"

Para establecer variables de entorno para aplicaciones gráficas, se utiliza el contenido de los archivos de configuración del entorno gráfico del usuario. ~/.xinitrc

Más a menudo, los valores de las variables de entorno se establecen para la sesión del usuario actual. Por ejemplo, para agregar un directorio personalizado ~/contenedor en la ruta de búsqueda de archivos ejecutables:

exportar RUTA=~/bin:$RUTA

Nuevo valor de variable CAMINO solo durará hasta que finalice la sesión del usuario actual.

Para ver el valor de una variable, puede utilizar el comando eco $variable, Por ejemplo:

eco $ RUTA

Actualmente, el shell más común, como se mencionó anteriormente, es intento. Esto se debe principalmente al hecho de que el caparazón intento es sh- un shell de comandos compatible, que agrega funciones útiles del shell Korn ( ksh) y shell C ( csh). Caparazón intento Puede ejecutar la mayoría de los scripts escritos en un lenguaje de programación Shell sin ninguna modificación. sh e intenta acercarse lo más posible al estándar POSIX, lo que supuso muchas mejoras, tanto para la programación como para el uso interactivo. En implementación moderna intento hay un modo de edición de línea de comandos, tamaño ilimitado del historial de comandos, herramientas de administración de tareas, la capacidad de usar alias, una lista extensa de comandos integrados, funciones del shell de comandos, etc. Generalmente, intento se adapta mejor a las necesidades del usuario medio, lo que lo ha convertido en el más utilizado en el entorno Linux.

Al iniciar intento sin parámetros de línea de comando, el shell se inicia en modo interactivo y muestra un símbolo del sistema en la pantalla. Un shell interactivo normalmente lee datos del terminal del usuario y escribe datos en el mismo terminal, siendo el dispositivo de entrada estándar el teclado y el dispositivo de salida estándar la pantalla. El usuario ingresa comandos en el teclado y el resultado de su ejecución se muestra en la pantalla.

Cualquier sistema operativo universal tiene que jugar mucho con el usuario y sus propias tareas. Sólo una pequeña parte de esta actividad puede programarse de una vez por todas en el kernel. La mayor parte de la lógica para gestionar las tareas y el sistema en sí debe estar disponible para el administrador en forma de proyecto; de lo contrario, simplemente no podrá comprender lo que está sucediendo en el sistema y mucho menos cambiarlo. Vale la pena echar un vistazo más de cerca a la herramienta utilizada en UNIX para configurar el algoritmo para muchas partes del sistema: el intérprete de comandos, caparazón . Resulta que el shell funciona bien no sólo en el diálogo con el usuario, sino también en cómo intérprete de guión, y como medios para organizar la interacción entre tareas en el sistema.

Comencemos con el hecho de que el caparazón está completo. lenguaje de programación, y, como muchos intérpretes, de un nivel bastante alto. Si la tarea es única (no hay requisitos de velocidad, compatibilidad y portabilidad) y bastante abstracta (no hay conexión con una estructura de datos compleja específica), lo más probable es que se pueda resolver. escribiendo un script de comando- programa de shell.

Por otro lado, uno no puede limitarse a la completitud algorítmica al resolver problemas en un sistema. Por ejemplo, la máquina de Turing [9] es extremadamente simple y algorítmicamente completa, pero a pocos se les ocurriría organizar un diálogo con el usuario o controlar el propio sistema operativo basándose en su modelo. Aquí conviene recordar que el shell también es un ejecutor de comandos: se comunica fácilmente con UNIX y utilidades. Esto significa que al complementarlo con un mecanismo para la interacción controlada de comandos con el sistema y entre sí, obtendremos un buen integrador (o shell, que, de hecho, es la traducción de la palabra caparazón).

La mejor parte es que dicho shell programable no irá mucho más allá del alcance de Y: si, como legado de la encarnación interactiva del shell, podemos recurrir fácilmente a la solución de la subtarea para cualquier Utilidad UNIX, no es necesario duplicarla en el lenguaje y solo quedarán abstracciones algorítmicas y de coordinación.

Guión

Antes de considerar las capacidades del caparazón desde dos ángulos, resolvamos esta dificultad. Digamos que escribimos un programa en el lenguaje de algún intérprete, por ejemplo /bin/sh, y lo escribimos en un archivo determinado, por ejemplo /home/george/myscript (si /home/george es el directorio actual, puede usar una ruta más corta: myscript). ¿Cómo puedo ejecutar este script ahora? De man sh sabemos que para hacer esto podemos ejecutar intérprete de comandos con el parámetro - nombre de archivo:

$ cat myscript echo "¡Hola, George!" $ /bin/sh myscript ¡Hola, George!

¿Es posible prescindir del nombre del programa que interpreta el guión? En términos generales, no: UNIX tiene muchos intérpretes diferentes con diferentes sintaxis, por ejemplo el procesador de textos. awk, transmisión editor de texto sed, universal lenguajes de programación Python y Perl y mucho más. Todos estos idiomas tienen la capacidad de insertar comentarios de línea en el texto del script, que comienzan con el carácter "#" y terminan al final de la línea. Por lo tanto, si un guión comienza con los caracteres "#!", cualquiera de estos intérpretes ignorará toda la primera línea como comentario. El sistema, al ver "#!" al principio del archivo, entiende que se trata de un script. Desde el tercer carácter hasta el final de la línea, lee el nombre del programa al que envía este archivo para su ejecución. Esto significa que si la primera línea en /home/george/myscript es #!/bin/sh , puedes convertirla en ejecutable de forma segura (establece el bit de uso) y ejecutarla:

$ chmod +x myscript $ cat myscript #!/bin/sh echo "¡Hola, $1!" $ ./myscript George ¡Hola, George!

Estrictamente hablando, después de "#!" puede ser cualquier cosa, por ejemplo el nombre del programa que escribimos con algunos parámetros requeridos; UNIX lo iniciará y se lo pasará como opciones de línea de comando parámetros requeridos (si los hay), luego el nombre del script y todo lo que viene después (en nuestro ejemplo, George). Si después de "#!" habrá un archivo inexistente, el sistema emitirá mensaje de error:

$ cat myscript #!/bad/sh echo "¡Hola, $1!" $ ./myscript ./myscript: no encontrado

Tenga en cuenta que este mensaje supuestamente implica que no se encontró el archivo de script en sí. Si no se conocen los antecedentes del fenómeno, la situación parece sospechosa. El hecho es que al ejecutar cualquier programa, UNIX Siempre le pasa un parámetro (que tiene índice 0): el nombre de este programa. Pero si se ejecuta el script, el controlador recibirá como parámetro nulo no su propio nombre, sino el nombre del script. Y cuando el sistema no encuentre este controlador, se mencionará con un nuevo nombre en el mensaje de error.

Nidos de conchas

Y una nota más importante. Al principio solo había uno en UNIX intérprete de comandos, escrito por Stephen Bourne, y simplemente se llamaba “shell” (es decir, shell, y el nombre de la utilidad es sh para abreviar). Era un pequeño programa muy simple, funcionaba perfectamente como integrador de sistemas, pero en todos los demás aspectos era bastante débil. Y entonces a los creadores de 3BSD se les ocurrió que necesitaban un sistema completamente nuevo. intérprete de comandos, más conveniente cuando se trabaja en la línea de comando, con nuevas capacidades de programación y una nueva sintaxis cercana al lenguaje C, que ya es familiar para cualquier programador de UNIX. El shell resultante se llamó C shell (por la sintaxis del comando; el nombre de la utilidad es csh), era mucho más poderoso que el anterior, incluía trabajar con el historial, completar nombres de archivos, gestión del trabajo; Aparecieron matrices y mucho más.

¿Qué es un caparazón y por qué es necesario?

El shell de comandos en cualquier sistema tipo Unix, incluido GNU/Linux, es un programa normal que se ejecuta tanto en una consola de texto (que se usa cada vez menos) como en un entorno gráfico, en la ventana de un emulador de terminal, disponible en cualquier sistema Linux.

Su tarea es simple y obvia: aceptar una línea (o líneas) de entrada, analizarlas y, según los resultados de este análisis, reaccionar en consecuencia: ejecutar un comando, ejecutar un programa, mostrar un mensaje de diagnóstico, etc.

Casi todas las distribuciones de Linux asignan a los usuarios el shell predeterminado para bash (Bourne Again SHell es otro shell Bourne; Steve Bourne es el autor del primer shell en Unix, sh). De hecho, se ha convertido en un estándar no oficial y se están realizando mejoras en su funcionalidad. Hay otros shells de comandos: tcsh (versión de C-shell), ksh (Korn Shell), zsh, etc. – cada uno tiene sus propias ventajas y desventajas, así como sus propios grupos de fans. Sin embargo, bash es más familiar para una amplia gama de usuarios con diferentes niveles de experiencia, razón por la cual lo elegí. También vale la pena señalar que, independientemente de las capacidades que tengan los distintos caparazones, todos son compatibles con su progenitor ideológico: el Bourn Shell (sh). En otras palabras, un script escrito para sh funcionará correctamente en cualquier shell moderno (lo contrario generalmente no ocurre).

Beneficios de la línea de comando

Puede surgir la pregunta: ¿por qué molestarse con la línea de comandos si existen interfaces gráficas cómodas y hermosas? Hay muchas razones para esto. En primer lugar, no todas las operaciones son más cómodas y rápidas de realizar utilizando una interfaz gráfica. En segundo lugar, cada programa sigue el principio fundamental de los sistemas Unix: hacer un trabajo bien definido y hacerlo bien. En otras palabras, siempre comprenderá lo que sucede cuando ejecuta una utilidad en particular (si algo no está del todo claro, debe consultar el manual). En tercer lugar, al dominar los comandos, probar sus combinaciones y combinaciones de parámetros, el usuario estudia el sistema y adquiere una valiosa experiencia práctica. Obtiene acceso a herramientas poderosas, como canalizaciones que le permiten organizar una cadena de comandos para procesar datos, herramientas de redirección de E/S y también puede programar directamente desde el shell de comandos. Quizás valga la pena detenerse en la programación con más detalle, especialmente porque muchos scripts del sistema en Linux (por ejemplo, scripts para iniciar servicios del sistema) están escritos para el shell.

Shell de comandos como lenguaje de programación

Por lo tanto, el shell de comandos puede considerarse como un lenguaje de programación y como un tiempo de ejecución de software al mismo tiempo. Por supuesto, este lenguaje no se compila, sino que se interpreta. Permite el uso de variables: del sistema o propias. La secuencia de ejecución de los comandos del programa se cambia utilizando construcciones de verificación de condiciones y seleccionando la opción apropiada: si-entonces-si no y caso. Los bucles while, Until y for le permiten automatizar acciones repetitivas. Es posible combinar grupos de comandos en bloques lógicos. Incluso puedes escribir funciones reales que les pasen parámetros. Por tanto, están disponibles todas las características y características de un lenguaje de programación completo. Intentemos sacar el doble beneficio de esto: además de aprender los conceptos básicos de programación, automatizaremos nuestro trabajo diario.

¡Hola Mundo! Sistema de respaldo sencillo

Todo el mundo sabe la necesidad de realizar copias de seguridad de datos periódicamente, pero los usuarios nunca tienen tiempo suficiente para esta aburrida operación. La solución es simple: organizar la creación automática de copias de seguridad. Esta será nuestra primera tarea de programación de shell.

#!/bin/bash # # Copia de seguridad de directorios y archivos desde el directorio de inicio # Este script por lotes se puede ejecutar automáticamente usando cron # cd $HOME if [ ! -d archivos] luego mkdir archivos fi cur_date=`fecha +%Y%m%d%H%M` if [$# -eq 0]; luego tar czf archive$(cur_date).tar.gz proyectos bin else tar czf archive$(cur_date).tar.gz $* fi if [ $? = 0 ] ; luego mv archive$(cur_date).tar.gz $HOME/archives echo "$cur_date – Copia de seguridad completada exitosamente". else echo "$cur_date - ERROR durante la copia de seguridad". fi

Cualquier script de comando (el script es un script, como se llama a los programas de shell de comandos) comienza con una línea de identificación, en la que se especifica explícitamente el intérprete de comandos, indicando la ruta completa al mismo. La ruta completa es una lista secuencial de todos los directorios, comenzando desde la raíz, que se deben ingresar para llegar al archivo de destino y, por supuesto, el nombre de este archivo. Registrar la ruta completa es extremadamente importante para identificar de forma única cada archivo en la jerarquía del sistema de archivos.

Siguen cuatro líneas de comentarios. Una vez que el shell encuentra el carácter "#", trata todos los caracteres siguientes como comentarios y los ignora por completo hasta el final de la línea actual. Por lo tanto, puede iniciar un comentario no desde el principio de la línea, sino acompañarlo con algún comando.

Después de los comentarios hay una línea vacía. No significa nada para el shell de comandos y no se realiza ninguna acción. En los scripts, normalmente se insertan líneas en blanco para que el código sea más fácil de leer.

Finalmente llegamos al primer equipo "real". Le permite cambiar el directorio (Cambiar directorio), es decir. pasar del directorio actual a otro pasado al comando como argumento. En la mayoría de los casos, el directorio de destino se especifica explícitamente, por ejemplo, cd /tmp o cd proyectos, pero en nuestro caso se utiliza la variable de sistema predefinida HOME: contiene la ruta completa al directorio de inicio del usuario actual bajo cuyo nombre Se está ejecutando el script de comando. Esto elimina la necesidad de realizar cambios de código cada vez que cambiamos de usuario, porque el comando devuelve a todos a su directorio personal. El signo de dólar "$" delante del nombre de una variable significa que debe extraer el valor contenido en esa variable y sustituirlo por su nombre en la línea de comando. Cabe señalar especialmente que en un lenguaje de comandos, los shells de letras son importantes, es decir INICIO, Hogar y hogar son tres variables diferentes. Por convención, las letras mayúsculas indican los nombres de las variables del sistema: INICIO, RUTA, EDITOR, etc. Esta convención no impide que los usuarios creen sus propias variables con nombres en mayúsculas, pero ¿por qué complicarse la vida violando reglas y regulaciones generalmente aceptadas? Tampoco se recomienda cambiar los valores de las variables del sistema a menos que sea absolutamente necesario. En general, seguimos una regla simple: usamos variables del sistema para fines de solo lectura y, si necesitamos las nuestras, escribimos su nombre en letras minúsculas.

Nuestro primer comando podría escribirse más brevemente:

discos compactos ~

Aquí el símbolo "~" también significa el directorio de inicio del usuario actual. Los veteranos de la línea de comando lo expresan de manera aún más sucinta:

CD

La idea es que cuando el comando cd no recibe ningún argumento, cambia al directorio de inicio.

El siguiente paso es el diseño de software clásico para verificar las condiciones y tomar la decisión adecuada. El esquema general es:

si<условие>entonces<одна или несколько команд>fi

La última palabra de la construcción (si está en orden inverso) actúa como paréntesis de cierre, es decir límites de la lista de comandos ejecutados cuando la condición es verdadera. La presencia de fi es obligatoria, incluso si solo hay un equipo en la lista.

Para verificar una condición, por regla general, se utiliza el comando de prueba o su forma alternativa de notación entre corchetes. En otras palabras, registros

si [! -d archivos] si prueba! -d archivos

absolutamente equivalente. Prefiero los corchetes porque definen más claramente los límites de la condición que se está probando. Tanto el paréntesis derecho como el izquierdo deben estar separados de la condición por espacios.

Los criterios para comprobar el estado están determinados por varias banderas. El comando de prueba reconoce una lista muy grande de ellos. En nuestro ejemplo, el indicador -d se utiliza para comprobar si el nombre especificado después del indicador corresponde a un directorio de la vida real. Las siguientes opciones se utilizan con mayor frecuencia cuando se trabaja con archivos:

F – si existe un archivo normal con el nombre de pila;

R – si el archivo especificado tiene derecho a leerlo;

W – si el archivo especificado tiene derecho a escribir en él;

X – si el archivo especificado tiene derecho a ejecutarlo;

S: si el archivo especificado tiene un tamaño distinto de cero.

En nuestro caso, la condición está precedida por un signo de exclamación, que indica la operación de negación lógica, por lo que el significado de la condición que se está probando se vuelve completamente opuesto. Intentemos escribir el significado de estos comandos en ruso común:

si [! -d archivos] Si el directorio de archivos (en el directorio actual) no existe, comience a ejecutar el bloque de comandos: mkdir archivos crea el directorio de archivos (en el directorio actual) y finalice la ejecución del bloque de comandos.

Como puede ver, todo resultó no ser tan complicado. Con un poco de práctica, usted mismo podrá leer y crear fácilmente diseños similares. El comando de creación de directorio es tan obvio que no se requieren más explicaciones.

En la siguiente línea creamos nuestra propia variable local, cur_date. En la gran mayoría de los casos, las variables se crean simplemente asignando un valor específico, por ejemplo:

ten=10 string="Esta es una línea de texto"

Pero en nuestro ejemplo se utiliza un pequeño truco. Tenga en cuenta que después del signo igual, el símbolo de asignación, el comando está escrito entre comillas invertidas. Esta forma de notación le permite asignar a una variable no la cadena en sí, sino el resultado de su ejecución. Aquí está el resultado del comando de fecha, que devuelve la fecha y hora actuales en un formato especificado por una lista de parámetros:

%Y – año actual en forma completa, es decir de cuatro dígitos (por ejemplo, 2009);

%m – número del mes actual (por ejemplo, 09 – para septiembre);

%d – número del día actual;

%H – hora actual en formato de 24 horas;

%M – minuto actual.

Por lo tanto, si ejecuta el comando

cur_date=`fecha +%Y%m%d%H%M`

el diez de septiembre de 2009 a las 22:45, a la variable cur_date se le asignará el valor de cadena "200909102245". El propósito de este truco es crear un nombre único y no repetitivo para el archivo comprimido. Si tiene la intención de ejecutar varias instancias del programa en un minuto, puede mejorar la unicidad de los nombres agregando los segundos actuales. ¿Cómo? Estudie el manual de la utilidad de fecha (fecha de hombre); no tiene nada de complicado.

Antes de comenzar a crear un archivo de almacenamiento, debemos determinar qué directorios guardaremos en él. Para mayor flexibilidad, podemos especificar un conjunto de directorios para archivar de forma predeterminada, pero brindar la posibilidad de reemplazar este conjunto con una lista de directorios pasados ​​como argumento a nuestro script de comando. Para este propósito, se utilizan variables de shell de comando especiales: $# – el número de parámetros pasados ​​al script y $* – todos los parámetros pasados, escritos en formato de una línea.

si [$# -eq 0]; entonces

Verificando la condición "si el número de parámetros pasados ​​es cero", luego ejecute el siguiente comando. Tenga en cuenta que la palabra clave entonces se puede escribir en la línea de condición, separada de la expresión condicional por un punto y coma.

archivo tar czf$(cur_date).tar.gz contenedores de proyectos

El comando para crear un archivo de almacenamiento y comprimir este archivo. La utilidad tar en sí no realiza compresión, solo recopila todos los archivos y directorios especificados en un solo archivo tar. La primera bandera está destinada a esto: c (crear). La compresión la realiza un programa externo; aquí es gzip, llamado por la segunda bandera: z. Si tiene instalado en su sistema el programa de compresión bzip2, más eficiente, puede aprovecharlo modificando el comando de la siguiente manera:

tar cjf archive$(cur_date).tar.bz2 contenedores de proyectos

La tercera bandera f indica que lo que sigue es el nombre del archivo comprimido, por lo que siempre es el último en la lista de banderas. Tenga en cuenta que al sustituir, el nombre de la variable se escribe entre llaves. Esto se hace para resaltar explícitamente la variable en la línea que la rodea, eliminando así muchos problemas potenciales. Las extensiones no se asignan al archivo comprimido automáticamente; usted mismo agrega todo lo que necesita. He especificado proyectos y bin como directorios predeterminados para archivar, pero puedes escribir los nombres de tus directorios más valiosos aquí.

La palabra clave else abre una rama de ejecución alternativa. Los comandos de este bloque comienzan a funcionar si la verificación de condición devuelve el resultado "falso" (en nuestro ejemplo: "el número de parámetros pasados ​​no es cero", es decir, los nombres de directorio especificados por el usuario). En este caso el comando se verá así:

archivo tar czf$(cur_date).tar.gz $*

Aquí los directorios predeterminados se reemplazan por una cadena de nombre de directorio aceptada externamente. Es posible aceptar y procesar cada parámetro externo por separado, pero nos resulta más conveniente pasar la cadena completa.

Al final del programa, se realiza otra verificación. En entornos Unix, todos los comandos devuelven un código de estado de finalización. Si el comando fue exitoso, devuelve el código 0; de lo contrario, el código de salida será distinto de cero. Para comprobar el éxito del comando de archivado anterior, usaremos otra variable especial $?, que siempre contiene el valor del código de finalización del comando más reciente. Si en la variable $? contiene 0, es decir El archivo de copia de seguridad se creó correctamente, luego lo movemos al directorio de archivo:

mv archivo$(cur_date).tar.gz $HOME/archivos

y mostrar el mensaje correspondiente:

echo "$cur_date – Copia de seguridad completada exitosamente."

Si la verificación muestra que el código de finalización de la operación de archivado no es cero, se muestra un mensaje de error:

echo "$cur_date - ERROR durante la copia de seguridad."

Esto completa nuestro script de comando.

Para probar el funcionamiento de nuestro programa, necesitamos guardar el código fuente descrito anteriormente en un archivo, por ejemplo, llamado bckp, y luego, por conveniencia, hacerlo ejecutable:

chmod 750 bckp

y ejecuta:

./bckp

para crear una copia de seguridad de los directorios predeterminados, y

./bckp docs progs funciona

para crear una copia de seguridad de los directorios enumerados (especifique los nombres de los directorios que realmente existen en su sistema; de lo contrario, recibirá un mensaje de error).

Puede colocar el archivo bckp en uno de los directorios especificados en la variable PATH del sistema. Las ubicaciones más preferidas son /usr/local/bin o $HOME/bin si las tiene. Después de esto, puedes ejecutar bckp como comando del sistema.

Cómo automatizar las operaciones de copia de seguridad programadas

Algunas palabras sobre la automatización de copias de seguridad. Para ello, se utiliza el programador cron del sistema, que lee las instrucciones de trabajo de un archivo crontab especial. Para definir dichas instrucciones, necesita crear y editar su archivo crontab usando el comando:

crontab-e

Las instrucciones están escritas en un formato estrictamente definido (los campos están separados por espacios):

minutos horas día_del_mes mes día_de_la semana comando

Una opción para programar operaciones de respaldo podría verse así:

30 23 10,20,30 * * /usr/local/bin/bckp

Esto significa que el script de copia de seguridad (debe proporcionar la ruta completa a este archivo) se ejecutará a las 23:30 los días 10, 20 y 30 de cada mes, independientemente del día de la semana. (Los asteriscos indican todo el rango de valores permitidos, en este caso: cada mes - en el 4º campo, cualquier día de la semana - en el 5º campo)

Si prefiere resumir sus resultados por semana y su sistema funciona las 24 horas del día, los 7 días de la semana, entonces tiene sentido programar copias de seguridad durante las horas de menor actividad:

0 5 * * 3.5 /usr/local/bin/bckp

Aquí, las copias de seguridad se crearán a las 5:00 los miércoles y viernes de cada mes (asterisco en el 4º campo), independientemente de la fecha (asterisco en el 3º campo).

Puede leer sobre todas las complejidades de la programación en el manual de crontab de man 5.

Resultados y conclusiones

El script de copia de seguridad que se analiza en este artículo tiene propiedades funcionales modestas. Pero esta no era su tarea principal, sino que el lector entendiera lo que se puede hacer en la línea de comando, y no solo copiara y ejecutara el archivo de comando propuesto, sino que se interesara en ampliar sus funciones y comenzara a explorar las inmensas posibilidades que brinda. mediante shells de comando. Y si alguien, después de leer este artículo, intenta mejorar el código proporcionado aquí, escribe su propia versión o implementa su propia idea independiente, entonces consideraré que se ha logrado el objetivo principal.

Recursos para descargar

static.content.url=http://www.site/developerworks/js/artrating/

ID del artículo=458335

ArticleTitle=Conceptos básicos de programación de Shell

Los shells de comando aparecieron al comienzo del desarrollo de Unix, eran necesarios porque eran la única forma de interactuar con el sistema. Durante este tiempo, han recorrido un largo camino de desarrollo y han recibido muchas funciones nuevas. No es fácil apreciar la evolución de los shells de Linux. Puedes escribir sobre esto durante mucho tiempo y un artículo definitivamente no es suficiente. Intentaremos cubrir sólo lo básico sin profundizar demasiado. Primero veamos qué es el shell de comandos de Linux y qué shells existen.

¿Qué es un shell de Linux/Unix?

El shell de Unix es un intérprete de línea de comandos que ejecuta comandos ingresados ​​por el usuario. Ingresamos un comando, se interpreta, ejecuta y luego obtenemos el resultado de su ejecución. El shell proporciona la interfaz de entrada de comandos tradicional de Unix a la que estamos acostumbrados. Suele ser una pantalla negra y texto en blanco. Ingresamos comandos en texto plano y también podemos crear scripts a partir de uno o más comandos.

El shell es su interfaz para interactuar con el sistema. Después de iniciar sesión en un sistema Unix, se encuentra en un programa llamado shell.

Concha Thompson

Si cree en la historia y en muchas fuentes de Internet, el primer caparazón fue el Thompson Shell, escrito por Ken Thomson en Bell Labs. Hubo 6 versiones en total y se distribuyó desde 1971 hasta 1975. Se admitían funciones como la redirección de entrada/salida y construcciones de control simples (si, ir a). Estas funciones son compatibles con todos los shells de comandos de Linux modernos.

Carcasa PWB

La carcasa PWB es una modificación de la carcasa Thomson desarrollada por John Masheu. Fue escrito para aumentar la conveniencia de la programación Shell. Han aparecido estructuras interesantes como los bucles if-then-else-endif, switch y while.

Concha Bourne

Unix comenzó su ascenso con el shell Bourne. Fue escrito por Stefan Born en Bell Labs y se usó como shell predeterminado en la versión 7 de Unix desde 1979. Aquí ya se han implementado una gran cantidad de funciones disponibles en los shells modernos: finalización de nombres de archivos, finalización de comandos, variables de entorno estándar y estructuras de control integradas. Bourne Shell se llamaba sh y estaba ubicado en el sistema de archivos Unix en /bin/sh.

En muchos sistemas, un programa Bourne Shell (sh) es un enlace físico o simbólico a una de sus alternativas:

  • Concha de Almquist (ceniza)
  • Shell Bourne-Again (bash)
  • cáscara de maíz (ksh)
  • Carcasa Z (zsh)

Script de ejemplo para Bourne Shell:

!/bin/sh
echo "¡Hola mundo 1!"
echo "¡Hola mundo 2!"

Concha de Almquist (ceniza)

Concha de Almquist, también conocida como Concha A. Es un shell Unix liviano escrito originalmente por Kenneth Almquist. Fue desarrollado a finales de los años 1980. Esta es una modificación del shell Bourne y reemplazó al original en BSD Unix lanzado en 1990. Ahora se puede utilizar en distribuciones como Debian y Ubuntu como una versión de ash llamada dash (shell Debian Almquist). Este shell también es popular en distribuciones Unix integradas.

Es un shell Unix rápido, compacto y compatible con POSTIX, razón por la cual se utiliza a menudo en dispositivos integrados. Pero Ash no admite historiales de comando. Aunque en las versiones modernas ya se ha añadido esta función.

Bourne-Again Shell (Bash)

Escrito por Brian Fox como parte del Proyecto GNU como reemplazo gratuito y de código abierto del shell Bourne. Bash es el más popular y ampliamente utilizado de todos los shells. Todas las distribuciones de Linux vienen con este shell de forma predeterminada. Amplía el conjunto de funciones de Bourne Shell. En la mayoría de los sistemas Unix/Linux, este shell se puede encontrar en el sistema de archivos en /bin/bash. Fue lanzado en 1989.

Debido a tal popularidad, fue portado a Windows y distribuido junto con un conjunto de compiladores Cygwin y MinGW. Bash también se usa en Android y se puede acceder a él mediante varios emuladores de terminal.

Admite autocompletado, redirección de E/S, finalización de comandos, variables y estructuras de control para la toma de decisiones (si-entonces-elese si) y bucles.

Los scripts de Bash comienzan con esta línea:

Este shell de Linux también admite la lectura de comandos de un archivo y la redirección de la salida a un archivo u otro comando.

Código de ejemplo en Bash:

!/bin/sh
si [ $días -gt 365 ]
entonces
echo Esto es más de un año.
fi

cáscara de maíz (ksh)

Escrito por David Kron y basado en el código fuente del shell Bourne. KornShell (ksh) es un shell desarrollado en Bell Labs en 1980. Es compatible con versiones anteriores de Bourne Shell y también incluye muchas de las características del shell C.

Existen las siguientes versiones y modificaciones:

  • dtksh
  • Concha de Korn MKS

Guión de ejemplo:

!/bin/ksh
imprimir uso de espacio en disco
Du-k
salir 0

Carcasa Z (zsh)

Paul Falstad escribió la primera versión con el comando zsh shell en 1990. Es un shell de comandos de Linux que se puede utilizar como un shell de inicio de sesión interactivo, un intérprete de comandos muy potente. Zsh es en realidad un shell Bourne extendido con muchas mejoras que incluye algunas características de Bash, KSH y Tcsh.

El nombre Zsh proviene del profesor de Yale Zhong Shao, ya que Paul era estudiante en la Universidad de Princeton.

Se admiten las siguientes características interesantes:

  • Finalización de línea
  • Historial de comandos compartido para todas las sesiones de shell
  • Trabajo mejorado con variables y matrices.
  • Editar varias líneas en un búfer
  • Corrección ortográfica y mucho más.

caparazón C

El shell C también se conoce como Csh. Fue desarrollado por Bill Joy cuando era estudiante en la Universidad de California. Este shell es muy común en los sistemas BSD Linux. Aquí hay muchas características interesantes, incluidas estructuras de control y expresiones gramaticales. Este shell también introdujo una gran cantidad de características interesantes por primera vez, como mecanismos de edición e historial, alias, CDPATH, administración de tareas y hash, redirección de salida, anexaciones, reemplazo de variables, ejecución en segundo plano, etc.

Al igual que otros tipos de shells de Linux, admite archivos de script, redirección y estructuras de control. Csh ahora se usa como tcsh en muchos sistemas, como MacOS X y Red Hat Linux. En Debian puedes usar tanto CSH como Tcsh.

Código de muestra en C Shell:

!/bin/csh
si ($días > 365) entonces
echo Esto es más de un año.
endif

Pez

Fish o Friendly Interactive Shell es un shell de comandos de Linux de nueva generación. Está diseñado para facilitar al usuario la ejecución de comandos, hay resaltado de sintaxis, resaltado de direcciones de archivos correctas, búsqueda rápida en el historial, un configurador web, así como una sintaxis de script especial.

Este es un nuevo shell de comandos en Linux y su sintaxis no se parece a ningún otro shell de comandos moderno, sino que se parece más bien al lenguaje de programación Python.

Un ejemplo de creación de una función en fish:

!/usr/bin/pescado
funciono su
función su
/bin/su --shell=/usr/bin/fish $argv
fin
guardar función su

Puede ver una comparación más detallada de shells de comandos en Linux en el enlace.

Eso es todo por hoy. Espero que te haya resultado interesante.

Seguramente casi todos los lectores de Habr conocen los shells sh y bash. Además, la mayoría de nosotros hemos oído algo sobre zsh y tcsh. Sin embargo, la lista de shells existentes no termina ahí. Se pueden dividir a grandes rasgos en tres grupos:

  • Clones de shell Bourne (bash, zsh)
  • C shell (csh, tcsh)
  • Basado en lenguajes de programación populares (psh, ipython, scsh)
  • Exótico, específico y todo lo demás.
Se discutirán los más interesantes de ellos.

El propósito de escribir este artículo no fue revisar o clasificar todos los shells de comandos existentes. Sólo quiero hablar sobre algunos productos interesantes en esta área y ampliar los horizontes del lector. Me alegraré. Si esto anima a alguien a estudiar el tema con más detalle o incluso pasar a otro tema.
Primero, brevemente sobre qué es. Un shell de comandos o intérprete de comandos es una aplicación que proporciona al usuario una interfaz de línea de comandos en la que el usuario ingresa comandos individualmente o ejecuta scripts que constan de una lista de comandos. Oralmente y en textos no oficiales a menudo se le llama "shell", del inglés shell - shell.

Los shells compatibles con POSIX más utilizados descienden del shell Bourne, así que comenzaremos con eso.

Bourne Shell y sus clones.

concha de bourne, archivo ejecutable: sh. Un shell de comandos que lleva el nombre de su creador, Stephen Bourne. La mayoría de los operadores fueron tomados del lenguaje ALGOL 68. Fue lanzado en la séptima edición del sistema operativo UNIX, donde era el shell predeterminado. Hasta el día de hoy, la gran mayoría de sistemas tipo Unix tienen /bin/sh, un enlace físico o simbólico a un shell compatible con sh.

Bourne Shell otra vez, archivo ejecutable: intento. El título se puede traducir como “El paseo renacido de Bourne”. Probablemente el caparazón más popular en la actualidad. Estándar de facto para Linux. No me detendré en ello, porque... Hay muchos buenos artículos sobre bash en Internet. Por ejemplo aquí y aquí.

concha Z, archivo ejecutable: zsh. Un shell gratuito y moderno compatible con SH. Tiene una serie de ventajas sobre bash, principalmente relacionadas con el trabajo en modo interactivo. Escribieron sobre esto en Habré y
Además, hay bastantes proyectiles que entran en este grupo: el proyectil Korn (ksh) y el proyectil Almquist (ash), etc., pero no nos detendremos en ellos en detalle.

caparazón C

caparazón C, archivo ejecutable: csh Un shell de comando desarrollado por el autor de vi, Bill Joy. La base del lenguaje de programación csh fue, como su nombre indica, el lenguaje C. en aquel momento, en 1978, era el lenguaje de programación más popular entre los desarrolladores y usuarios de BSD UNIX. Actualmente, la implementación gratuita más popular de csh es tcsh.

Carcasa TENEX C, archivo ejecutable: tcsh. Fue en tcsh donde apareció por primera vez el autocompletado. Este es el shell predeterminado en FreeBSD. Puedes leer más al respecto.
Para mostrar claramente la diferencia en la sintaxis, daré varios ejemplos de scripts que hacen lo mismo para csh y un intérprete de comandos compatible con sh.

Construcción condicional:

Un bucle que calcula las primeras 10 potencias de dos:

#!/bin/sh i=2 j=1 mientras [ $j -le 10 ]; hacer echo "2 **" $j = $i i=`expr $i "*" 2` j=`expr $j + 1` hecho #!/bin/csh establecer i = 2 establecer j = 1 mientras ($j<= 10) echo "2 **" $j = $i @ i *= 2 @ j++ end

Sin embargo, la lista de características admitidas por las últimas versiones de bash, zsh y tcsh es muy similar y la elección de un shell específico es principalmente una cuestión de gustos. Con conchas menos comunes la situación es diferente. Aquí las diferencias son más significativas.

Shells de comandos basados ​​en lenguajes de programación populares.

Shell Perl, archivo ejecutable: psh. Un shell que combina la funcionalidad de los shells anteriores y el poder del lenguaje Perl. Porque psh está escrito en perl e incluso puede ejecutarse en Windows. Algunos ejemplos de uso de psh:
ls | s/y/k/ # Reemplazo usando expresiones regulares ls | ( print ++$i, ": $_"; )q # Filtro rápido. Dentro de las llaves hay una expresión Perl donde $_ contiene una línea de salida.

netstat | ( $_>2; )g # filtros grep. Solo se imprimen aquellas líneas para las cuales la expresión entre paréntesis devuelve verdadero comando >[=FOO] # Redirigir a un descriptor de archivo abierto comando > archivo # Equivalente al comando 2> archivo en bash. Redirige la salida y el flujo de error a un archivo grep foo lib/**/*.pm # Usando **, lo que significa el directorio actual y todos los subdirectorios scsh , archivo ejecutable scsh
. Un intérprete de comandos de código abierto que utiliza el Esquema 48 como lenguaje de secuencias de comandos. No admite funciones estándar para otros shells (historial de comandos, edición de texto en la línea de comandos, adición de rutas/comandos). Se recomienda el uso de scripts, pero no para trabajos interactivos. Puede atraer a los fanáticos de la programación funcional. A continuación se muestra un ejemplo de un script que muestra los nombres de todos los archivos ejecutables ubicados en directorios de la variable de entorno PATH.

#!/usr/local/bin/scsh -s !# (definir (directorio de ejecutables) (con-cwd dir (filtrar archivo-ejecutable? (directorio-archivos dir #t)))) (definir (writeln x) (mostrar x) (nueva línea)) (para cada escritura (ejecutables append-map ((infix-splitter ":") (getenv "PATH")))) IPython
ipython3 --perfil=pysh

Ya se ha escrito bastante sobre IPython, incluso en ruso (enlaces al final del artículo). Intentaré enumerar sus características principales desde el punto de vista de su uso como shell de comandos:

  • Multiplataforma. Incluso existe una versión para Windows.
  • Versiones de Python 2.x o 3.x como lenguaje de programación, capacidades de introspección mejoradas
  • Autocompletado de código Python, así como nombres de archivos y comandos del sistema.
  • Historial de comandos y macros basadas en él.
  • Un mecanismo que agiliza la navegación por catálogos, marcadores y mucho más
Como puede ver, en términos de capacidades interactivas, IPython es al menos tan bueno como bash. En cuanto a los scripts, IPython será conveniente para aquellos que conocen Python mejor que bash. De hecho, los scripts de IPython se diferenciarán de Python puro sólo en la llamada simplificada de los comandos del sistema. A continuación se muestran algunos ejemplos de la integración de Python y los comandos del sistema:
# Digamos que queremos calcular el tamaño total de los archivos de registro dpkg: Entrada: cd /var/log/ /var/log Entrada: log_files = !ls -l dpkg.log* Entrada: log_files Salida: "-rw-r- -r-- 1 raíz raíz 1824 3 de noviembre 16:41 dpkg.log" Entrada: para línea en log_files: ....: tamaño += int(line.split()) ....: Entrada: tamaño Salida: 1330009 # ..o hacer ping secuencialmente a diez hosts In: for i in range(100,110): ....: !ping -c 1 192.168.0.$i ....:
Descansar
Por supuesto, esta no es una lista completa ni siquiera de los shells más populares. Además de las categorías anteriores, también existen aquellas que utilizan su propia sintaxis, que no es compatible con sh y no copia el lenguaje existente. Un ejemplo sería el amigable caparazón interactivo (pez). Pero, por último, no me gustaría hablar de eso, sino de un Sleepshell más específico.

Chupete para dormir, archivo ejecutable: sueño. Estrictamente hablando, a Sleepshell no se le puede llamar procesador de comandos, porque no puede procesar comandos. Y, en general, no puede hacer nada excepto escribir periódicamente asteriscos "*" en la salida estándar. Sin embargo, se usa precisamente como shell de comandos y por esta razón: Digamos que queremos darle a alguien la oportunidad de hacer túneles ssh a través de nuestro servidor ejecutando Linux o Unix. Lea más sobre los túneles ssh. Pero no necesitamos que alguien tenga acceso a la línea de comandos y al sistema de archivos de nuestro servidor. Sleepshell está diseñado para tal caso. Creamos una cuenta en el servidor como shell e instalamos sleepshell para ella. El propietario de la cuenta podrá conectarse y reenviar puertos, pero no podrá ejecutar comandos.

Eso es todo. Espero que haya sido interesante. Estaré encantado de recibir cualquier comentario y consejo sobre el texto del artículo.

Enlaces relacionados
www.faqs.org/faqs/unix-faq/shell/shell-differences - tabla resumen de diferencias y similitudes de shell
www.mariovaldez.net/software/sleepshell - Sleep Dummy Shell
ipython.org/ipython-doc/dev/interactive/shell.html - IPython como shell del sistema
www.opennet.ru/base/dev/ipython_sysadmin.txt.html - Shell IPython como herramienta de administrador del sistema


Arriba