Tracks
/
Bash
Bash
/
Temario
/
Comandos y argumentos
Co

Comandos y argumentos en Bash

{one: "1 ejercicio", many: "%{count} ejercicios", other: "%{count} ejercicios"}

Acerca de Comandos y argumentos

Shells

Un shell es un programa que te permite introducir comandos para interactuar con el sistema operativo. Los shells pueden ser gráficos; el entorno de escritorio que usas con el ratón o el trackpad es un shell. Nos centraremos en las interfaces de línea de comandos, en las que escribes comandos y los resultados se imprimen (normalmente) en tu terminal.

Existen muchos shells de línea de comandos distintos. Windows ofrece cmd y powershell. Mac y Linux ofrecen «shells de Unix», de los que hay muchos. El shell predeterminado de Mac es zsh. csh es un shell heredado con una sintaxis similar a la de C. bash es uno de los shells más populares, sobre todo en Linux.

Uno de los primeros shells es el shell de Bourne, sh. Con el tiempo, este shell se estandarizó para ofrecerse en todos los sistemas similares a Unix. Muchos shells se basan en el shell de Bourne y a menudo aportan funcionalidad adicional, ya sea interactiva o de programación.

Bash se basa en el shell de Bourne. Por eso se llama «Bourne-again shell». Es el shell predeterminado en muchos sistemas Linux. Bash ofrece muchas facilidades que lo convierten en un shell interactivo agradable, como:

  • un prompt totalmente personalizable,
  • la capacidad de recuperar y modificar comandos del historial,
  • la capacidad de manipular procesos en ejecución,
  • alias que reducen la cantidad de texto que escribes,
  • y mucho más.

Este track no trata sobre cómo usar bash como shell interactivo. Trata sobre aprender a escribir programas con bash. El énfasis estará en usar únicamente bash para resolver problemas, aunque no hay ninguna restricción a la hora de llamar a herramientas externas.

Fundamentos de bash: comandos y argumentos

Bash lee comandos de su entrada (que normalmente es un terminal o un fichero). Cada línea de entrada que lee se trata como un comando: una instrucción que hay que llevar a cabo. (Hay algunos casos avanzados, como los comandos que abarcan varias líneas, que veremos más adelante.)

Bash divide cada línea en palabras delimitadas por un espacio en blanco (espacios y tabuladores). La primera palabra de la línea es el nombre del comando que se va a ejecutar. Todas las palabras restantes se convierten en argumentos de ese comando (opciones, nombres de fichero, etc.).

Note

En los ejemplos siguientes te mostramos algunos comandos interactivos que puedes ejecutar.

  • El carácter # inicia un comentario. El shell ignora todas las palabras que siguen al comentario; el comentario solo sirve para leerlo.
  • El carácter $ indica el prompt del shell. Si copias el comando, no incluyas el prompt.
# Note: It is always a good idea to run `ls` before `rm`
# to make sure you know what you are deleting.

$ rm *            # Remove all files in the current directory.
                  # Make sure you run this in a temp directory or you can lose files!
$ ls              # List files in the current directory (no output, no files).
$ touch a   b c   # Create files 'a', 'b' and 'c'.
$ ls              # List files again; this time the outputs: 'a', 'b' and 'c'.
a  b  c

rm es una aplicación que elimina los ficheros que se le pasan. * es un carácter glob, un patrón «comodín» que coincide con todos los ficheros del directorio actual. Hablaremos más sobre los globs más adelante.

¿Te has fijado en que hay varios espacios entre a y b, y solo uno entre b y c? ¡La cantidad de espacios en blanco entre argumentos da igual! Por ejemplo:

$ echo This is a test.
This is a test.
$ echo This    is    a    test.
This is a test.

echo es un comando que imprime sus argumentos en la salida estándar (que en nuestro caso es el terminal). Bash divide el comando en cinco palabras y llama al comando echo con cuatro argumentos. Los espacios de más del segundo ejemplo no cambian nada. echo no sabe cómo estaban repartidos originalmente los espacios entre las palabras.

