Curso Básico de UNIX
 

Introducción al "shell"


Crear dos archivos de prueba
Comandos en el sistema UNIX
Estructura de Comandos
Expansiones de la línea de comandos
Variables de ambiente
Entrecomillado de argumentos
PS1
Entrada estándar y salida estándar
Fin de flujo
Agregar la salida estándar a un archivo
Error estándar
Interconexión de comandos (entubamiento)
Filtros
Campos y delimitadores
Valores de retorno de los comandos
El operador grave
Secuencias de comandos
Redirección del shell
Fin
Bibliografía y Referencias
 

El intérprete de comandos o "shell" actúa entre el sistema operativo y el operador. Provee al usuario una interfaz hacia el sistema operativo. El usuario dialoga con el intérprete de comandos, y éste transfiere las órdenes al sistema operativo, que las ejecuta sobre la máquina.

Crear dos archivos de prueba.

Con el comando cat puede crearse un archivo aceptando el teclado como entrada estándar y direccionando la salida estándar hacia un archivo:
  cat >nota
digitar las siguientes líneas, tal cual están, terminando cada línea dando <Enter>; finalizar con <Ctrl-D>. Digitar con cuidado: una vez pasados al renglón siguiente, no puede volverse atrás para corregir.
  El shell es un intérprete de comandos.
  Es también un lenguaje de programación.
  Los programas escritos con el shell se llaman scripts.
 
Digitar <Ctrl-D> para finalizar el ingreso.
 cat nota
muestra el contenido digitado.
 
Crear del mismo modo el archivo LEAME, haciendo
cat > LEAME
con este contenido:
Este es el archivo LEAME.
Recuerde que UNIX diferencia entre mayúsculas y minúsculas.
El archivo LEAME tendrá este contenido.
 
  cat LEAME
para verificar el contenido.

Comandos en el sistema UNIX.

En UNIX, los comandos son programas ejecutables separados. El shell es un intérprete de comandos: puede expandir y cambiar la manera en que actúan los comandos, admite el uso de comodines y la interconexión o entubamiento de comandos.

Estructura de comandos.

La estructura general de un comando es la siguiente:
  nombre opciones argumentos
nombre es el nombre del comando. Las opciones o banderas controlan la forma en que actúa el comando; van precedidas por el signo - (menos). Los argumentos son comúnmente nombres de archivos o nombres de login de usuarios.
 
 pr -l23 nota
 pr -l23 LEAME
da formato y muestra el archivo indicado en páginas de 23 líneas de largo para que quepa en la pantalla.
 pr -d -l23 LEAME
muestra el archivo LEAME a doble espacio, largo de página 23.
 pr -d -o15 -l23 LEAME
doble espacio, margen izquierdo de 15 espacios, largo de página 23.
 pr -l23 nota LEAME | more
muestra los dos archivos uno tras otro, pero los pagina separados.
 cat nota LEAME
concatena los archivos; los presenta uno tras otro.
 cat nota LEAME | pr -l23
concatena los archivos y luego les da formato a los dos juntos.

Expansiones de la línea de comando.

Los comodines son caracteres que sustituyen cadenas de caracteres.
*     secuencia de caracteres cualesquiera, 0 o más.
?     caracter cualquiera, uno y uno sólo; debe aparear un caracter.
[...] sustituye los caracteres indicados individualmente.

Variables de ambiente.

Las variables de ambiente son cadenas de caracteres de la forma
  nombre=valor
nombre es cualquier cadena de caracteres que no incluya $ ni espacio (\b); valor es cualquier cadena; puede incluir el espacio si el valor está entre comillas.
 
  MUESTRA="hola chicos"
asigna "hola chicos" a la variable MUESTRA.
  echo $MUESTRA
muestra en pantalla el contenido de la variable MUESTRA. Para exhibir el contenido de una variable de ambiente se escribe echo $nombre-variable.  En general, para hacer uso del contenido de una variable, se escribe $nombre-variable.
 
