Aprendiendo_Korn_Shell/Secciones/Capitulo1.tex

783 lines
82 KiB
TeX

Usted ha utilizado su ordenador para realizar tareas sencillas, como invocar sus programas de aplicación favoritos, leer su correo electrónico y quizás examinar e imprimir archivos. Sabe que su máquina ejecuta el sistema operativo Unix, o quizá lo conozca bajo algún otro nombre, como Solaris, HP-UX, AIX o SunOS. (O puede que esté utilizando un sistema como GNU/Linux o uno de los sistemas derivados de 4.4-BSD que no está basado en el código fuente original de Unix). Pero aparte de eso, puede que no hayas pensado demasiado en lo que ocurre dentro de la máquina cuando escribes un comando y pulsas ENTER.
Es cierto que varias capas de eventos tienen lugar cada vez que introduces un comando, pero vamos a considerar sólo la capa superior, conocida como shell. En términos generales, un shell es cualquier interfaz de usuario para el sistema operativo Unix, es decir, cualquier programa que toma la entrada del usuario, la traduce en instrucciones que el sistema operativo puede entender, y transmite la salida del sistema operativo de vuelta al usuario.
Hay varios tipos de interfaz de usuario. El shell de Korn pertenece a la categoría más común, conocida como interfaces de usuario basadas en caracteres. Estas interfaces aceptan líneas de comandos textuales que el usuario escribe; normalmente producen una salida basada en texto. Otros tipos de interfaz incluyen las ahora comunes interfaces gráficas de usuario (GUI), que añaden la capacidad de mostrar gráficos arbitrarios (no sólo caracteres de máquina de escribir) y de aceptar entradas de ratones y otros dispositivos señaladores, interfaces de pantalla táctil (como las que se ven en algunos cajeros automáticos), etc.
\section{¿Qué es un Shell?}
El trabajo del shell, entonces, es traducir las líneas de comando del usuario en instrucciones del sistema operativo. Por ejemplo, considere esta línea de comando:
\begin{lstlisting}[language=bash]
sort -n phonelist > phonelist.sorted
\end{lstlisting}
Esto significa: <<Ordena las líneas del archivo \emph{phonelist} en orden numérico, y pon el resultado en el archivo \emph{phonelist.sorted}>> Esto es lo que hace el shell con este comando:
\begin{enumerate}
\item Divide la línea en los trozos \texttt{sort, -n, phonelist, >,} y \texttt{phonelist.sorted}. Estos trozos se llaman \emph{palabras}.
\item Determina el propósito de las palabras: \texttt{sort} es un comando; \texttt{-n} y \texttt{phonelist} son argumentos; \texttt{>} y \texttt{phonelist.sorted}, en conjunto, son instrucciones de E/S.
\item Establece la E/S según \texttt{> phonelist.sorted} (salida al archivo \emph{phonelist.sorted}) y algunas instrucciones estándar implícitas.
\item Busca el comando \emph{sort} en un archivo y lo ejecuta con la opción \emph{-n} (orden numérico) y el argumento \emph{phonelist} (nombre de archivo de entrada).
\end{enumerate}
Por supuesto, cada paso implica realmente varios subpasos, y cada subpaso incluye una instrucción particular al sistema operativo subyacente.
Recuerde que el shell en sí mismo no es Unix - sólo la interfaz de usuario para él. Esto se ilustra en la Figura \ref{fig1}. Unix es uno de los primeros sistemas operativos en hacer la interfaz de usuario independiente del sistema operativo.
\begin{figure}[h!]
\centering
\includegraphics[scale=1]{fig_01}
\caption{\small{El shell es una capa alrededor del sistema operativo Unix}}
\label{fig1}
\end{figure}
\section{Alcance de Este Libro}
En este libro, aprenderá sobre el shell de Korn, que es el más reciente y potente de los shells distribuidos con los sistemas Unix comerciales. Hay dos formas de utilizar el shell de Korn: como interfaz de usuario y como entorno de programación.
Este capítulo y el siguiente cubren el uso interactivo. Estos dos capítulos deberían darle suficiente información para usar el shell con confianza y de forma productiva para la mayoría de sus tareas diarias.
Después de haber utilizado el shell durante un tiempo, sin duda encontrará ciertas características de su entorno (la <<apariencia>> del shell) que le gustaría cambiar y tareas que le gustaría automatizar. El \hyperref[sec:Chapter3]{Capítulo 3} muestra varias formas de hacerlo.
El \hyperref[sec:Chapter3]{Capítulo 3} también le prepara para la programación del shell, la cual se cubre en su mayor parte en los Capítulos \hyperref[sec:Chapter4]{4} a \hyperref[sec:Chapter6]{6}. No necesita tener ninguna experiencia en programación para entender estos capítulos y aprender la programación del shell. El \hyperref[sec:Chapter7]{Capítulo 7} y el \hyperref[sec:Chapter8]{Capítulo 8} dan descripciones más completas de las capacidades de E/S y de manejo de procesos del shell, y el \hyperref[sec:Chapter9]{Capítulo 9} discute varias técnicas para encontrar y eliminar problemas en sus programas del shell.
Aprenderá mucho sobre el shell de Korn en este libro; también aprenderá sobre las utilidades de Unix y el funcionamiento del sistema operativo Unix en general. Es posible convertirse en un virtuoso programador de shell sin ninguna experiencia previa en programación. Al mismo tiempo, hemos evitado cuidadosamente bajar más allá de un cierto nivel de detalle sobre los aspectos internos de Unix. Mantenemos que no deberías ser un experto en el funcionamiento interno para usar y programar el shell de forma efectiva, y no nos detendremos en las pocas características del shell que están pensadas específicamente para los programadores de sistemas de bajo nivel.
\section{Historia de los Shells de Unix}
La independencia del shell del sistema operativo Unix en sí mismo ha llevado al desarrollo de docenas de shells a lo largo de la historia de Unix, aunque sólo unos pocos han logrado un uso generalizado.
El primer intérprete de comandos importante fue el intérprete de comandos Bourne (llamado así por su inventor, Stephen Bourne); se incluyó en la primera versión ampliamente popular de Unix, la versión 7, a partir de 1979. El shell de Bourne se conoce en el sistema como sh. Aunque Unix ha pasado por muchos, muchos cambios, el shell de Bourne sigue siendo popular y esencialmente sin cambios. Varias utilidades y funciones de administración de Unix dependen de él.
El primer shell alternativo ampliamente utilizado fue el shell C, o \emph{csh}. Fue escrito por Bill Joy en la Universidad de California en Berkeley como parte de la versión de Unix de la Berkeley Software Distribution (BSD) que salió un par de años después de la versión 7. Está incluido en casi todas las versiones recientes de Unix. (Una variante popular es el llamado Twenex \emph{csh}, \emph{tcsh}).
El shell C recibe su nombre del parecido de sus comandos con las declaraciones del lenguaje de programación C, lo que hace que el shell sea más fácil de aprender para los programadores de los sistemas Unix. Soporta una serie de características del sistema operativo (por ejemplo, el control de trabajos; véase el \hyperref[sec:Chapter8]{Capítulo 8}) que antes eran exclusivas de BSD Unix pero que ahora han migrado a casi todas las demás versiones modernas. También tiene algunas características importantes (por ejemplo, los alias; véase el \hyperref[sec:Chapter3]{Capítulo 3}) que facilitan su uso en general.
\subsection{El Shell de Korn}
El shell de Korn, o \emph{ksh}, fue inventado por David Korn de AT\&T Bell Laboratories a mediados de la década de 1980. Es casi totalmente compatible con el shell de Bourne,\footnote{Con algunas excepciones extremadamente pequeñas. Vea el \hyperref[sec:Chapter10]{Capítulo 10} para la única importante.}
lo que significa que los usuarios del shell de Bourne pueden utilizarlo inmediatamente, y todas las utilidades del sistema que utilizan el shell de Bourne pueden utilizar el shell de Korn en su lugar. De hecho, algunos sistemas tienen el shell de Korn instalado como si fuera el shell de Bourne.
El intérprete de comandos Korn comenzó su vida pública en 1986 como parte del <<Toolchest Experimental>> de AT\&T, lo que significa que su código fuente estaba disponible a muy bajo costo para cualquiera que estuviera dispuesto a usarlo sin soporte técnico y con el conocimiento de que todavía podría tener algunos errores. Finalmente, los Laboratorios de Sistemas Unix (USL) de AT\&T decidieron darle soporte completo como utilidad Unix. A partir de la versión de Unix de USL llamada System V Release 4 (SVR4 para abreviar, 1989), se distribuyó con todos los sistemas Unix de USL, todas las versiones de Unix de terceros derivadas de SVR4 y muchas otras versiones.
A finales de 1993, David Korn publicó una versión más reciente, conocida popularmente como \emph{ksh93}. Esta versión se distribuye con muchos sistemas Unix comerciales como parte del Entorno Común de Escritorio (CDE), normalmente como el <<shell de Korn de escritorio>>, \emph{/usr/dt/bin/dtksh}.
Aunque el propio Unix ha cambiado de propietario varias veces desde entonces, David Korn permaneció en los Laboratorios Bell hasta 1996, cuando AT\&T (voluntariamente, esta vez) se dividió en AT\&T Corporation, Lucent Technologies y NCR. En ese momento, se trasladó a AT\&T Research Laboratories desde Bell Labs (que siguió formando parte de Lucent). Aunque tanto Lucent como AT\&T conservaron todos los derechos del shell de Korn, todas las mejoras y cambios provienen ahora de David Korn en AT\&T.
El 1 de marzo de 2000, AT\&T liberó el código fuente de \emph{ksh93} bajo una licencia de tipo Open Source. La obtención del código fuente se discute en el \hyperref[sec:ApendiceC]{Apéndice C}, y la licencia se presenta en el \hyperref[sec:ApendiceD]{Apéndice D}.
Este libro se centra en la versión 2001 de \emph{ksh93}. Ocasionalmente, el libro señala una diferencia significativa entre las versiones de 1993 y 1988. Cuando es necesario, las distinguimos como \emph{ksh93} y \emph{ksh88}, respectivamente. En el \hyperref[sec:ApendiceA]{Apéndice A} se describen las diferencias entre las versiones de 1988 y 1993 de forma ordenada, y en ese apéndice también se resumen brevemente otras versiones del shell.
\subsection{Características del Shell Korn}
Aunque el shell de Bourne sigue siendo conocido como el shell <<estándar>>, el shell de Korn también es popular. Además de su compatibilidad con el shell de Bourne, incluye las mejores características del shell C, así como varias ventajas propias. También se ejecuta de forma más eficiente que cualquier shell anterior.
Los modos de edición de la línea de comandos del shell de Korn son las características que suelen atraer a la gente al principio. Con la edición de la línea de comandos, es mucho más fácil volver atrás y corregir errores que con el mecanismo de historial del shell C -- y el shell de Bourne no permite hacer esto en absoluto.
La otra característica principal del shell de Korn que está pensada principalmente para los usuarios interactivos es el control de trabajos. Como se explica en el \hyperref[sec:Chapter8]{Capítulo 8}, el control de trabajos le da la capacidad de parar, iniciar y pausar cualquier número de comandos al mismo tiempo. Esta característica fue tomada casi literalmente del shell C.
El resto de las ventajas importantes del shell de Korn están destinadas principalmente a los personalizadores y programadores del shell. Tiene muchas opciones y variables nuevas para la personalización, y sus características de programación se han ampliado significativamente para incluir la definición de funciones, más estructuras de control, expresiones regulares y aritmética incorporadas, matrices asociativas, variables estructuradas, control avanzado de E/S, y más.
\section{Cómo Obtener el Shell Korn de 1993}
Este libro cubre la versión de 1993 del shell de Korn. Gran parte de lo que se cubre es exclusivo de ese shell; un subconjunto de lo que es exclusivo se aplica sólo a las versiones recientes disponibles directamente de AT\&T. Para hacer un mejor uso de este libro, debería estar usando el shell de Korn de 1993. Utilice la siguiente secuencia de instrucciones para determinar qué shell tiene actualmente y si el shell de Korn de 1993 existe en su sistema, y para hacer que el shell de Korn de 1993 sea su shell de inicio de sesión.
\begin{enumerate}
\item{Determine qué shell está utilizando. La variable SHELL indica su shell de inicio de sesión. Entre en su sistema y escriba \emph{echo \$SHELL} en el prompt. Verá una respuesta que contiene sh, \emph{csh}, o \emph{ksh}; estos denotan los shells Bourne, C, y Korn, respectivamente. (También es muy probable que esté utilizando un shell de terceros como bash o tcsh). Si la respuesta es \emph{ksh}, vaya al paso 3. De lo contrario, continúe con el paso 2.}
\item{Vea si existe alguna versión de \emph{ksh} en su sistema en un directorio estándar. Escriba \emph{ksh}. Si eso funciona (imprime un prompt \$), tiene una versión del shell de Korn; continúe con el paso 3. De lo contrario, continúe con el paso 5.}
\item{Compruebe la versión. Escriba \emph{echo \${.sh.version}}. Si eso imprime una versión, está todo listo; omita el resto de estas instrucciones. De lo contrario, continúe con el paso 4.}
\item{No tiene la versión 1993 del shell de Korn. Para saber qué versión tienes, escribe el comando \emph{set -o emacs}, y luego presiona CTRL-V. Esto te dirá si tienes la versión de 1988 o el shell de Korn de dominio público. En cualquier caso, continúe con el paso 5.}
\item{Escribe el comando \texttt{/usr/dt/bin/dtksh}. Si esto le da un prompt \emph{\$}, usted tiene el Desktop Korn Shell, que está basado en una versión temprana de \emph{ksh93}. Puede utilizar esta versión; casi todo lo que se dice en este libro funcionará. Vaya al paso 7.}
\item{Necesita descargar una versión ejecutable de \emph{ksh93} o descargar el código fuente y construir un ejecutable a partir de él. Estas tareas se describen en el \hyperref[sec:ApendiceC]{Apéndice C}. Lo mejor sería solicitar la ayuda de su administrador de sistemas para este paso. Una vez que tenga un \emph{ksh93} que funcione, continúe con el paso 7.}
\item{Instale \emph{ksh93} como su shell de inicio de sesión. Hay dos situaciones; elija la que le convenga:}
\begin{description}
\item[Sistema monousuario] En un sistema monousuario, en el que usted es el administrador, probablemente tendrá que añadir la ruta completa a \emph{ksh93} al archivo \emph{/etc/shells} como primer paso. Luego, debería poder cambiar su shell de inicio de sesión escribiendo \emph{chsh nombre-k}, donde \emph{nombre-k} es la ruta completa al ejecutable \emph{ksh93}. Si esto funciona, se te pedirá tu contraseña. Escriba su contraseña, salga y vuelva a entrar para empezar a usar el shell de Korn. \\
Si \emph{chsh} no existe o no funciona, consulte la página man de \emph{passwd(1)}. Busque las opciones \emph{-e} o \emph{-s} para actualizar la información de su archivo de contraseñas. Utilice lo que sea apropiado para su sistema para cambiar su shell de inicio de sesión. \\
Si nada de lo anterior funciona, puede recurrir a editar el archivo \emph{/etc/passwd} mientras está conectado como root. Si tienes el comando vipw(8), deberías usarlo para editar tu archivo de contraseñas. Si no, edita el archivo manualmente con tu editor de texto favorito.
\item[Sistema multiusuario grande] Esta situación es aún más compleja que el caso de un solo usuario. Lo mejor es dejar que el administrador del sistema se encargue de cambiar el shell por ti. La mayoría de las instalaciones grandes tienen un <<servicio de ayuda>> (accesible por correo electrónico o por teléfono, o ambos) para introducir dichas solicitudes.
\end{description}
\end{enumerate}
\section{Uso Interactivo del Shell}
Cuando usas el shell de forma interactiva, entras en una sesión de inicio de sesión que comienza cuando te conectas y termina cuando sales o presionas CTRL-D.\footnote{Puedes configurar tu shell para que no acepte CTRL-D, es decir, que requiera que escribas \texttt{exit} para terminar tu sesión. Recomendamos esto, porque CTRL-D es demasiado fácil de escribir por accidente; vea la sección de opciones en el \hyperref[sec:Chapter3]{Capítulo 3}.}
Durante una sesión de inicio de sesión, escribes líneas de comando en el shell; estas son líneas de texto que terminan en ENTER y que escribes en tu terminal o estación de trabajo.\footnote{Aunque asumimos que hay pocas personas que todavía usan terminales seriales reales, los sistemas modernos de ventanas proporcionan acceso al shell a través de un emulador de terminal. Por lo tanto, al menos cuando se trata del uso interactivo del shell, el término <<terminal>> se aplica igualmente a un entorno de ventanas.}
Por defecto, el shell te pide cada comando con un signo de dólar, aunque, como verás en el \hyperref[sec:Chapter3]{Capítulo 3}, el prompt puede ser cambiado.
\subsection{Comandos, Argumentos y Opciones}
Las líneas de comandos del shell consisten en una o más palabras, que se separan en una línea de comandos por espacios o TABs. La primera palabra de la línea es el comando. El resto (si lo hay) son argumentos (también llamados parámetros) del comando, que son nombres de cosas sobre las que actuará el comando.
Por ejemplo, la línea de comandos \texttt{lpr myfile} está formada por el comando \emph{lpr} (imprimir un archivo) y el único argumento \emph{myfile}. \emph{lpr} trata \emph{myfile} como el nombre de un archivo a imprimir. Los argumentos suelen ser nombres de archivos, pero no necesariamente: en la línea de comandos \texttt{mail billr}, el programa de correo trata a \emph{billr} como el nombre del usuario al que se enviará un mensaje.
Una opción es un tipo especial de argumento que da al comando información específica sobre lo que debe hacer. Las opciones suelen consistir en un guión seguido de una letra; decimos <<suelen>> porque se trata de una convención más que de una regla rígida. El comando \texttt{lpr -h miarchivo} contiene la opción \emph{-h}, que le dice a \emph{lpr} que no imprima la <<página de bandera>> antes de imprimir el archivo.
A veces las opciones tienen sus propios argumentos. Por ejemplo, \texttt{lpr -P hp3si -h miarchivo} tiene dos opciones y un argumento. La primera opción es \emph{-P hp3si} , que significa <<Enviar la salida a la impresora llamada hp3si>>. La segunda opción y el argumento son como los anteriores.
\subsection{Ayuda Incorporada (Built-in)}
Casi todos los comandos incorporados en \emph{ksh} tienen ayuda <<en línea>> tanto mínima como más extensa. Si le das a un comando la opción -?, imprime un breve resumen de uso:
\begin{lstlisting}[language=bash, escapeinside={(*}{*)}]]
$ (*\textbf{cd -?}*)
Usage: cd [-LP] [directory]
Or: cd [ options ] old new
\end{lstlisting}
(Es posible que desee citar la \texttt{?}, ya que, como veremos más adelante, es especial para el shell). También puede dar la opción \emph{--man} para imprimir la ayuda en la forma de la tradicional página man de Unix\footnote{A partir de \emph{ksh93i}.}
La salida usa secuencias de escape estándar ANSI para producir un cambio visible en la pantalla, representado aquí usando una fuente en negrita:
\begin{lstlisting}[language=bash, escapeinside={(*}{*)}]]
$ (*\textbf{cd --man}*)
NAME
cd - change working directory
SYNOPSIS
(*\textbf{cd} [ \textbf{options}*) ] [directory]
(*\textbf{cd} [ \textbf{options}*) ] old new
DESCRIPTION
(*\textbf{cd}*) changes the current working directory of the current shell
environment.
In the first form with one operand, if (*\textbf{directory}*) begins with /,
or if the first component is . or .., the directory will be
changed to this directory...
\end{lstlisting}
Del mismo modo, la opción \emph{--html} produce la salida en formato HTML para su posterior renderización con un navegador web.
Por último, la opción \emph{--nroff} le permite producir la ayuda de cada comando en forma de entrada \texttt{nroff -man}\footnote{Todas las opciones de ayuda envían su salida a error estándar (que se describe más adelante en este capítulo). Esto significa que tiene que usar las facilidades del shell que no cubriremos hasta el \hyperref[sec:Chapter7]{Capítulo 7} para capturar su salida. Por ejemplo, \texttt{cd --man 2>\&1 | more} ejecuta la ayuda en línea a través del programa paginador \emph{more.}},
lo que resulta práctico para dar formato a la ayuda para la salida impresa.
Para cumplir con POSIX, algunos comandos no aceptan estas opciones: \emph{echo, false, jobs, login, newgrp, true} y \emph{:}. Para \emph{test}, tienes que escribir \texttt{test - -man - -} para obtener la ayuda en línea.
\section{Ficheros}
Aunque los argumentos de los comandos no siempre son ficheros, los ficheros son los tipos de <<cosas>> más importantes en cualquier sistema Unix. Un archivo puede contener cualquier tipo de información, y hay diferentes tipos de archivos. Cuatro tipos son, con mucho, los más importantes:
\begin{description}
\item[Archivos normales] También llamados \emph{archivos de texto}; contienen caracteres legibles. Por ejemplo, este libro se creó a partir de varios archivos regulares que contienen el texto del libro más instrucciones de formato DocBook XML legibles por humanos.
\item[Archivos ejecutables] También llamados programas; se invocan como comandos. Algunos no pueden ser leídos por humanos; otros - los scripts del shell que examinaremos en este libro - son sólo archivos de texto especiales. El propio shell es un archivo ejecutable (no legible por humanos) llamado \emph{ksh}.
\item[Directorios] Como carpetas que contienen otros archivos - posiblemente otros directorios (llamados subdirectorios).
\item[Enlaces simbólicos] Una especie de <<atajo>> de un lugar a otro en la jerarquía de directorios del sistema. Veremos más adelante en este capítulo cómo los enlaces simbólicos pueden afectar al uso interactivo del shell de Korn.
\end{description}
\subsection{Directorios}
Repasemos los conceptos más importantes sobre los directorios. El hecho de que los directorios puedan contener otros directorios da lugar a una estructura jerárquica, más popularmente conocida como árbol, para todos los ficheros de un sistema Unix. La Figura \ref{fig2} muestra parte de un árbol de directorios típico; los óvalos son ficheros normales y los rectángulos son directorios.
\begin{figure}[h!]
\centering
\includegraphics[scale=1]{fig_02}
\caption{\small{Árbol de directorios y archivos}}
\label{fig2}
\end{figure}
La parte superior del árbol es un directorio llamado <<raíz>> o <<\emph{root}>> que no tiene nombre en el sistema\footnote{La mayoría de los tutoriales introductorios de Unix dicen que \emph{root} tiene el nombre /. Nos quedamos con esta explicación alternativa porque es más consistente lógicamente.}.
Todos los archivos pueden nombrarse expresando su ubicación en el sistema en relación con la raíz; dichos nombres se construyen enumerando todos los nombres de directorio (en orden desde la raíz), separados por barras (/), seguidos del nombre del archivo. Esta forma de nombrar los archivos se denomina \emph{ruta completa (o absoluta)}.
Por ejemplo, supongamos que hay un archivo llamado \emph{memo} en el directorio \emph{fred}, que está en el directorio \emph{home}, que está en el directorio raíz. La ruta completa de este fichero es \texttt{/home/fred/memo}.
\subsubsection{El Directorio de Trabajo}
Por supuesto, es molesto tener que utilizar nombres de ruta completos cada vez que necesitas especificar un archivo, por lo que también existe el concepto de \emph{directorio de trabajo} (a veces llamado \emph{directorio actual}), que es el directorio en el que te encuentras en un momento dado. Si se da un nombre de ruta sin barra inicial, la ubicación del archivo se calcula en relación con el directorio de trabajo. Este tipo de nombres de ruta se denominan nombres de ruta relativos; los utilizarás con mucha más frecuencia que los nombres de ruta completos.
Cuando te conectas al sistema, tu directorio de trabajo se establece inicialmente en un directorio especial llamado tu directorio personal (o \emph{de inicio de sesión}). Los administradores de sistemas a menudo configuran el sistema para que el nombre del directorio personal de cada usuario sea el mismo que su nombre de inicio de sesión, y todos los directorios personales están contenidos en un directorio común bajo \emph{root}. En la actualidad, es habitual utilizar \emph{/home} como directorio principal para los directorios personales.
Por ejemplo, \emph{/home/billr} es un directorio personal típico. Si este es tu directorio de trabajo y das el comando \texttt{lp memo}, el sistema busca el archivo memo en \emph{/home/billr}. Si tienes un directorio llamado bob en tu directorio personal, y contiene el archivo statrpt, puedes imprimir \emph{statrpt} con el comando \texttt{lp bob/statrpt}.
\subsubsection{Notación con tilde}
Como puedes imaginar, los directorios personales aparecen a menudo en los nombres de ruta. Aunque muchos sistemas están organizados de forma que todos los directorios personales tienen un directorio principal común (como \emph{/home}), no debería depender de que esto sea así, ni siquiera debería saber cuál es el nombre absoluto del directorio personal de alguien.
Por lo tanto, el shell de Korn tiene una forma de abreviar los directorios home: basta con preceder el nombre del usuario con una tilde (\textasciitilde). Por ejemplo, puedes referirte al archivo memo en el directorio personal del usuario fred como \emph{\textasciitilde{} fred/memo}. Se trata de una ruta absoluta, por lo que no importa cuál sea tu directorio de trabajo cuando la utilices. Si el directorio personal de fred tiene un subdirectorio llamado bob y el archivo está allí, puedes usar \emph{\textasciitilde{} fred/bob/memo} como nombre.
Aún más conveniente, una tilde por sí misma se refiere a su propio directorio personal. Puede referirse a un archivo llamado \emph{notas} en su directorio personal como \emph{\textasciitilde{} /notas} (observe la diferencia entre eso y \emph{\textasciitilde{} notas}, que el shell trataría de interpretar como el directorio personal del usuario notas). Si \emph{notes} está en tu subdirectorio bob, puedes llamarlo \emph{\textasciitilde{} /bob/notes}. Esta notación es más útil cuando su directorio de trabajo no está en su árbol de directorios personales, por ejemplo, cuando es algún directorio del <<sistema>> como \emph{/tmp}.
\subsubsection{Cambiar los Directorios de Trabajo}
Si desea cambiar su directorio de trabajo, utilice el comando \emph{cd}. Si no recuerda su directorio de trabajo, el comando \emph{pwd} indica al shell que lo imprima.
\emph{cd} toma como argumento el nombre del directorio que desea que se convierta en su directorio de trabajo. Puede ser relativo a su directorio actual, puede contener una tilde, o puede ser absoluto (comenzando con una barra). Si omite el argumento, \emph{cd} cambia a su directorio personal (es decir, es lo mismo que \texttt{cd \~ }).
La Tabla \ref{tab1} muestra algunos ejemplos de comandos \emph{cd}. Cada comando asume que tu directorio de trabajo es \emph{/home/billr} justo antes de que se ejecute el comando, y que tu estructura de directorios se parece a la Figura \ref{fig2}.
\begin{table}[h]
\center
\caption{Ejemplos de comandos cd}
\label{tab1}
\begin{tabular}{m{4cm}|m{4cm}} \hline
\textbf{Comando} & \textbf{Nuevo directorio de trabajo} \\ \hline
\texttt{cd bob} & \emph{/home/billr/bob} \\
\texttt{cd bob/dave} & \emph{/home/billr/bob/dave} \\
\texttt{cd \textasciitilde{}/bob/dave} & \emph{/home/billr/bob/dave} \\
\texttt{cd /usr/lib} & \emph{/usr/lib} \\
\texttt{cd ..} & \emph{/home} \\
\texttt{cd ../pete} & \emph{/home/pete} \\
\texttt{cd \textasciitilde{}pete} & \emph{/home/pete} \\
\texttt{cd billr pete} & \emph{/home/pete} \\
\texttt{cd illr arry} & \emph{/home/barry} \\
\end{tabular}
\end{table}
Los cuatro primeros son sencillos. Los dos siguientes utilizan un directorio especial llamado \texttt{..} (dos puntos, pronunciado <<dot dot>>), que significa <<padre de este directorio>>. Todos los directorios tienen uno de estos; es una forma universal de llegar al directorio situado por encima del actual en la jerarquía, que se denomina directorio padre.
Cada directorio también tiene el directorio especial . (punto simple), que sólo significa <<este directorio>>. Por lo tanto, \texttt{cd .} efectivamente no hace nada. Tanto . como .. son en realidad ficheros especiales ocultos en cada directorio que apuntan al propio directorio y a su directorio padre, respectivamente. El directorio raíz es su propio directorio padre.
Los dos últimos ejemplos de la tabla utilizan una nueva forma del comando \emph{cd}, que no está incluida en la mayoría de los shells Bourne. La forma es \texttt{cd viejo nuevo}. Toma la ruta completa del directorio de trabajo actual e intenta encontrar la cadena \emph{old} en ella. Si encuentra la cadena, la sustituye por \emph{new} y cambia al directorio resultante.
En el primero de los dos ejemplos, el shell sustituye \emph{pete} por \emph{billr} en el nombre del directorio actual y convierte el resultado en el nuevo directorio actual. El último ejemplo muestra que la sustitución no necesita ser un nombre de archivo completo: al sustituir \emph{arry} por \emph{illr} en \emph{/home/billr} se obtiene \emph{/home/barry}. (Si no se puede encontrar la cadena antigua en el nombre del directorio actual, el intérprete de comandos imprime un mensaje de error).
Otra característica del comando \emph{cd} del shell de Korn es la forma \texttt{cd -}, que cambia al directorio en el que se encontraba antes del actual. Por ejemplo, si empiezas en \emph{/usr/lib}, escribes \texttt{cd} sin un argumento para ir a tu directorio personal, y luego escribes \texttt{cd -}, estarás de vuelta en \emph{/usr/lib}.
\subsubsection{Enlaces Simbólicos a Directorios}
Los sistemas Unix modernos ofrecen \emph{enlaces simbólicos}. Los enlaces simbólicos (a veces llamados \emph{enlaces blandos}) proporcionan una especie de <<acceso directo>> a los archivos en una parte diferente de la jerarquía de archivos del sistema. Se puede crear un enlace simbólico a un fichero o a un directorio, utilizando nombres de ruta completos o relativos. Cuando se accede a un fichero o directorio mediante un enlace simbólico, Unix <<sigue el enlace>> hasta el fichero o directorio real.
Los enlaces simbólicos a directorios pueden generar comportamientos sorprendentes. Para explicar por qué, vamos a empezar asumiendo que estás usando el shell de Bourne normal, sh.\footnote{Si tienes un sistema donde el shell de Korn está instalado como /bin/sh, este ejemplo no funcionará}
Ahora, supongamos que nosotros y el usuario fred estamos trabajando juntos en un proyecto, y el directorio primario para el proyecto está bajo su directorio personal, digamos \texttt{/home/fred/projects/} \texttt{important/wonderprog}. Es un nombre de ruta bastante largo, incluso usando la notación con tilde (que no podemos usar en el shell de Bourne, pero eso es otra historia). Para hacer la vida más fácil, vamos a crear un enlace simbólico al directorio \emph{wonderprog} en nuestro directorio personal:
\begin{lstlisting}[language=bash, escapeinside={(*}{*)}]]
$ (*\textbf{sh} \emph{Utilizar el shell de Bourne}*)
$ (*\textbf{cd} \emph{Asegurarse de que se estamos en nuestro directorio de inicio}*)
$ (*\textbf{pwd} \emph{Mostrar el directorio en el que estamos}*)
/home/billr
(*\emph{Crear el enlace suave}*)
$ (*\textbf{ln -s /home/fred/projects/important/wonderprog wonderprog}*)
\end{lstlisting}
Ahora, cuando escribimos \texttt{cd wonderprog}, terminamos en \texttt{/home/fred/projects/important} \texttt{/wonderprog}:
\begin{lstlisting}[language=bash]
$ cd wonderprog
$ pwd
/home/fred/projects/important/wonderprog
\end{lstlisting}
Después de trabajar un rato añadiendo nuevas e importantes características\footnote{Las <<importantes>> son las que desea el departamento de marketing, las necesiten o no los clientes.} a \emph{wonderprog}, recordamos que necesitamos actualizar el archivo \emph{.profile} en nuestro directorio home. No hay problema: simplemente \emph{cd} de nuevo allí y empezar a trabajar en el archivo, mirándolo primero con \emph{more}.
\begin{lstlisting}[language=bash]
$ cd ..
Retrocedemos un nivel
$ more .profile
Observamos .profile
.profile: No such file or directory
\end{lstlisting}
¿Qué ha pasado? El \texttt{cd ..} no nos llevó de vuelta por donde vinimos. En su lugar, subió un nivel en la jerarquía \emph{física} del sistema de archivos:
\begin{lstlisting}[language=bash]
$ pwd
/home/fred/projects/important
\end{lstlisting}
Este es el <<problema>> de los enlaces simbólicos: la visión lógica de la jerarquía del sistema de ficheros que presenta un enlace simbólico a un directorio se rompe con la realidad física subyacente cuando se accede al directorio padre.
El shell de Korn funciona de forma diferente. Entiende los enlaces simbólicos y, por defecto, siempre te presenta una vista lógica del sistema de ficheros. No sólo \emph{cd} está integrado en el shell, sino también \emph{pwd}. Ambos comandos aceptan las mismas dos opciones: \emph{-L}, para realizar operaciones lógicas (por defecto), y \emph{-P}, para realizar las operaciones en los directorios reales. Empecemos de nuevo en el shell de Korn:
\begin{lstlisting}[language=bash]
$ cd wonderprog ; pwd
# cd a traves del enlace simbolico
/home/billr/wonderprog # La respuesta es la ubicacion logica
$ pwd -P
# Cual es la ubicacion fisica
/home/fred/projects/important/wonderprog # La respuesta es la ubicacion fisica
$ cd .. ; pwd
# Sube un nivel
/home/billr # El trayecto fue de nuevo logico
$ cd -P wonderprog; pwd
# Hacer un cd fisico
/home/fred/projects/important/wonderprog # logico es ahora igual a fisico
cd .. ; pwd
# Vuelve a subir un nivel
/home/fred/projects/important # logico sigue siendo igual a fisico
\end{lstlisting}
Como se muestra, la opción \emph{-P} de \emph{cd} y \emph{pwd} le permite <<evitar>> el uso por defecto del posicionamiento lógico del shell de Korn. La mayoría de las veces, sin embargo, el posicionamiento lógico es exactamente lo que quieres.
\textbf{NOTA}: El intérprete de comandos establece las variables PWD y OLDPWD de forma correspondiente cada vez que se realiza un \emph{cd}; los resultados de escribir \emph{pwd} y \emph{print \$PWD} deberían ser siempre los mismos.
Como nota no relacionada que redondea la discusión, los sistemas Unix también proporcionan <<enlaces duros>> (o simplemente \emph{enlaces}) a los archivos. Cada nombre para un fichero se llama enlace; todos los enlaces duros se refieren a los mismos datos en el disco, y si el fichero cambia de nombre, ese cambio se ve al mirarlo desde un nombre diferente. Los enlaces duros tienen ciertas restricciones, que los enlaces simbólicos superan. (Véase \emph{ln(1)} para más información). Sin embargo, no puedes hacer enlaces duros a directorios, así que los enlaces simbólicos son todo lo que importa para \emph{cd} y \emph{pwd}.
\subsection{Nombres de Archivo y Comodines}
A veces es necesario ejecutar un comando en más de un archivo a la vez. El ejemplo más común de este tipo de órdenes es \emph{ls}, que muestra información sobre los ficheros. En su forma más simple, sin opciones ni argumentos, enumera los nombres de todos los archivos del directorio de trabajo excepto los archivos ocultos especiales, cuyos nombres empiezan por un punto (.).
Si le das a \emph{ls} argumentos de nombre de archivo, listará esos archivos, lo cual es un poco tonto: si tu directorio actual tiene los archivos bob y fred, y escribes \texttt{ls bob fred}, el sistema simplemente te devolverá los nombres de los archivos.
En realidad, \texttt{ls} se usa más a menudo con opciones que le dicen que liste información sobre los ficheros, como la opción \emph{-l} (long), que le dice a \emph{ls} que liste el propietario del fichero, el grupo, el tamaño, la hora de la última modificación y otra información, o \emph{-a} (all), que también lista los ficheros ocultos descritos anteriormente. Pero a veces quieres verificar la existencia de un determinado grupo de archivos sin tener que saber todos sus nombres; por ejemplo, si diseñas páginas web, puede que quieras ver qué archivos de tu directorio actual tienen nombres que terminan en \emph{.html}.
Los nombres de fichero son tan importantes en Unix que el shell proporciona una forma integrada de especificar el patrón de un conjunto de nombres de fichero sin tener que conocer todos los nombres en sí. Puede utilizar caracteres especiales, llamados \emph{comodines}, en los nombres de archivo para convertirlos en patrones. Mostraremos los tres tipos básicos de comodines que soportan los principales shells de Unix, y dejaremos el conjunto de operadores comodín avanzados del shell de Korn para el \hyperref[sec:Chapter4]{Capítulo 4}. La Tabla \ref{tab2} lista los comodines básicos.
\begin{table}[h]
\center
\caption{Comodines básicos}
\label{tab2}
\begin{tabular}{m{2cm}|m{8cm}} \hline
\textbf{Comodín} & \textbf{Coincidencia} \\ \hline
? & Cualquier carácter \\
\texttt{*} & Cualquier cadena de caracteres \\
\texttt{[set]} & Cualquier caracter del conjunto \\
\texttt{[!set]} & Cualquier carácter no incluido en el conjunto \\
\end{tabular}
\end{table}
El comodín \texttt{?} coincide con cualquier carácter, de modo que si el directorio contiene los archivos \emph{program.c, program.log} y \emph{program.o}, la expresión \texttt{program.?} coincide con \emph{program.c} y \emph{program.o}, pero no con \emph{program.log}.
El asterisco (*) es más potente y se utiliza mucho más; coincide con cualquier cadena de caracteres. La expresión \texttt{program.*} coincidirá con los tres archivos del párrafo anterior; los diseñadores web pueden utilizar la expresión \texttt{*.html} para coincidir con sus archivos de entrada\footnote{Los usuarios de MS-DOS, Windows y OpenVMS deben tener en cuenta que el punto (.) no tiene nada de especial en los nombres de archivo Unix (aparte del punto inicial, que <<oculta>> el archivo); es simplemente otro carácter. Por ejemplo, ls * lista todos los ficheros del directorio actual; no se necesita *.* como en otros sistemas.}.
La Tabla \ref{tab3} debería darte una mejor idea de cómo funciona el asterisco. Suponga que tiene los archivos \emph{bob, darlene, dave, ed, frank} y \emph{fred} en su directorio de trabajo.
Observe que * puede no significar nada: tanto \texttt{*ed} como \texttt{*e*} coinciden con \emph{ed}. Observe también que el último ejemplo muestra lo que hace el intérprete de comandos si no puede encontrar ninguna coincidencia: simplemente deja la cadena con el comodín intacta.
\begin{table}[h]
\center
\caption{Usando el comodín *}
\label{tab3}
\begin{tabular}{p{3cm}|p{6cm}} \hline
\textbf{Expresión} & \textbf{Campos} \\ \hline
fr* & frank fred \\
*ed & ed fred \\
b* & bob \\
*e* & darlene dave ed fred \\
*r* & darlene frank fred \\
\texttt{*} & bob darlene dave ed frank fred \\
d*e & darlene dave \\
g* & g*
\end{tabular}
\end{table}
Los archivos se guardan dentro de los directorios en un orden no especificado; el shell ordena los resultados de cada expansión de comodines. (En algunos sistemas, la ordenación puede estar sujeta a un orden apropiado para la ubicación del sistema, pero que es diferente del orden de cotejo subyacente de la máquina. Los tradicionalistas de Unix pueden utilizar \texttt{export LANG=C} para obtener el comportamiento al que están acostumbrados).
El comodín restante es la construcción set. Un conjunto es una lista de caracteres (por ejemplo, abc), un rango inclusivo (por ejemplo, a-z) o una combinación de ambos. Si desea que el guión forme parte de una lista, sólo tiene que ponerlo en primer o último lugar. La Tabla \ref{tab4} (que asume un entorno ASCII) debería explicar las cosas más claramente.
\begin{table}[h]
\center
\caption{Uso de los comodines de construcción de conjuntos}
\label{tab4}
\begin{tabular}{m{3cm}|m{10cm}} \hline
\textbf{Expresión} & \textbf{Coincidencia} \\ \hline
\texttt{[abc]} & a, b, ó c \\
\texttt{[.,;]} & punto, coma o punto y coma \\
\texttt{[\texttt{-}\_]} & Guión medio o guión bajo \\
\texttt{[a-c]} & a, b ó c \\
\texttt{[a-z]} & Todas las letras minúsculas \\
\texttt{[!0-9]} & Todos los no dígitos \\
\texttt{[0-9!]} & Todos los dígitos y signos de exclamación \\
\texttt{[a-zA-Z]} & Todas las letras mayúsculas y minúsculas \\
\texttt{[a-zA-Z0-9\_\texttt{-}]} & Todas las letras, todos los dígitos, guión bajo y guión \\
\end{tabular}
\end{table}
En el ejemplo del comodín original, \texttt{program.[co]} y \texttt{program.[a-z]} coinciden con \emph{program.c} y \emph{program.o}, pero no con \emph{program.log}.
Un signo de exclamación tras el corchete izquierdo permite <<negar>> un conjunto. Por ejemplo, \texttt{[!.;]} coincide con cualquier carácter excepto punto y coma; \texttt{[!a-zA-Z]} coincide con cualquier carácter que no sea una letra.
La notación de rango es útil, pero no debe hacer demasiadas suposiciones sobre los caracteres que se incluyen en un rango. Por lo general, es seguro utilizar un rango para letras mayúsculas, minúsculas, dígitos o cualquier subrango de éstos (por ejemplo, \texttt{[f-q], [2-6]}). No utilices rangos en caracteres de puntuación o letras mixtas: por ejemplo, no se debe confiar en que \texttt{[a-Z]} y \texttt{[A-z]} incluyan todas las letras y nada más. El problema es que esos rangos no son del todo portables entre distintos tipos de ordenadores\footnote{En concreto, los rangos dependen del esquema de codificación de caracteres que utilice tu ordenador. La gran mayoría utiliza ASCII, pero los mainframes IBM utilizan EBCDIC. (En realidad, en los sistemas EBCDIC, ni siquiera las mayúsculas y minúsculas forman un rango contiguo).}.
Otro problema es que los sistemas modernos admiten diferentes configuraciones regionales, que son formas de describir cómo funciona el juego de caracteres local. En la mayoría de los países, el conjunto de caracteres por defecto de la configuración regional es diferente al del ASCII plano. En el \hyperref[sec:Chapter4]{Capítulo 4}, le mostramos cómo usar expresiones POSIX entre corchetes para denotar letras, dígitos, puntuación y otros tipos de caracteres de una forma portable.
El proceso de hacer coincidir expresiones que contienen comodines con nombres de archivo se denomina \emph{expansión de comodines}. Este es sólo uno de los varios pasos que da el shell al leer y procesar una línea de órdenes; otro que ya hemos visto es la \emph{expansión de tildes}, en la que las tildes se sustituyen por directorios de inicio cuando procede. Veremos otros en capítulos posteriores, y los detalles completos del proceso se enumeran en el \hyperref[sec:Chapter7]{Capítulo 7}.
Sin embargo, es importante tener en cuenta que los comandos que ejecutas sólo ven los resultados de la expansión de comodines. (De hecho, esto es cierto para todas las expansiones.) Es decir, sólo ven una lista de argumentos, y no tienen conocimiento de cómo surgieron esos argumentos. Por ejemplo, si escribe \texttt{ls fr*} y sus archivos son como los descritos anteriormente, entonces el shell expande la línea de comandos a \texttt{ls fred frank} e invoca el comando \emph{ls} con los argumentos \emph{fred} y \emph{frank}. Si escribe \texttt{ls g*}, entonces (porque no hay coincidencia) \emph{ls} recibirá la cadena literal \texttt{g*} y se quejará con el mensaje de error, \texttt{g* no encontrado}. \footnote{Esto es diferente del mecanismo de comodines del shell de C, que imprime un mensaje de error y no ejecuta el comando en absoluto.} (Es probable que el mensaje real varíe de un sistema a otro).
He aquí otro ejemplo que le ayudará a entender por qué esto es importante. Supongamos que eres un programador en C. Esto significa que trabajas con archivos cuyos nombres terminan en \texttt{.c} (programas, también conocidos como archivos fuente), \texttt{.h} (archivos de cabecera para programas) y \texttt{.o} (archivos de código objeto que no son legibles por humanos), así como otros archivos.
Supongamos que quieres listar todos los archivos fuente, objeto y de cabecera de tu directorio de trabajo. El comando \texttt{ls *.[cho]} hace el truco. El shell expande \texttt{*.[cho]} a todos los archivos cuyos nombres terminan en un punto seguido de una \texttt{c, h}, u \texttt{o} y pasa la lista resultante a \emph{ls} como argumentos.
En otras palabras, \emph{ls} verá los nombres de los ficheros como si se hubieran tecleado individualmente - ¡pero fíjese que no hemos asumido ningún conocimiento de los nombres reales de los ficheros! Dejamos que los comodines hagan el trabajo.
A medida que adquiera experiencia con el shell, reflexione sobre cómo sería la vida sin comodines. Bastante miserable, diríamos nosotros.
Una nota final sobre los comodines. Puede asignar a la variable \texttt{FIGNORE} un patrón del shell que describa los nombres de archivo que deben ignorarse durante la comparación de patrones. (Las capacidades completas de patrones del shell se describen más adelante, en el \hyperref[sec:Chapter4]{Capítulo 4}.) Por ejemplo, \emph{emacs} guarda copias de seguridad de archivos añadiendo un \texttt{\~} al nombre original. A menudo, no necesitas ver estos archivos. Para ignorarlos, puedes añadir lo siguiente a tu archivo \emph{.profile}:
\begin{lstlisting}[language=bash]
export FIGNORE='*~'
\end{lstlisting}
Al igual que con la expansión de comodines, la prueba contra FIGNORE se aplica a todos los componentes de un nombre de ruta, no sólo al final.
\section{Entrada y Salida}
El campo del software -en realidad, cualquier campo científico- tiende a avanzar de forma más rápida e impresionante en esas pocas ocasiones en las que a alguien (es decir, no a un comité) se le ocurre una idea pequeña en concepto pero enorme en sus implicaciones. El esquema de entrada y salida estándar de Unix tiene que estar en la lista corta de tales ideas, junto con innovaciones clásicas como el lenguaje LISP, el modelo de datos relacional y la programación orientada a objetos.
El esquema de E/S de Unix se basa en dos ideas deslumbrantemente simples. En primer lugar, la E/S de archivos Unix adopta la forma de secuencias arbitrariamente largas de caracteres (bytes). Por el contrario, los sistemas de archivos más antiguos tienen esquemas de E/S más complicados (por ejemplo, <<bloque>>, <<registro>>, <<imagen de tarjeta>>, etc.). En segundo lugar, todo lo que en el sistema produce o acepta datos se trata como un archivo; esto incluye dispositivos de hardware como unidades de disco y terminales. Los sistemas antiguos trataban cada dispositivo de forma diferente. Ambas ideas han hecho la vida de los programadores de sistemas mucho más agradable.
\subsection{E/S Estándar}
Por convención, cada programa Unix tiene una única forma de aceptar entrada llamada \emph{entrada estándar}, una única forma de producir salida llamada \emph{salida estándar}, y una única forma de producir mensajes de error llamada \emph{salida de error estándar}, normalmente abreviada como \emph{error estándar}. Por supuesto, un programa puede tener también otras fuentes de entrada y salida, como veremos en el \hyperref[sec:Chapter7]{Capítulo 7}.
La E/S estándar fue el primer esquema de su clase que se diseñó específicamente para usuarios interactivos, en lugar del antiguo estilo de uso por lotes que normalmente implicaba barajas de tarjetas perforadas. Dado que el shell de Unix proporciona la interfaz de usuario, no debería sorprendernos que la E/S estándar se diseñara para encajar perfectamente con el shell.
Todos los shells manejan la E/S estándar básicamente de la misma manera. Cada programa que invocas tiene los tres canales de E/S estándar configurados para tu terminal o ventana de estación de trabajo, de modo que la entrada estándar es tu teclado, y la salida estándar y el error son tu pantalla o ventana. Por ejemplo, la utilidad de correo imprime mensajes para ti en la salida estándar, y cuando la usas para enviar mensajes a otros usuarios, acepta tu entrada en la entrada estándar. Esto significa que ves los mensajes en tu pantalla y escribes los nuevos en tu teclado.
Cuando sea necesario, puede redirigir la entrada y la salida para que procedan o vayan a un archivo en su lugar. Si quieres enviar el contenido de un archivo preexistente a alguien como correo, redirige la entrada estándar de correo para que lea de ese archivo en lugar de tu teclado.
También puedes conectar programas en una \emph{tubería (pipeline)}, en la que la salida estándar de un programa se alimenta directamente de la entrada estándar de otro; por ejemplo, podrías alimentar la salida de mail directamente al programa \emph{lp} para que los mensajes se impriman en lugar de mostrarse en pantalla.
Esto hace posible el uso de utilidades Unix como bloques de construcción para programas más grandes. Muchos programas de utilidades Unix están pensados para ser utilizados de esta manera: cada uno de ellos realiza un tipo específico de operación de filtrado en el texto de entrada. Aunque este no es un libro de texto sobre utilidades Unix, son esenciales para el uso productivo del shell. Las utilidades de filtrado más populares se listan en la Tabla \ref{tab5}
\begin{table}[h]
\center
\caption{Utilidades populares de filtrado de datos Unix}
\label{tab5}
\begin{tabular}{m{2cm}|m{11cm}} \hline
\textbf{Utilidad} & \textbf{Propósito} \\ \hline
cat & Copia la entrada estándar en la salida estándar \\
grep & Busca \emph{strings} en la entrada estándar \\
sort & Ordena las líneas de la entrada estándar \\
sed & Realiza operaciones de edición en la entrada estándar \\
tr & Traduce caracteres de la entrada estándar a otros caracteres \\
\end{tabular}
\end{table}
Es posible que haya utilizado alguna de estas utilidades antes y se haya dado cuenta de que toman nombres de archivos de entrada como argumentos y producen salida en la salida estándar. Sin embargo, puede que no sepa que todas ellas (y la mayoría de las utilidades de Unix) aceptan la entrada estándar si omite el argumento\footnote{Si una determinada utilidad Unix no acepta la entrada estándar cuando se omite el argumento nombre de fichero, pruebe a utilizar - como argumento. Esta es una convención común, aunque no universal.}.
Por ejemplo, la utilidad más básica es \emph{cat}, que simplemente copia su entrada a su salida. Si escribe \texttt{cat} con un argumento de nombre de archivo, imprimirá el contenido de ese archivo en su pantalla. Pero si lo invocas sin argumentos, leerá la entrada estándar y la copiará en la salida estándar. Pruébelo: \emph{cat} esperará a que escriba una línea de texto; cuando teclee ENTER, \emph{cat} repetirá el texto como un loro. Para detener el proceso, pulse CTRL-D al principio de una línea (vea más abajo lo que significa este carácter). Verás \textasciicircum D cuando teclees CTRL-D. Esto es lo que debería parecer:
\begin{lstlisting}[language=bash]
$ cat
Here is a line of text.
Here is a line of text.
This is another line of text.
This is another line of text.
^D
$
\end{lstlisting}
\subsection{Redirección de E/S}
\emph{cat} es en realidad la abreviatura de <<catenate>>, es decir, unir. Acepta varios argumentos de nombre de archivo y los copia en la salida estándar. Pero supongamos, por el momento, que \emph{cat} y otras utilidades no aceptan argumentos de nombre de archivo y sólo aceptan la entrada estándar. Como dijimos anteriormente, el shell le permite redirigir la entrada estándar para que provenga de un archivo. La notación \texttt{command < filename} hace esto; configura las cosas para que \emph{command} tome la entrada estándar de un archivo en lugar de una terminal.
Por ejemplo, si usted tiene un archivo llamado fred que contiene algún texto, entonces \texttt{cat < fred} imprimirá el contenido de fred en su terminal. \texttt{sort < fred} ordenará las líneas en el archivo fred e imprimirá el resultado en su terminal (recuerde: estamos pretendiendo que las utilidades no toman argumentos de nombre de archivo).
Del mismo modo, \texttt{command > filename} hace que la salida estándar del comando sea redirigida al archivo nombrado. El clásico ejemplo <<canónico>> de esto es \texttt{date > now:} el comando \emph{date} imprime la fecha y hora actual en la salida estándar; el comando anterior la guarda en un archivo llamado \emph{now}.
Las redirecciones de entrada y salida pueden combinarse. Por ejemplo, el comando \emph{cp} se usa normalmente para copiar archivos; si por alguna razón no existiera o estuviera roto, podrías usar \emph{cat} de esta manera:
\begin{lstlisting}[language=bash]
cat < file1 > file2
\end{lstlisting}
Esto sería similar a \texttt{cp archivo1 archivo2}.
Como recurso mnemotécnico, piensa en < y > como <<embudos de datos>>. Los datos entran por el extremo grande y salen por el pequeño.
Cuando se utiliza de forma interactiva, el shell de Korn le permite utilizar un comodín de shell después de un operador de redirección de E/S. Si el patrón coincide \emph{exactamente} con un archivo, ese archivo se utiliza para la redirección de E/S. De lo contrario, el patrón no se modifica y el shell intenta abrir un archivo cuyo nombre sea exactamente el que ha escrito. Además, no es válido intentar una redirección con la cadena nula como nombre de fichero (como podría ocurrir cuando se utiliza el valor de una variable, y la variable resulta estar vacía).
Por último, es tentador utilizar el mismo fichero tanto para la entrada como para la salida:
\begin{lstlisting}[language=bash]
sort < myfile > myfile
\end{lstlisting}
Esto no funciona. El shell trunca \emph{myfile} cuando lo abre para la salida, y no habrá ningún dato allí para que \emph{sort} lo procese cuando se ejecute.
\subsection{Tuberías (pipes)}
También es posible redirigir la salida de un comando a la entrada estándar de otro comando en ejecución en lugar de a un archivo. La construcción que hace esto se llama tubería, anotada como |. Una línea de comandos que incluye dos o más comandos conectados con tuberías se denomina \emph{pipeline}.
Las tuberías se utilizan muy a menudo con el comando \emph{more}, que funciona igual que \emph{cat} excepto que imprime su salida pantalla a pantalla, haciendo una pausa para que el usuario escriba SPACE (siguiente pantalla), ENTER (siguiente línea), u otros comandos. Si estás en un directorio con un gran número de ficheros y quieres ver detalles sobre ellos, \texttt{ls -l | more} te dará un listado detallado pantalla a pantalla.
Los pipelines pueden llegar a ser muy complejos (vea, por ejemplo, la función \emph{lsd} en el \hyperref[sec:Chapter4]{Capítulo 4} o la versión pipeline del driver del compilador de C en el \hyperref[sec:Chapter7]{Capítulo 7}); también pueden combinarse con otros redireccionadores de E/S. Para ver un listado ordenado del fichero \emph{fred} pantalla a pantalla, escriba \texttt{sort < fred | more}. Para imprimirlo en lugar de verlo en su terminal, escriba \texttt{sort < fred | lp}.
He aquí un ejemplo más complicado. El archivo \texttt{/etc/passwd} almacena información sobre las cuentas de usuario en un sistema Unix. Cada línea del archivo contiene el nombre de usuario, el número de identificación de usuario, la contraseña encriptada, el directorio de inicio, el shell de inicio de sesión y otra información. El primer campo de cada línea es el nombre de usuario; los campos están separados por dos puntos (:). Una línea de ejemplo podría tener este aspecto:
\begin{lstlisting}[language=bash]
billr:5Ae40BGR/tePk:284:93:Bill Rosenblatt:/home/billr:/bin/ksh
\end{lstlisting}
Para obtener un listado ordenado de todos los usuarios del sistema, escriba:
\begin{lstlisting}[language=bash]
cut -d: -f1 < /etc/passwd | sort
\end{lstlisting}
\newpage
El comando \emph{cut} extrae el primer campo \emph{(-f1)}, donde los campos están separados por dos puntos \emph{(-d:)}, de la entrada. La tubería completa imprime una lista que se parece a esto:
\begin{lstlisting}[language=bash]
al
billr
bob
chris
dave
ed
frank
...
\end{lstlisting}
Si desea enviar la lista directamente a la impresora (en lugar de a la pantalla), puede ampliar el proceso de la siguiente manera:
\begin{lstlisting}[language=bash]
cut -d: -f1 < /etc/passwd | sort | lp
\end{lstlisting}
Ahora deberías ver cómo la redirección de E/S y los pipelines apoyan la filosofía de bloques de construcción de Unix. La notación es extremadamente concisa y poderosa. Igualmente importante, el concepto de tubería elimina la necesidad de archivos temporales desordenados para almacenar la salida de comandos antes de que se alimente a otros comandos.
Por ejemplo, para hacer lo mismo que en la línea de comandos anterior en otros sistemas operativos (suponiendo que hubiera disponibles utilidades equivalentes), se necesitarían tres comandos. En el sistema OpenVMS de Compaq, tendrían este aspecto:
\begin{lstlisting}[language=bash]
$ cut [etc]passwd /d=":" /f=1 /out=temp1
$ sort temp1 /out=temp2
$ print temp2
\end{lstlisting}
Después de practicar lo suficiente, se encontrará tecleando rutinariamente potentes conductos de comandos que hacen en una línea lo que en otros sistemas operativos requeriría varios comandos (y archivos temporales) para lograrlo.
\section{Trabajos en Segundo Plano}
Las tuberías son en realidad un caso especial de una característica más general: hacer más de una cosa a la vez. cualquier otro sistema operativo comercial no tiene esta capacidad, debido a los rígidos límites que tienden a imponer a los usuarios. Unix, por otro lado, fue desarrollado en un laboratorio de investigación y pensado para uso interno, por lo que hace relativamente poco para imponer límites a los recursos disponibles para los usuarios en un ordenador - como de costumbre, inclinándose hacia la simplicidad despejada en lugar de la sobrecomplejidad.
<<Hacer más de una cosa a la vez>> significa ejecutar más de un programa al mismo tiempo. Esto se hace cuando se invoca un pipeline; también se puede hacer iniciando sesión en un sistema Unix tantas veces simultáneamente como se desee. (Si lo intentas en un sistema IBM VM/CMS, por ejemplo, obtendrás un odioso mensaje de <<ya ha iniciado sesión>>).
El shell también le permite ejecutar más de un comando a la vez durante una única sesión de inicio de sesión. Normalmente, cuando escribes un comando y pulsas ENTER, el shell deja que el comando tenga el control de tu terminal hasta que termine; no puedes ejecutar más comandos hasta que termine el primero. Pero si quieres ejecutar un comando que no requiere la entrada del usuario y quieres hacer otras cosas mientras se ejecuta el comando, pon un ampersand (\&) después del comando.
Esto se denomina ejecutar el comando en segundo plano, y un comando que se ejecuta de esta forma se denomina \emph{trabajo en segundo plano}; por el contrario, un trabajo que se ejecuta de la forma normal se denomina \emph{trabajo en primer plano}. Cuando inicias un trabajo en segundo plano, recuperas inmediatamente el prompt del shell, lo que te permite introducir otros comandos.
El uso más obvio de los trabajos en segundo plano son los programas que pueden tardar mucho tiempo en ejecutarse, como \emph{sort} o \emph{gunzip} en archivos grandes. Por ejemplo, supongamos que acabas de cargar en tu directorio un enorme archivo comprimido desde una cinta magnética. Hoy en día, la utilidad \emph{gzip} es la utilidad de compresión de archivos de-facto. \emph{gzip} a menudo logra una compresión del 50\% al 90\% de sus archivos de entrada. Los archivos comprimidos tienen nombres del tipo \emph{nombrearchivo.gz}, donde \emph{nombrearchivo} es el nombre del archivo original sin comprimir. Digamos que el archivo es \emph{gcc-3.0.1.tar.gz}, que es un archivo comprimido que contiene más de 36 MB de código fuente.
Escriba \texttt{gunzip gcc-3.0.1.tar.gz \&}, y el sistema inicia un trabajo en segundo plano que descomprime los datos <<en el lugar>> y termina con el archivo \emph{gcc-3.0.1.tar}. Justo después de escribir el comando, verá una línea como esta:
\begin{lstlisting}[language=bash]
[1] 4692
\end{lstlisting}
seguido de su prompt de shell, lo que significa que puede introducir otros comandos. Estos números te dan formas de referirte a tu trabajo en segundo plano; el \hyperref[sec:Chapter8]{Capítulo 8} los explica en detalle.
Puede verificar los trabajos en segundo plano con el comando \emph{jobs}. Para cada trabajo en segundo plano, \emph{jobs} imprime una línea similar a la anterior pero con una indicación del estado del trabajo:
\begin{lstlisting}[language=bash]
[1] + Running gunzip gcc-3.0.1.tar.gz
\end{lstlisting}
Cuando el trabajo termine, verás un mensaje como este justo antes de tu prompt de shell:
\begin{lstlisting}[language=bash]
[1] + Done gunzip gcc-3.0.1.tar.gz
\end{lstlisting}
El mensaje cambia si su trabajo en segundo plano finaliza con un error; de nuevo, consulte el \hyperref[sec:Chapter8]{Capítulo 8} para más detalles.
\subsection{E/S en Segundo Plano}
Los trabajos que pongas en segundo plano no deberían hacer E/S a tu terminal. Piénsalo un momento y entenderás por qué.
Por definición, un trabajo en segundo plano no tiene control sobre tu terminal. Entre otras cosas, esto significa que sólo el proceso en primer plano (o, en su defecto, el propio shell) está <<escuchando>> la entrada de tu teclado. Si un trabajo en segundo plano necesita entrada de teclado, a menudo se quedará ahí sin hacer nada hasta que usted haga algo al respecto (como se describe en el \hyperref[sec:Chapter8]{Capítulo 8}).
Si un trabajo en segundo plano produce salida por pantalla, la salida simplemente aparecerá en su pantalla. Si está ejecutando un trabajo en primer plano que también produce salida, la salida de los dos trabajos se intercalará de forma aleatoria (y a menudo molesta).
Si quieres ejecutar un trabajo en segundo plano que espera una entrada estándar o produce una salida estándar, la solución obvia es redirigirlo para que venga o vaya a un fichero. La única excepción es que algunos programas producen pequeños mensajes de una línea (advertencias, mensajes de <<hecho>>, etc.); puede que no te importe si éstos se intercalan con cualquier otra salida que estés viendo en un momento dado.
Por ejemplo, la utilidad \emph{diff} examina dos archivos, cuyos nombres se dan como argumentos, e imprime un resumen de sus diferencias en la salida estándar. Si los archivos son exactamente iguales, \emph{diff} no dice nada. Normalmente, usted invoca \emph{diff} esperando ver unas pocas líneas que son diferentes.
\emph{diff}, al igual que \emph{sort} y \emph{gzip}, puede tardar mucho tiempo en ejecutarse si los ficheros de entrada son muy grandes. Suponga que tiene dos archivos grandes llamados \emph{warandpeace.html} y \emph{warandpeace.html.old}. El comando \texttt{diff warandpeace.html.old warandpeace.html} revela que el autor decidió cambiar el nombre <<Ivan>> por <<Aleksandr>> en todo el archivo - es decir, cientos de diferencias, lo que resulta en grandes cantidades de salida.
Si escribe \texttt{diff warandpeace.html.old warandpeace.html \&}, el sistema le arrojará montones y montones de resultados, que serán muy difíciles de detener - incluso con las técnicas explicadas en el \hyperref[sec:Chapter7]{Capítulo 7}. Sin embargo, si escribe:
\begin{lstlisting}[language=bash]
diff warandpeace.html.antiguo warandpeace.html > wpdiff &
\end{lstlisting}
las diferencias se guardarán en el archivo \emph{wpdiff} para que pueda examinarlas más tarde.
\subsection{Trabajos en Segundo Plano y Prioridades}
Las tareas en segundo plano pueden ahorrarte mucho tiempo (o pueden ayudarte a hacer dieta eliminando las excusas para ir corriendo a la máquina de caramelos). Pero recuerda que no hay almuerzo gratis; los trabajos en segundo plano consumen recursos que dejan de estar disponibles para ti o para otros usuarios del sistema. El hecho de que ejecutes varios trabajos a la vez no significa que vayan a funcionar más rápido que si se ejecutaran secuencialmente; de hecho, suele ser peor.
A cada tarea del sistema se le asigna una \emph{prioridad}, un número que indica al sistema operativo cuánta prioridad debe darle a la hora de repartir los recursos (cuanto mayor sea el número, menor será la prioridad). Los comandos en primer plano que se introducen desde el shell suelen tener la misma prioridad estándar. Pero los trabajos en segundo plano, por defecto, tienen una prioridad más baja\footnote{Esta característica se tomó prestada del intérprete de comandos C; no está presente en la mayoría de los intérpretes de comandos Bourne.}. En el \hyperref[sec:Chapter3]{Capítulo 3} descubrirás cómo puedes anular esta asignación de prioridad para que los trabajos en segundo plano se ejecuten con la misma prioridad que los trabajos en primer plano.
Si estás en un gran sistema multiusuario, ejecutar muchos trabajos en segundo plano puede consumir más recursos de los que te corresponden, y deberías considerar si hacer que tu trabajo se ejecute lo más rápido posible es realmente más importante que ser un buen ciudadano.
Por otro lado, si tienes una estación de trabajo dedicada con un procesador rápido y mucha memoria y disco, probablemente tengas ciclos de sobra y no debas preocuparte tanto por ello. De todos modos, el patrón de uso típico de estos sistemas obvia en gran medida la necesidad de procesos en segundo plano: basta con iniciar un trabajo y luego abrir otra ventana y seguir trabajando.
\subsubsection{nice}
Hablando de buena ciudadanía, también hay un comando de shell que te permite bajar la prioridad de cualquier trabajo: el acertadamente llamado \emph{nice}. Si escribes lo siguiente, el comando se ejecutará con una prioridad más baja:
\begin{lstlisting}[language=bash]
nice command
\end{lstlisting}
Puedes controlar cuánto más bajo es dando a \emph{nice} un argumento numérico; consulta la página \emph{man} para más detalles\footnote{Si eres administrador del sistema y has iniciado sesión como \texttt{root}, también puedes utilizar \emph{nice} para aumentar la prioridad de una tarea.}.
\section{Caracteres Especiales y Citas}
Los caracteres \texttt{<, >, | y \&} son cuatro ejemplos de \emph{caracteres especiales} que tienen significados particulares para el shell. Los comodines que vimos anteriormente en este capítulo \texttt{(*, ?, y [...])} también son caracteres especiales.
En la Tabla \ref{tab6} se indican los significados de todos los caracteres especiales sólo dentro de las líneas de comandos del shell. Otros caracteres tienen significados especiales en situaciones específicas, como las expresiones regulares y los operadores de manejo de cadenas que veremos en el \hyperref[sec:Chapter3]{Capítulo 3} y el \hyperref[sec:Chapter4]{Capítulo 4}.
\begin{longtable}[h]{p{2cm}|p{8cm}|p{3cm}}
\caption{Caracteres especiales}
\label{tab6}\\
\hline
\textbf{Caracter} & \textbf{Significado} & \textbf{Ver capítulo} \\\hline
\endfirsthead
\hline
\textbf{Caracter} & \textbf{Significado} & \textbf{Ver capítulo} \\\hline
\endhead
\texttt{\~} & Directorio \emph{Home} & 1 \\
\texttt{`} & Sustitución de comandos (arcaico) & 4 \\
\texttt{\#} & Comentario & 4 \\
\texttt{\$} & Expresión variable & 3 \\
\texttt{\&} & Trabajo en segundo plano & 1 \\
\texttt{*} & Cadena comodín & 1 \\
\texttt{(} & Inicio subshell & 8 \\
\texttt{)} & Fin subshell & 8 \\
\textbackslash{} & Cita siguiente carácter & 1 \\
| & Tubería (Pipe) & 1 \\
\texttt{[} & Inicio conjunto caracteres comodín & 1 \\
\texttt{]} & Fin del juego de caracteres comodín & 1 \\
\textbraceleft & Inicio bloque de código & 7 \\
\textbraceright & Fin del bloque de código & 7 \\
; & Separador de comandos Shell & 3 \\
' & Comilla simple & 1 \\
" & Doble comilla & 1 \\
< & Redirección de entrada & 1 \\
> & Redirección de salida & 1 \\
/ & Separador de directorio & 1 \\
? & Comodín de un solo carácter & 1 \\
\% & Identificador de nombre/número de trabajo & 8 \\
\end{longtable}
\subsection{Citando}
A veces querrá utilizar caracteres especiales literalmente, es decir, sin sus significados especiales. Esto se denomina \emph{entrecomillado}. Si rodea una cadena de caracteres con comillas simples, despojará a todos los caracteres entre comillas de cualquier significado especial que pudieran tener.
La situación más obvia en la que podrías necesitar entrecomillar una cadena es con la orden \emph{print}, que simplemente toma sus argumentos y los imprime en la salida estándar. ¿Para qué sirve esto? Como verá en capítulos posteriores, el intérprete de comandos realiza bastantes procesos en las líneas de comandos, la mayoría de los cuales implican algunos de los caracteres especiales enumerados en la Tabla \ref{tab6}. \emph{print} es una forma de hacer que el resultado de ese proceso esté disponible en la salida estándar.
\newpage
Pero, ¿qué pasaría si quisiéramos imprimir la cadena, \texttt{2 * 3 > 5 is a valid inequality} Supongamos que escribimos esto:
\begin{lstlisting}[language=bash]
print 2 * 3 > 5 is a valid inequality
\end{lstlisting}
Volverías a tener el prompt del shell, ¡como si no hubiera pasado nada! Pero entonces habría un nuevo archivo, con el nombre 5, conteniendo <<2>>, los nombres de todos los archivos en tu directorio actual, y entonces la cadena \texttt{3 is a valid inequality}. Asegúrate de entender por qué\footnote{Esto también debería enseñarte algo sobre la flexibilidad de colocar redireccionadores de E/S en cualquier parte de la línea de comandos, incluso en lugares donde no parecen tener sentido.}.
Sin embargo, si escribes
\begin{lstlisting}[language=bash]
print '2 * 3 > 5 is a valid inequality.'
\end{lstlisting}
el resultado es la cadena, tomada literalmente. No es necesario que cites toda la línea, sólo la parte que contiene caracteres especiales (o caracteres que crees que pueden ser especiales, si quieres estar seguro):
\begin{lstlisting}[language=bash]
print '2 * 3 > 5' is a valid inequality.
\end{lstlisting}
Esto tiene exactamente el mismo resultado.
Observe que la Tabla \ref{tab6} enumera las comillas dobles ('') como comillas simples. Una cadena entre comillas dobles está sujeta a algunos de los pasos que sigue el shell para procesar líneas de órdenes, pero no a todos. (En otras palabras, trata sólo algunos caracteres especiales como especiales.) Verá en capítulos posteriores por qué las comillas dobles son a veces preferibles; el \hyperref[sec:Chapter7]{Capítulo 7} contiene la explicación más completa de las reglas del shell para las comillas y otros aspectos del procesamiento de la línea de órdenes. Por ahora, sin embargo, deberías ceñirte a las comillas simples.
\subsection{Barra invertida}
Otra forma de cambiar el significado de un carácter es precederlo de una barra invertida (\textbackslash{}). Esto se denomina barra invertida-escapar el carácter. En la mayoría de los casos, cuando se escapa una barra invertida, se entrecomilla el carácter. Por ejemplo:
\begin{lstlisting}[language=bash]
print 2 \* 3 \> 5 is a valid inequality.
\end{lstlisting}
produce los mismos resultados que si rodeara la cadena con comillas simples. Para utilizar una barra invertida literal, basta con rodearla de comillas ('\textbackslash{}') o, mejor aún, con escaparla (\textbackslash{} \textbackslash{}).
He aquí un ejemplo más práctico de cómo entrecomillar caracteres especiales. Algunos comandos Unix toman argumentos que a menudo incluyen caracteres comodín, que necesitan ser escapados para que el shell no los procese primero. El comando más común es \emph{find}, que busca archivos en árboles de directorios completos.
Para utilizar \emph{find}, debe proporcionar la raíz del árbol en el que desea buscar y argumentos que describan las características de los archivos que desea encontrar. Por ejemplo, el comando \texttt{find . -name string -print} busca en el árbol de directorios cuya raíz es el directorio actual los archivos cuyos nombres coinciden con la cadena e imprime sus nombres. (Otros argumentos permiten buscar por tamaño del archivo, propietario, permisos, fecha del último acceso, etc.).
Puede utilizar comodines en la cadena, pero debe entrecomillarlos para que el propio comando \emph{find} pueda compararlos con los nombres de los archivos de cada directorio en el que busca. El comando \texttt{find . -name '*.c'} buscará todos los archivos cuyo nombre termine en \texttt{.c} en cualquier lugar del directorio actual, subdirectorios, sub-subdirectorios, etc.
\subsection{Comillas dobles}
También puede utilizar una barra invertida para incluir comillas dobles dentro de una cadena. Por ejemplo
\begin{lstlisting}[language=bash]
print \"2 \* 3 \> 5\" is a valid inequality.
\end{lstlisting}
produce el siguiente resultado:
\begin{lstlisting}[language=bash]
"2 * 3 > 5" is a valid inequality.
\end{lstlisting}
Dentro de una cadena entre comillas dobles, sólo es necesario escapar las comillas dobles:
\begin{lstlisting}[language=bash]
$ print "\"2 * 3 > 5\" is a valid inequality."
"2 * 3 > 5" is a valid inequality.
\end{lstlisting}
Sin embargo, esto no funcionará con comillas simples dentro de expresiones entrecomilladas. Por ejemplo, \texttt{print 'Bob\textbackslash{}'s hair is brown'} no dará como resultado \texttt{Bob's hair is brown}. Puede evitar esta limitación de varias maneras. Primero, intente eliminar las comillas:
\begin{lstlisting}[language=bash]
print Bob\'s hair is brown
\end{lstlisting}
Si no hay otros caracteres especiales (como en este caso), esto funciona. De lo contrario, puede utilizar el siguiente comando:
\begin{lstlisting}[language=bash]
print 'Bob'\''s hair is brown'
\end{lstlisting}
Es decir, '\textbackslash{}'' (comilla simple, barra invertida, comilla simple, comilla simple) actúa como una comilla simple dentro de una cadena entrecomillada. ¿Por qué? La primera ' de '\textbackslash{}'' termina la cadena entrecomillada que empezamos con 'Bob, la \textbackslash{}' inserta una comilla simple literal, y la siguiente ' inicia otra cadena entrecomillada que termina con la palabra <<brown>>. Si entiendes esto, no tendrás problemas para resolver los otros problemas desconcertantes que surgen de la sintaxis a menudo críptica del shell.
Existe un mecanismo algo más legible, específico de \emph{ksh93}, para los casos en los que necesite entrecomillar comillas simples. Este es el mecanismo de entrecomillado extendido del shell: \texttt{\$'...'}. Esto se conoce en la documentación de \emph{ksh} como entrecomillado ANSI C, ya que las reglas se parecen mucho a las del estándar ANSI/ISO C. Los detalles completos se proporcionan en el \hyperref[sec:Chapter7]{Capítulo 7}. A continuación se muestra cómo utilizar el entrecomillado ANSI C para el ejemplo anterior:
\begin{lstlisting}[language=bash]
$ print $'Bob\'s hair is brown'
Bob's hair is brown
\end{lstlisting}
\subsection{Continuación de líneas}
Una cuestión relacionada es cómo continuar el texto de un comando más allá de una sola línea en la ventana de tu terminal o estación de trabajo. La respuesta es conceptualmente sencilla: basta con citar la tecla ENTER. Después de todo, ENTER no es más que otro carácter.
Puede hacerlo de dos maneras: terminando una línea con una barra invertida o no cerrando una comilla (es decir, incluyendo ENTER en una cadena entrecomillada). Si utiliza la barra invertida, no debe haber nada entre ella y el final de la línea - ni siquiera espacios o TABs.
Tanto si utiliza una barra invertida como una comilla simple, le está diciendo al shell que ignore el significado especial del carácter ENTER. Después de pulsar ENTER, el shell entiende que no ha terminado su línea de comandos (es decir, ya que no ha escrito un ENTER <<real>>), por lo que responde con un prompt secundario, que es > por defecto, y espera a que termine la línea. Puedes continuar una línea tantas veces como desees.
Por ejemplo, si quiere que el shell imprima la primera frase de \emph{The Return of the Native} de Thomas Hardy, puede escribir esto:
\begin{lstlisting}[language=bash]
$ print A Saturday afternoon in November was approaching the \
> time of twilight, and the vast tract of unenclosed wild known \
> as Egdon Heath embrowned itself moment by moment.
\end{lstlisting}
O puedes hacerlo así:
\begin{lstlisting}[language=bash]
$ print 'A Saturday afternoon in November was approaching the
> time of twilight, and the vast tract of unenclosed wild known
> as Egdon Heath embrowned itself moment by moment.'
\end{lstlisting}
Hay una diferencia entre los dos métodos. El primero imprime la frase como una línea larga. El segundo conserva las nuevas líneas incrustadas. Pruebe ambos y verá la diferencia.
\subsection{Teclas de control}
Las teclas de control (las que escribes manteniendo pulsada la tecla CONTROL (o CTRL) y pulsando otra tecla) son otro tipo de caracteres especiales. Normalmente no imprimen nada en la pantalla, pero el sistema operativo interpreta algunos de ellos como comandos especiales. Ya conoces uno de ellos: ENTER es en realidad lo mismo que CTRL-M (pruébalo y verás). Probablemente también hayas utilizado la tecla RETROCESO o SUPR para borrar errores tipográficos en tu línea de comandos.
En realidad, muchas teclas de control tienen funciones que realmente no te conciernen - sin embargo, deberías conocerlas para futuras referencias y en caso de que las escribas por accidente.
Quizás lo más difícil de las teclas de control es que pueden diferir de un sistema a otro. La disposición habitual se muestra en la Tabla \ref{Tab:1-7}, que lista las teclas de control que soportan las principales versiones modernas de Unix. Tenga en cuenta que CTRL-\textbackslash{} y CTRL-| (control-barra invertida y control-tubo) son el mismo carácter anotado de dos formas diferentes; lo mismo ocurre con DEL y CTRL-?
Puede utilizar el comando \emph{stty(1)} para averiguar cuál es su configuración y cambiarla si lo desea; consulte el \hyperref[sec:Chapter8]{Capítulo 8} para más detalles. En sistemas Unix modernos (incluyendo GNU/Linux), use \texttt{stty -a} para ver su configuración de teclas de control:
\begin{lstlisting}[language=bash]
$ stty -a
speed 38400 baud; rows 24; columns 80; line = 0;
intr = ^C; quit = ^\; erase = ^H; kill = ^U; eof = ^D; eol = ; <undef>;
eol2 = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W;
lnext = ^V; flush = ^O; min = 1; time = 0;
...
\end{lstlisting}
La notación \^{}X significa CTRL-X.
\newpage
\begin{table}[h]
\center
\caption{Teclas de control}
\label{Tab:1-7}
\begin{tabular}{m{3.5cm}|m{2cm}|m{9cm}} \hline
\textbf{Tecla de control} & \textbf{Nombre de stty} & \textbf{Descripción de la función} \\ \hline
CTRL-C & intr & Detiene el comando actual \\
CTRL-D & eof & Detiene el comando actual \\
CTRL-\textbackslash{} ó CTRL-| & quit & Detiene el comando actual, si CTRL-C no funciona \\
CTRL-S & stop & Detiene el comando actual, si CTRL-C no funciona \\
CTRL-Q & start & Reinicia la salida a pantalla \\
BACKSPACE ó CTRL-H & erase & Borra el último carácter. Esta es la configuración más común \\
DEL ó CTRL-? & erase & Borra último carácter. Este es un ajuste alternativo común. para el carácter de borrado \\
CTRL-U & kill & Borra toda la línea de comandos \\
CTRL-Z & susp & Suspende el comando actual (ver \hyperref[sec:Chapter8]{Capítulo 8}) \\
CTRL-R & rprnt & Reimprime los caracteres introducidos hasta el momento \\
\end{tabular}
\end{table}
La tecla de control que probablemente utilices más a menudo es CTRL-C, a veces llamada \emph{tecla de interrupción}. Esto detiene - o intenta detener - el comando que se está ejecutando en ese momento. Querrás usarla cuando introduzcas un comando y veas que está tardando demasiado, cuando le des los argumentos equivocados por error, cuando cambies de opinión sobre si quieres ejecutarlo, etc.
A veces CTRL-C no funciona; en ese caso, si realmente quieres detener un trabajo, prueba con CTRL-\textbackslash. Pero no escriba simplemente CTRL-\textbackslash; ¡pruebe siempre CTRL-C primero! El \hyperref[sec:Chapter8]{Capítulo 8} explica por qué en detalle. Por ahora, basta con decir que CTRL-C da al trabajo en ejecución más oportunidad de limpiar antes de salir, para que los ficheros y otros recursos no queden en estados extraños.
Ya hemos visto un ejemplo de CTRL-D. Cuando estás ejecutando un comando que acepta la entrada estándar de tu teclado, CTRL-D (como el primer carácter en la línea) le dice al proceso que tu entrada ha terminado - como si el proceso estuviera leyendo un archivo y llegara al final del archivo. mail es una utilidad en la que esto sucede a menudo. Cuando estás escribiendo un mensaje, terminas tecleando CTRL-D. Esto le dice a mail que su mensaje está completo y listo para ser enviado. La mayoría de las utilidades que aceptan entrada estándar entienden CTRL-D como el carácter de fin de entrada, aunque muchos de estos programas aceptan comandos como \emph{q, quit, exit,} etc. El propio intérprete de comandos entiende CTRL-D como el carácter de fin de entrada: como vimos anteriormente en este capítulo, normalmente puede finalizar una sesión de inicio de sesión escribiendo CTRL-D en el indicador del intérprete de comandos. Sólo le está diciendo al shell que su entrada de comandos ha terminado.
CTRL-S y CTRL-Q se llaman caracteres de control de flujo. Representan una forma anticuada de detener y reiniciar el flujo de salida de un dispositivo a otro (por ejemplo, del ordenador a tu terminal) que era útil cuando la velocidad de dicha salida era baja. Están bastante obsoletos en estos tiempos de redes locales de alta velocidad y líneas de acceso telefónico. De hecho, en estas últimas condiciones, CTRL-S y CTRL-Q son básicamente una molestia. Lo único que realmente necesitas saber sobre ellas es que si la salida de tu pantalla se <<atasca>>, puede que hayas pulsado CTRL-S por accidente. Escribe CTRL-Q para reiniciar la salida; cualquier tecla que hayas pulsado entretanto tendrá efecto.
El último grupo de caracteres de control te ofrece formas rudimentarias de editar tu línea de comandos. RETROCESO o CTRL-H actúan como una tecla de retroceso (de hecho, algunos sistemas usan las teclas DEL o CTRL-? como <<borrar>> en lugar de RETROCESO); CTRL-U borra toda la línea y te permite empezar de nuevo. De nuevo, la mayoría de estas funciones son obsoletas\footnote{¿Por qué se siguen utilizando tantas teclas de control obsoletas? No tienen nada que ver con el shell per se; en su lugar, son reconocidas por el controlador tty, una vieja y vetusta parte de las profundidades inferiores del sistema operativo que controla la entrada y salida a/desde tu terminal. De hecho, es el controlador tty el que entiende CTRL-D y señala el fin de la entrada a los programas que leen desde el terminal, no los propios programas.} En lugar de usarlas, vaya al siguiente capítulo y lea sobre los modos de edición del shell de Korn, que están entre sus características más interesantes.