Si queremos conservar los espacios adicionales, tenemos que pasar la frase como un único argumento. Podemos hacerlo usando comillas:

$ echo "This    is    a    test."
This    is    a    test.

Las comillas agrupan todo lo que hay dentro de ellas en un único argumento. El argumento es This is a test., incluidos esos caracteres de espacio concretos. Ten en cuenta que las comillas no forman parte del argumento: bash las elimina antes de pasar ese único argumento a echo.

Los argumentos se separan del nombre del comando y entre sí mediante espacios en blanco. Es importante recordarlo. Por ejemplo, lo siguiente es incorrecto:

$ [-f file]
bash: [-f: command not found

La intención es comprobar si existe un fichero llamado file. Es razonable suponer que los espacios alrededor de [ y ] dan igual, pero [ es en realidad un comando y exige que su último argumento sea ]. (Veremos el comando [ con más detalle más adelante.) Por lo tanto, tenemos que separar [ de -f y ] de file. De lo contrario, bash pensará que estamos intentando ejecutar un comando llamado [-f con un único argumento file]. El comando correcto separa todos los argumentos con espacios en blanco:

$ [ -f file ]

(Vemos a mucha gente a la que este comportamiento confunde; creen que [...] es «solo sintaxis» y que pueden omitir los espacios; [ es un comando y los espacios son obligatorios.)

Si el nombre de nuestro fichero contiene espacios u otros caracteres especiales, también hay que entrecomillarlo:

$ [ -f "my file" ]

Tipos de comandos

Bash entiende varios tipos distintos de comandos: alias, funciones, comandos internos, palabras clave y ejecutables. Todos ellos son comandos y actúan de forma muy similar.

De forma predeterminada, los alias solo están activados en los shells interactivos, no en los scripts de shell. No los trataremos aquí.

Funciones

Una función contiene comandos de shell y se comporta de forma muy parecida a un script pequeño; incluso puede recibir argumentos y crear variables locales. Cuando se llama a una función, se ejecutan los comandos que contiene. Trataremos las funciones en profundidad más adelante.

Comandos internos

Bash incluye algunos comandos básicos integrados, como cd (cambiar de directorio), echo (escribir una salida), etc. Se pueden concebir como funciones que ya vienen incluidas.

Palabras clave

Las palabras clave son como los comandos internos, con la diferencia principal de que las palabras clave son en realidad sintaxis de bash y pueden analizarse con reglas especiales. Por ejemplo, [ es un comando interno de bash, mientras que [[ es una palabra clave de bash; ambos se usan para comprobar diversas condiciones. Pero la palabra clave [[ tiene alguna funcionalidad adicional. Por ejemplo, proporciona el operador =~, que realiza comprobaciones con expresiones regulares.

$ [[ "hello world" =~ e.*o ]]   # returns a "success" status
$ [ "hello world" =~ e.*o ]
bash: [: =~: binary operator expected

Los operadores de comparación de cadenas < y > son otro ejemplo de cómo las palabras clave analizan el código de forma distinta. Dentro de [[...]], estos operadores no necesitan ningún cuidado especial.

$ if [[ "$USER" < "n" ]]; then
    echo "$USER is in the first half of the alphabet"
fi
# => glennj is in the first half of the alphabet

Pero dentro de [...] tienes que entrecomillarlos o escaparlos para evitar que el shell los analice como operadores de redirección.

$ if [ "$USER" < "n" ]; then
    echo "$USER is in the first half of the alphabet"
fi
# => bash: n: No such file or directory

$ if [ "$USER" \< "n" ]; then
    echo "$USER is in the first half of the alphabet"
fi
# => glennj is in the first half of the alphabet

Ejecutables

El último tipo de comando que puede ejecutar bash es un ejecutable. Son ficheros ejecutables (programas) del sistema de ficheros de tu ordenador que puedes ejecutar. (A los ejecutables también se los puede llamar comandos externos o aplicaciones.) Lo habitual es invocar los ejecutables escribiendo solo su nombre; normalmente no hace falta la ruta completa al fichero. Esto es posible porque bash usa una variable predefinida que le ayuda a encontrar la ubicación de los ficheros ejecutables habituales. Esta variable se llama PATH. Es un conjunto de nombres de directorio separados por dos puntos (p. ej. /usr/bin:/bin). Cuando se especifica un comando (p. ej. myprogram o ls) sin una ruta de fichero (y no es un alias, una función, un comando interno ni una palabra clave), bash busca en los directorios de PATH. Los directorios se recorren en orden, de izquierda a derecha, para ver si contienen un ejecutable con el nombre indicado.

Si el ejecutable está fuera de una ruta conocida, habrá que especificar la ruta del fichero del ejecutable. Para el ejecutable myprogram del directorio actual, usa ./myprogram; si está en el directorio /opt/somedirectory, usa /opt/somedirectory/myprogram.

Consejo: el comando type sirve para obtener detalles sobre el comando:

$ type rm
rm is hashed (/bin/rm)
# or it might return: `rm is /bin/rm`

$ type cd
cd is a shell builtin

Scripts

Un script es una secuencia de comandos guardada en un fichero. Bash lee el fichero y procesa los comandos en orden. Pasa al siguiente comando solo cuando ha terminado el actual. La excepción es que se haya especificado que un comando se ejecute de forma asíncrona (en segundo plano). No te preocupes demasiado por este caso todavía; aprenderemos cómo funciona más adelante.

Cualquier ejemplo de línea de comandos de esta guía también se puede usar en un script.

Crear un script es fácil. Empieza creando un fichero nuevo y escribe esto en la primera línea:

#!/bin/bash

Esta línea se llama directiva de intérprete (también se la conoce como hashbang o shebang). Indica que se use /bin/bash como intérprete cuando el fichero se emplea como ejecutable en un comando. Cuando el kernel del sistema operativo ejecuta un fichero no binario, lee la primera línea del fichero. Si la línea empieza por #!, el kernel la usa para determinar a qué intérprete pasar el fichero. (También hay otras formas válidas de hacerlo, consulta más abajo.) El #! debe estar al principio mismo del fichero, sin espacios ni líneas en blanco antes. Los comandos de nuestro script aparecerán en líneas separadas debajo de esta.

Consejo: en lugar de #!/bin/bash , puedes usar

#!/usr/bin/env bash

env busca en $PATH el ejecutable indicado por su primer argumento (en este caso, «bash»). Para una explicación más detallada de esta técnica y de en qué se diferencia del simple #!/bin/bash, consulta esta pregunta de StackOverflow.

No te dejes engañar por scripts o ejemplos de Internet que usen /bin/sh como intérprete. ¡sh no es bash! El propio bash es un shell «compatible con sh», lo que significa que puede ejecutar la mayoría de los scripts de sh y comparte buena parte de la misma sintaxis. Sin embargo, lo contrario no es cierto; algunas características de bash fallarán o provocarán un comportamiento inesperado en sh. De hecho, no existe un único shell sh. Hay muchas implementaciones de shell que admiten la sintaxis de POSIX-sh. Según tu sistema operativo, cuando ejecutas sh puede que en realidad estés ejecutando bash, ash, dash u otro shell.

Una vez creado el fichero del script, se puede ejecutar así:

$ bash myscript

En este ejemplo, ejecutamos el comando bash y le decimos que lea el script que le hemos pasado como argumento. Cuando lo hacemos así, la línea #! es solo un comentario.

Como alternativa, podemos dar a nuestros scripts permisos de ejecución. Con este método podemos ejecutar el script como cualquier otro ejecutable en lugar de llamar a bash manualmente:

$ chmod +x myscript  # Mark the file as executable.
$ ./myscript         # Now, myscript can be executed directly
                     # instead of having to specify bash.

Cuando ejecutamos el comando de esta forma, el sistema operativo usa la línea #! para determinar qué intérprete usar para ejecutar tu script.

Créditos

El contenido de esta lección procede de Commands and Arguments, en la Bash Guide.

Editar en GitHub El enlace se abre en una nueva ventana o pestaña