Es una costumbre muy arraigada en UNIX usar mayúsculas para los nombres de variable, así como es una regla usar minúsculas para los comandos. Las opciones pueden ser mayúsculas y minúsculas; la opción -a no es lo mismo que -A.
 
Las variables de ambiente pueden ser usadas como nombres de comando o como argumentos de un comando.
 XYZ="cat nota"
 $XYZ
la variable XYZ contiene un comando, y al ser invocado su contenido, el comando es ejecutado.
 
  echo hola $MUESTRA chicos
la variable puede usarse en la formación de cadenas.
  echo hola${MUESTRA}chicos
la variable puede embeberse en una cadena; las llaves delimitan el nombre de la variable.
  env
muestra las variables de ambiente definidas. Muchas son fijadas en el ingreso del usuario al sistema (variables de login); y otras son propias del shell (variables del shell).
  echo $LOGNAME
muestra el nombre de login del usuario.
  echo $HOSTNAME
muestra el nombre de la máquina.
  echo $NOEXISTE
Las variables no definidas no muestran nada cuando son referenciadas.

Entrecomillado de argumentos en la línea de comandos.

Los espacios separan argumentos. El entrecomillado obliga a tratar una cadena con espacios como si fuera un solo argumento. Cuando se usan comillas dobles (" ") el shell interpreta las variables de ambiente incluídas, actuando según su contenido:
  MUESTRA="Mi nombre de login es $LOGNAME"
  echo $MUESTRA

Cuando se usan comillas simples (' ') el shell no interpreta las variables de ambiente, tratando sus nombres como cadenas:

  MUESTRA='La variable $LOGNAME contiene su nombre de login'
  echo $MUESTRA
 
Las comillas simples permiten usar comillas dobles:
  echo '"hola chicos"'

PS1.

Aunque generalmente los omitimos, en los ejemplos de esta sección mostraremos el indicador de comandos y la salida de ejecución.

La variable símbolo de indicador de comandos nivel 1 PS1 (Prompt Symbol level 1) es un valor de ambiente que puede no aparecer en la salida de env:

  $ echo $PS1
  $
responde con el indicador de comandos actual, $.
  $ PS1=hola:
  hola:
carga un nuevo indicador de comandos; el sistema responde con el nuevo indicador de comandos, hola:.
  hola: MUESTRA="ingrese comando:"
  hola: PS1=$MUESTRA
  ingrese comando: MUESTRA=hola
  ingrese comando: echo $MUESTRA
  hola
  ingrese comando:
la variable MUESTRA cambió pero el indicador no cambió;
  ingrese comando: PS1='$'
  $
repone el indicador de comandos.

Entrada estándar y salida estándar.

Los comandos leen como entrada una secuencia de caracteres (flujo de entrada o "input stream"), y escriben a la salida otra secuencia de caracteres (flujo de salida o "output stream"). Estas secuencias no tienen estructura interna alguna, y se les llama entrada estándar y salida estándar.
  cat nota > nota2
redirige la salida estándar a un archivo que crea o sobreescribe, en vez de a la pantalla.
  mail juan < nota
toma la entrada estándar de un archivo en vez del teclado.
  pr < nota > nueva.nota
el archivo nota es la entrada, el archivo nueva.nota es la salida.
  cat nueva.nota
muestra el archivo donde se grabó la salida con formato.
 
Los símbolos < y > redirigen entrada y salida estándar:
  < nombre_entrada    redirige la entrada estándar
  > nombre_salida     redirige la salida estándar
 
  MUESTRA=/etc/passwd
  pr < $MUESTRA > lista.usuarios
  more lista.usuarios
 
Los comandos y los archivos tienen una estructura orientada a caracter. En muchos comandos se puede intercambiar teclado por archivos o dispositivos de hardware.
 
  cat nota
  cat < nota
son comandos equivalentes porque cat opera sobre un archivo y también sobre la entrada estándar.
  cat nota LEAME nueva.nota
  cat nota - nueva.nota < LEAME
son comandos equivalentes. El signo menos (-) aislado equivale a tomar en ese punto la entrada estándar, que usualmente está asignada al teclado.

Fin de flujo.

El ingreso de datos desde el teclado, así como el despliegue en pantalla, se manejan en UNIX como "flujos de caracteres", una serie de caracteres uno tras otro. Para indicar en el teclado el fin de un flujo de caracteres se usa Ctrl-D. Este símbolo no forma parte del ingreso; simplemente indica el final del ingreso, que ya no se escribirá más. En UNIX no hay un caracter especial para indicar fin de archivo; el sistema sabe cuando termina un archivo por medio de contadores.
 
 cat nota - nueva.nota > arch.salida
procesa el archivo nota, lee lo que se digite en el teclado hasta recibir un Ctrl-D, procesa nueva.copia y escribe todo en el archivo arch.salida; se reúnen tres fuentes distintas en una única salida.
  cat arch.salida
muestra todo lo reunido.

Agregar la salida estándar a un archivo.

  cat < nota > nota.copia
  cat nota nota.copia > doble.nota
  rm nota.copia
doble.nota contiene nota dos veces. Se logra lo mismo con
  cat nota > dup.nota
  cat nota >> dup.nota
El símbolo >> redirige la salida estándar a un archivo, pero agregando al final del mismo en lugar de reemplazar su contenido.

Error estándar.

Además de los flujos de entrada y salida estándar, existe un tercer flujo de caracteres, el error estándar, hacia donde se dirigen los mensajes de error. El error estándar está dirigido habitualmente a la pantalla, pero mediante 2> o 2>> se redirige el error estándar hacia un archivo de errores. Los flujos estándar se reconocen por los siguientes números:
  0   la entrada estándar, usualmente el teclado;
  1   la salida estándar, usualmente la pantalla;
  2   el error estándar, usualmente la pantalla.
 
  echo Archivo de errores > salida.error
  cat noexiste 2>>salida.error
  cat salida.error
el archivo salida.error contiene el mensaje inicial y el de error.
  ls noexiste 2>>salida.error
  rm noexiste 2>>salida.error
  cat salida.error
reúne los mensajes de error en el archivo salida.error .

Interconexión de comandos (entubamiento).

El operador | hace que la salida del comando precedente sea la entrada del comando siguiente, creando un entubamiento o interconexión de comandos.
 
  cat nota LEAME | pr > salida
hace que la concatenacion de los archivos nota y LEAME sea servida al comando pr, cuya salida está redirigida a un archivo.
  cat - LEAME < nota | pr > salida
tiene el mismo efecto. Notar la posicion de redireccion <.
 
Los operadores < y > redirigen, | conecta comandos.

Filtros.

Muchos comandos están pensados para ser interconectados, pasando simplemente la entrada hacia la salida, por lo que se les llama habitualmente filtros.
  echo 'hola chicos' | tr l p
tr traduce caracteres y produce 'hopa chicos'.
  echo 'hola chicos' | tr lo pa
produce 'hapa chicas'.

Campos y delimitadores.

Un campo es una cadena de caracteres separada por un caracter delimitador. El archivo /etc/passwd tiene en cada línea una serie de campos separados por dos puntos (:) .
  more /etc/passwd
muestra el contenido de /etc/passwd.
  cut -f1 -d: < /etc/passwd
  cut -f1,3,5 -d: < /etc/passwd
muestra los campos pedidos usando el delimitador : (dos puntos).
  cut -c1-8 < /etc/passwd
muestra columnas 1 a 8.
  ls -l | cut -c56-
corta el listado de archivos desde donde empieza el nombre al final.
  sort < /etc/passwd | cut -f1 -d: | more
ordena las líneas, corta el primer campo y presenta los nombres de usuarios habilitados en el sistema.
  env | cut -f1 -d= | sort
muestra nombres de variables de ambiente ordenadas; el separador es =.

Valores de retorno de los comandos.

Los comandos devuelven un código de retorno 0 si el comando termina correctamente, o un número entre 1 y 255 según la razón de falla. El código de retorno del último comando queda en una variable llamada '?', que se interroga como $?.
  cat noexiste
  ERROR=$?
  echo $?
  echo $ERROR
guarda el código de error; la asignación termina bien, por lo que en $? queda 0, pero en ERROR quedó el número de error de la operación fallida. $? es una 'variable de shell' mantenida internamente por el propio intérprete. Otras variables de shell son:
 
#  número de argumentos en el comando para la shell actual
$  número de proceso para el shell actual
 
Estas variables se interrogan como $# y $$.

El operador grave.

El acento grave (`) asigna a una variable de ambiente la salida estándar de un comando. El largo de la variable es limitado, pero usualmente > 5120 en SVR4.
  MUESTRA=`echo $LOGNAME`
  echo $MUESTRA
escribe el nombre de login del usuario.
  wc /etc/passw
cuenta líneas, palabras y caracteres.
 
El comando wc (word count) acepta opciones -l para líneas, -w para palabras y -c para caracteres.
  TOTALPALABRAS=`cat * | wc -w`
  echo $TOTALPALABRAS
cuenta las palabras en todos los archivos del directorio. También
  echo `cat * | wc -w`
  echo Total de palabras en el directorio: `cat * | wc -w`
 
El  acento grave permite ejecutar un comando dentro de otro, encerrando el comando anidado entre acentos graves.

Secuencias de comandos.

El shell es también un lenguaje de programación. Pueden escribirse varios comandos en una misma línea separándolos con ; (punto y coma).
  date ; echo Hola ; echo $LOGNAME
  MUESTRA=`date ; echo Hola ; echo $LOGNAME`;echo $MUESTRA

Redirección del shell.

El shell que atiende los comandos del usuario es el login shell; arranca cuando el usuario ingresa al sistema y termina cuando sale. Escribir sh como comando invoca una segunda instancia del shell, que puede terminarse con el comando exit o con <Ctrl-D>.
 
Puede crearse un archivo de comandos haciendo
  cat > datos.usuario
y escribiendo las siguientes líneas. Pueden omitirse los comentarios (de # en adelante)
  echo Salida del comando datos.usuario
  echo Fecha: `date `      # fecha y hora
  echo Usuario: $LOGNAME   # nombre de login del usuario
  ps                       # procesos corriendo del usuario
  echo Shell actual: $$    # número de proceso para el shell actual
finalizar con <Ctrl-D>. Los # indican comentario.
Para convertir el archivo en ejecutable para el usuario, hacer
 chmod u+x datos.usuario
Verificar con ls -l. Los comandos ingresados en el archivo pueden ejecutarse con
 sh datos.usuario
Este comando invoca una nueva instancia de shell que no es la del ingreso al sistema.
 
Agregar una línea más haciendo
  cat datos.usuario - >> masdatos.usuario
y escribiendo
  cat noexiste   # intenta mostrar un archivo inexistente
Finalizar con <Ctrl-D>.
 
  echo "Archivo de errores del usuario" > errores.usuario
coloca una línea descriptiva en el archivo errores.usuario.
  cat errores.usuario
verifica su contenido.
 
  sh <masdatos.usuario >salida.usuario 2>>errores.usuario
lee los comandos del archivo masdatos.usuario en la entrada estándar, redirige la salida estándar al archivo salida.usuario y redirige la salida del error estándar al archivo errores.usuario.
  cat salida.usuario
  cat errores.usuario

Fin.

Borrar con el comando rm los archivos auxiliares; conservar para referencia los archivos nota, LEAME, datos.usuario , masdatos.usuario y eventualmente otros que le interesen.

Preguntas y Ejercicios

Ejercicios Complementarios

Bibliografía y Referencias:

Comandos: cat chmod pr echo env tr cut sort wc ps
Referencias:
Coffin[1989], Greenfield[].

Páginas man/info de Linux "bash" ("Bourne-Again SHell").
 

Víctor A. González Barbone vagonbar en fing edu uy
Instituto de Ingeniería Eléctrica - Facultad de Ingeniería - Montevideo, Uruguay.