Corregir texto en cursiva y monoespaciado

This commit is contained in:
Tuxliban Torvalds 2023-12-29 02:06:17 -06:00
parent f46a2eabd1
commit 431122029f
15 changed files with 443 additions and 443 deletions

Binary file not shown.

View File

@ -1,28 +1,28 @@
La fragmentación del mercado de Unix ha tenido sus ventajas y desventajas. Las ventajas vinieron principalmente en los primeros días: la falta de estandarización y la proliferación entre académicos y profesionales técnicamente competentes contribuyeron a un <<mercado libre>> saludable para el software de Unix, en el que varios programas del mismo tipo (por ejemplo, shells, editores de texto, herramientas de administración del sistema) a menudo competían por popularidad. Los mejores programas generalmente se volvían más ampliamente utilizados, mientras que el software inferior tendía a desaparecer.
La fragmentación del mercado Unix ha tenido sus ventajas y desventajas. Las ventajas vinieron principalmente en los primeros días: la falta de estandarización y la proliferación entre académicos y profesionales técnicamente competentes contribuyeron a un <<mercado libre>> saludable para el software de Unix, en el que varios programas del mismo tipo (por ejemplo, shells, editores de texto, herramientas de administración del sistema) a menudo competían por popularidad. Los mejores programas generalmente se volvían más ampliamente utilizados, mientras que el software inferior tendía a desaparecer.
Pero a menudo no había un único programa <<mejor>> en una categoría dada, por lo que varios prevalecían. Esto llevó a la situación actual, donde la multiplicidad de software similar ha llevado a la confusión, la falta de compatibilidad y, lo más desafortunado de todo, a la incapacidad de Unix para capturar una parte tan grande del mercado como otras plataformas operativas. En particular, Unix se ha relegado a su posición actual como un sistema operativo muy popular para servidores, pero es una rareza en las computadoras de escritorio.
La categoría <<shell>> probablemente ha sufrido de esta manera más que cualquier otro tipo de software. Como dijimos en el \hyperref[sec:Prefacio]{Prefacio} y el \hyperref[sec:Chapter1]{Capítulo 1}, una de las fortalezas de Unix es que el shell es reemplazable y, por lo tanto, actualmente hay varios shells disponibles; las diferencias entre ellos a menudo no son tan grandes. Creemos que el shell Korn es uno de los mejores entre los shells más utilizados, pero otros shells ciertamente tienen sus seguidores leales, por lo que no es probable que caigan en el olvido. De hecho, parece que los shells, compatibles con Bourne o no, continúan proliferando.
La categoría <<shell>> probablemente ha sufrido de esta manera más que cualquier otro tipo de software. Como dijimos en el \hyperref[sec:Prefacio]{Prefacio} y el \hyperref[sec:Chapter1]{Capítulo 1}, una de las fortalezas de Unix es que el shell es reemplazable y, por lo tanto, actualmente hay varios shells disponibles; las diferencias entre ellos a menudo no son tan grandes. Creemos que el shell de Korn es uno de los mejores entre los shells más utilizados, pero otros shells ciertamente tienen sus seguidores leales, por lo que no es probable que caigan en el olvido. De hecho, parece que los shells, compatibles con Bourne o no, continúan proliferando.
Por lo tanto, sentimos que era necesario incluir información sobre shells similares al shell Korn. Este apéndice resume las diferencias entre el shell Korn y los siguientes shells:
Por lo tanto, sentimos que era necesario incluir información sobre shells similares al shell de Korn. Este apéndice resume las diferencias entre el shell de Korn y los siguientes shells:
\begin{itemize}
\item El Shell de Bourne de System V Release 4, como una especie de referencia.
\item La versión de 1988 del shell Korn.
\item El Estándar del shell IEEE POSIX 1003.2, al que se adhieren el shell Korn y otros shells.
\item El shell Desktop Korn (\emph{dtksh}), un shell Korn con mejoras para programación en el sistema X Window, como parte del Common Desktop Environment (CDE).
\item La versión de 1988 del shell de Korn.
\item El Estándar del Shell IEEE POSIX 1003.2, al que se adhieren el shell de Korn y otros shells.
\item El Shell Desktop Korn (\emph{dtksh}), un shell de Korn con mejoras para programación en el sistema X Window, como parte del Common Desktop Environment (CDE).
\item El shell \emph{tksh}, una interesante combinación de \emph{ksh93} con Tcl/Tk.
\item \emph{pdksh}, una versión de dominio público ampliamente utilizada del shell Korn.
\item \emph{pdksh}, una versión de dominio público ampliamente utilizada del shell de Korn.
\item El shell \emph{bash}, otro shell mejorado de Bourne con algunas características del shell C y Korn.
\item El shell Z, \emph{zsh}, otro shell mejorado de Bourne con algunas características de los shells C y Korn y muchas, muchas más características propias en plataformas de PC de escritorio.
\item Similares al shell Korn en plataformas de PC de sobremesa
\item Similares al shell de Korn en plataformas de PC de sobremesa
\end{itemize}
\section{El Shell de Bourne}
El shell Korn es casi completamente compatible hacia atrás con el Shell de Bourne. La única característica significativa de este último que el shell Korn no admite es \^{} (acento circunflejo) como sinónimo del carácter pipe (|).\footnote{También hay algunas diferencias en cómo reaccionan los dos shells ante ciertas entradas extremadamente patológicas. Por lo general, el shell Korn procesa correctamente lo que hace que el Shell de Bourne <<se atragante>>.}
El shell de Korn es casi completamente compatible hacia atrás con el Shell de Bourne. La única característica significativa de este último que el shell de Korn no admite es \^{} (acento circunflejo) como sinónimo del carácter pipe (|).\footnote{También hay algunas diferencias en cómo reaccionan los dos shells ante ciertas entradas extremadamente patológicas. Por lo general, el shell de Korn procesa correctamente lo que hace que el Shell de Bourne <<se atragante>>.}
Esta es una característica arcaica que el Shell de Bourne incluye por su propia compatibilidad hacia atrás con shells anteriores. Ninguna versión moderna de Unix tiene código de shell que use \^{} como pipe.
Para describir las diferencias entre el Shell de Bourne y el Korn shell, revisaremos cada capítulo de este libro y enumeraremos las características discutidas en el capítulo que el Shell de Bourne no admite.
Para describir las diferencias entre el Shell de Bourne y el shell de Korn, revisaremos cada capítulo de este libro y enumeraremos las características discutidas en el capítulo que el Shell de Bourne no admite.
\begin{enumerate}
\item \hyperref[sec:Chapter1]{Capítulo 1}
@ -62,10 +62,10 @@ Para describir las diferencias entre el Shell de Bourne y el Korn shell, revisar
\end{enumerate}
\item \hyperref[sec:Chapter4]{Capítulo 4}
\begin{itemize}
\item No están disponibles los nombres de variables extendidas (aquellas con un punto en ellas), así como la asignación de variables compuestas y la concatenación de cadenas con el operador +=.
\item No están disponibles los nombres de variables extendidas (aquellas con un punto en ellas), así como la asignación de variables compuestas y la concatenación de cadenas con el operador \texttt{+=}.
\item No se admiten variables indirectas (referencias de nombres).
\item No está disponible el comando \emph{whence}; usa type en su lugar.
\item Los operadores variables de coincidencia de patrones (\%, \%\%, \#, \#\#, etc.) y los caracteres comodín avanzados (expresión regular) no están disponibles; usa el comando externo \emph{expr} en su lugar.
\item No está disponible el comando \emph{whence}; usa \emph{type} en su lugar.
\item Los operadores variables de coincidencia de patrones (\%, \%, \#, \#\#, etc.) y los caracteres comodín avanzados (expresión regular) no están disponibles; usa el comando externo \emph{expr} en su lugar.
\item No se admiten funciones cargadas automáticamente, y solo se pueden usar funciones de estilo POSIX (definidas utilizando la sintaxis \emph{name()}).
\item La sintaxis de sustitución de comandos es diferente: utilice el antiguo \texttt{`command`} en lugar de \texttt{\$(command)}. (Algunos proveedores han mejorado sus shells Bourne para que admitan la notación \texttt{\$(comando)}, ya que está definida por el estándar POSIX).
\end{itemize}
@ -73,14 +73,14 @@ Para describir las diferencias entre el Shell de Bourne y el Korn shell, revisar
\begin{itemize}
\item \texttt{return} solo se puede usar desde dentro de una función.
\item Las pruebas condicionales utilizan la sintaxis antigua: \texttt{[ condición ]} o \texttt{test condición} en lugar de \texttt{[[ condición ]]}. Estas son realmente dos formas del mismo comando (consulta la página de manual de \emph{test(1)}).
\item Los operadores lógicos \&\& y || son \texttt{-a} y \texttt{-o} en su lugar. Los operadores de prueba admitidos difieren de un sistema a otro.\footnote{En la Bourne Shell original de la Versión 7 (y en sistemas Unix de Berkeley hasta 4.3BSD), \emph{test} y \texttt{[ condición ]} eran en realidad comandos externos. (Eran enlaces duros entre sí en \emph{/bin}.) Sin embargo, se integraron en el Shell de Bourne en todos los sistemas desde System III (circa 1981).}
\item Los operadores lógicos \texttt{\&\&} y \texttt{||} son \texttt{-a} y \texttt{-o} en su lugar. Los operadores de prueba admitidos difieren de un sistema a otro.\footnote{En el Bourne Shell original de la Versión 7 (y en sistemas Unix de Berkeley hasta 4.3BSD), \emph{test} y \texttt{[ condición ]} eran en realidad comandos externos. (Eran enlaces duros entre sí en \emph{/bin}.) Sin embargo, se integraron en el Shell de Bourne en todos los sistemas desde System III (circa 1981).}
\item La palabra clave ! para invertir el estado de salida de un comando no estaba en el Shell de Bourne de SVR4, aunque puede estar disponible en tu sistema, ya que es requerida por POSIX.
\item No se admite la construcción \texttt{select}. Tampoco el bucle \texttt{for} aritmético, y no hay forma de pasar de un caso a otro dentro de una declaración \texttt{case}.
\item No hay un equivalente para \texttt{TMOUT}.
\end{itemize}
\item \hyperref[sec:Chapter6]{Capítulo 6}
\begin{itemize}
\item El comando getopts del Shell de Bourne de SVR4 es similar, pero no idéntico, al de \emph{ksh}. No permite opciones que comienzan con un signo más, ni ninguna de las características avanzadas descritas en el \hyperref[sec:ApendiceB]{Apéndice B}.
\item El comando \emph{getopts} del Shell de Bourne de SVR4 es similar, pero no idéntico, al de \emph{ksh}. No permite opciones que comienzan con un signo más, ni ninguna de las características avanzadas descritas en el \hyperref[sec:ApendiceB]{Apéndice B}.
\item No se admite la aritmética: usa el comando externo \emph{expr} en lugar de la sintaxis \texttt{\$((...))}. Para condicionales numéricas, usa la antigua sintaxis de prueba de condición y los operadores relacionales \texttt{-lt, -eq}, etc., en lugar de \texttt{((...))}. No se admite \emph{let}.
\item No se admiten variables de matriz y el comando \emph{typeset}.
\end{itemize}
@ -96,12 +96,12 @@ Para describir las diferencias entre el Shell de Bourne y el Korn shell, revisar
\item No se admite \emph{print} (usa \emph{echo} en su lugar). \emph{printf} generalmente está disponible como un comando externo.
\item Ninguna de las opciones de \emph{read} es compatible, ni la capacidad de proporcionar un indicador con el nombre de la primera variable.
\item El Shell de Bourne no hace interpretaciones especiales de rutas, como \texttt{/dev/fd/2} o \texttt{/dev/tcp/ftp.oreilly.com/ftp}.
\item Los mecanismos de cotización \texttt{\$"..."} y \texttt{\$'...'} no están disponibles.
\item Los mecanismos de comillas \texttt{\$"..."} y \texttt{\$'...'} no están disponibles.
\end{itemize}
\item \hyperref[sec:Chapter8]{Capítulo 8}
\begin{itemize}
\item Se admite el control de trabajos, pero solo si el shell se invoca con la opción \texttt{-j} o como \emph{jsh}.
\item La opción \texttt{-} a trap (restablecer trap al valor predeterminado para esa señal) no está disponible. En su lugar, la falta de un trap indica que se deben restablecer las trampas suministradas. \emph{trap} acepta solo números de señales, no nombres lógicos.
\item La opción \texttt{-} a \emph{trap} (restablecer \emph{trap} al valor predeterminado para esa señal) no está disponible. En su lugar, la falta de un \emph{trap} indica que se deben restablecer las trampas suministradas. \emph{trap} acepta solo números de señales, no nombres lógicos.
\item No se admiten las corutinas.
\item El comando \emph{wait} solo acepta identificadores de procesos.
\end{itemize}
@ -121,7 +121,7 @@ Para describir las diferencias entre el Shell de Bourne y el Korn shell, revisar
\end{enumerate}
\section{El Shell Korn de 1988}
Quizás el shell más evidente con el que comparar \emph{ksh93} sea \emph{ksh88}, la versión de 1988 del shell Korn. Esta sección describe brevemente aquellas características de \emph{ksh93} que son diferentes o inexistentes en \emph{ksh88}. Al igual que con la presentación para el shell Bourne, los temas se cubren en el mismo orden en que se presentan en el resto del libro.
Quizás el shell más evidente con el que comparar \emph{ksh93} sea \emph{ksh88}, la versión de 1988 del shell de Korn. Esta sección describe brevemente aquellas características de \emph{ksh93} que son diferentes o inexistentes en \emph{ksh88}. Al igual que con la presentación para el shell de Bourne, los temas se cubren en el mismo orden en que se presentan en el resto del libro.
\begin{enumerate}
\item \hyperref[sec:Chapter1]{Capítulo 1}
@ -154,7 +154,7 @@ Quizás el shell más evidente con el que comparar \emph{ksh93} sea \emph{ksh88}
\end{itemize}
\item \hyperref[sec:Chapter4]{Capítulo 4}
\begin{itemize}
\item En \emph{ksh88}, ambas sintaxis para definir funciones producen funciones con semántica de shell Korn. No puedes aplicar el comando dot a un nombre de función.
\item En \emph{ksh88}, ambas sintaxis para definir funciones producen funciones con semántica de shell de Korn. No puedes aplicar el comando dot a un nombre de función.
\item El orden de búsqueda de comandos en \emph{ksh88} es palabras clave, aliases, todos los comandos internos, funciones, y luego comandos externos y scripts. El orden fue cambiado en \emph{ksh93} para cumplir con POSIX.
\item En \emph{ksh88}, las funciones no definidas (\emph{autoloaded}) se buscan exclusivamente a lo largo de la lista en la variable \texttt{FPATH}, y \texttt{PATH} no está involucrado.
\item La característica del archivo \emph{.paths} no está disponible.
@ -172,7 +172,7 @@ Quizás el shell más evidente con el que comparar \emph{ksh93} sea \emph{ksh88}
\end{itemize}
\item \hyperref[sec:Chapter6]{Capítulo 6}
\begin{itemize}
\item La versión de getopts de \emph{ksh88} no tenía la capacidad de especificar argumentos numéricos para opciones, ni una forma de especificar argumentos opcionales para opciones.
\item La versión de \emph{getopts} de \emph{ksh88} no tenía la capacidad de especificar argumentos numéricos para opciones, ni una forma de especificar argumentos opcionales para opciones.
\item La aritmética integrada solo admite enteros, y los operadores ++, --, ?: y coma no están disponibles. Las constantes numéricas de la forma \texttt{base\#número} solo pueden llegar hasta la base 36. No hay funciones aritméticas integradas.
\item Solo existen arrays indexados, y el índice máximo es 1023.
\end{itemize}
@ -216,7 +216,7 @@ El primer estándar POSIX se publicó en 1988 y se revisó en 1996. Este, llamad
Los estándares POSIX nunca se pensaron como rígidos y absolutos. Los miembros del comité ciertamente no iban a poner armas en la cabeza de los implementadores del sistema operativo y obligarlos a adherirse. En cambio, los estándares están diseñados para ser lo suficientemente flexibles como para permitir tanto la coexistencia de software similar disponible, para que el código existente no esté en peligro de volverse obsoleto, como la adición de nuevas características, para que los proveedores tengan incentivos para innovar. En otras palabras, se supone que son el tipo de estándares de terceros que los proveedores podrían estar interesados en seguir.
Como resultado, la mayoría de los proveedores de Unix cumplen actualmente con ambos estándares. El shell Korn no es una excepción; se pretende que sea 100\% compatible con POSIX. Conviene estar familiarizado con lo que hay en el estándar si quieres escribir código que sea portable en diferentes sistemas.
Como resultado, la mayoría de los proveedores de Unix cumplen actualmente con ambos estándares. El shell de Korn no es una excepción; se pretende que sea 100\% compatible con POSIX. Conviene estar familiarizado con lo que hay en el estándar si quieres escribir código que sea portable en diferentes sistemas.
La parte del shell del estándar describe utilidades que deben estar presentes en todos los sistemas y otras que son opcionales, según la naturaleza del sistema. Una de esas opciones es la opción de Utilidades de Portabilidad del Usuario, que define estándares para el uso interactivo del shell y utilidades interactivas como el editor vi. El estándar, de aproximadamente 2000 páginas, está disponible a través del IEEE; para obtener información, ponte en contacto con el IEEE:
@ -243,9 +243,9 @@ Por otro lado, el diseño del shell debía servir como estándar en el que basar
Los diseñadores encontraron una manera de aliviar este dilema: decidieron que el estándar debería incluir no solo las características incluidas en el shell, sino también aquellas explícitamente omitidas y aquellas incluidas pero con funcionalidad no especificada. La última categoría permite que algunas innovaciones de shells existentes <<se cuelen>> sin formar parte del estándar, mientras que listar las características omitidas ayuda a los programadores a determinar qué características en los scripts de shell existentes no serán portables a los shells futuros.
El estándar POSIX se basa principalmente en el shell Bourne de System V. Por lo tanto, debes asumir que las características del shell Korn que no están presentes en el shell Bourne tampoco están incluidas en el estándar POSIX.
El estándar POSIX se basa principalmente en el shell de Bourne de System V. Por lo tanto, debes asumir que las características del shell de Korn que no están presentes en el shell de Bourne tampoco están incluidas en el estándar POSIX.
Sin embargo, el shell Korn contribuyó con algunas de sus características al estándar POSIX, incluyendo:
Sin embargo, el shell de Korn contribuyó con algunas de sus características al estándar POSIX, incluyendo:
\begin{itemize}
\item Sintaxis \texttt{\$((...))} para expresiones aritméticas.
@ -253,21 +253,21 @@ Sin embargo, el shell Korn contribuyó con algunas de sus características al es
\item Expansión de tilde (originalmente derivada del shell C).
\end{itemize}
Las siguientes características del shell Korn se dejan <<no especificadas>> en el estándar, lo que significa que su sintaxis es aceptable pero su funcionalidad no está estandarizada:
Las siguientes características del shell de Korn se dejan <<no especificadas>> en el estándar, lo que significa que su sintaxis es aceptable pero su funcionalidad no está estandarizada:
\begin{itemize}
\item Sintaxis \texttt{((...))} para condicionales aritméticos. Sin embargo, se incluyen los operadores de prueba aritmética introducidos en el \hyperref[sec:Chapter5]{Capítulo 5} (por ejemplo, \texttt{-eq, -lt}).
\item La sintaxis \texttt{[[...]]} para \emph{pruebas} condicionales. Debe usarse el comando de \emph{prueba} externo o \texttt{[...]} en su lugar. La versión del shell Korn de la prueba cumple con POSIX cuando se usa con no más de tres argumentos. (También cumple con cuatro argumentos, si el primer argumento es !).
\item La sintaxis \texttt{[[...]]} para \emph{pruebas} condicionales. Debe usarse el comando de \emph{prueba} externo o \texttt{[...]} en su lugar. La versión del shell de Korn de la prueba cumple con POSIX cuando se usa con no más de tres argumentos. (También cumple con cuatro argumentos, si el primer argumento es !).
\item La sintaxis para definir funciones que usa este libro. La otra sintaxis mostrada en el \hyperref[sec:Chapter4]{Capítulo 4} (\texttt{fname()} en lugar de \texttt{function fname}) se admite, con lo que describimos como <<semántica POSIX>>; ver más abajo.
\item La estructura de control \texttt{select}.
\item Solo se permiten números de señal si los números para ciertas señales clave (INT, TERM y algunas otras) son iguales que en las versiones históricas más importantes de Unix. En general, los scripts de shell deben usar nombres simbólicos para las señales.
\end{itemize}
El estándar POSIX admite funciones, pero la semántica es más débil que la de las funciones de estilo de \texttt{function} del shell Korn: las funciones no tienen trampas u opciones locales, y no es posible definir variables locales. (Por esta razón, \emph{ksh93} tiene dos sintaxis diferentes para definir funciones, con semánticas diferentes).
El estándar POSIX admite funciones, pero la semántica es más débil que la de las funciones de estilo de \texttt{function} del shell de Korn: las funciones no tienen trampas u opciones locales, y no es posible definir variables locales. (Por esta razón, \emph{ksh93} tiene dos sintaxis diferentes para definir funciones, con semánticas diferentes).
Se admiten bloques de código (\texttt{\{...;\}}). Para obtener máxima portabilidad, cuando desees llaves literales, debes entrecomillarlas (por razones demasiado complicadas para entrar aquí).
El estándar POSIX introdujo las siguientes características, que difieren del comportamiento tradicional del shell Bourne. \emph{ksh93} las admite todas:
El estándar POSIX introdujo las siguientes características, que difieren del comportamiento tradicional del shell de Bourne. \emph{ksh93} las admite todas:
\begin{itemize}
\item Se cambió el orden de búsqueda de comandos para permitir que ciertos comandos integrados sean anulados por funciones, ya que los alias no están incluidos en el estándar. Los comandos integrados se dividen en dos conjuntos según su posición en el orden de búsqueda de comandos: algunos se procesan antes que las funciones, otros después. Específicamente, los comandos integrados \emph{break}, : (no hacer nada), \emph{continue}, . (dot), \emph{eval, exec, exit, export, readonly, return, set, shift, trap,} y \emph{unse}t tienen prioridad sobre las funciones.
@ -279,10 +279,10 @@ El estándar POSIX introdujo las siguientes características, que difieren del c
Finalmente, debido a que el estándar POSIX está destinado a promover la portabilidad de scripts de shell, evita mencionar explícitamente características que solo se aplican al uso interactivo del shell, incluidos alias, modos de edición, teclas de control, y así sucesivamente. La opción de Utilidades de Portabilidad del Usuario cubre estos. También evita mencionar ciertos problemas clave de implementación: en particular, no hay requisito de que se use la multitarea para trabajos en segundo plano, subcadenas, etc. Esto se hizo para permitir la portabilidad a sistemas no multitarea como MS-DOS, de modo que, por ejemplo, el Toolkit MKS (ver más adelante en este apéndice) pueda ser compatible con POSIX.
\section{dtksh}
El Desk Top Korn Shell (\emph{dtksh}) es una parte estándar del \emph{Common Desktop Environment (CDE)}, disponible en sistemas Unix comerciales como Solaris, HP-UX y AIX. Está basado en una versión algo más antigua de \emph{ksh93}. Evolucionó a partir del programa anterior \emph{wksh}, el Windowing Korn shell, lanzado por Unix System Laboratories a fines de 1992. Es un Korn shell completo, compatible con la versión que describe este libro,\footnote{Las características enumeradas a lo largo del libro como introducidas en versiones <<recientes>> no estarán en \emph{dtksh}.}
El Desk Top Korn Shell (\emph{dtksh}) es una parte estándar del \emph{Common Desktop Environment (CDE)}, disponible en sistemas Unix comerciales como Solaris, HP-UX y AIX. Está basado en una versión algo más antigua de \emph{ksh93}. Evolucionó a partir del programa anterior \emph{wksh}, el Windowing shell de Korn, lanzado por Unix System Laboratories a fines de 1992. Es un shell de Korn completo, compatible con la versión que describe este libro,\footnote{Las características enumeradas a lo largo del libro como introducidas en versiones <<recientes>> no estarán en \emph{dtksh}.}
y tiene extensiones para la programación de interfaces gráficas de usuario (GUI) en el entorno del sistema X Window. Se encuentra típicamente en \texttt{/usr/dt/bin/dtksh}.
\emph{dtksh} admite el Toolkit gráfico OSF/Motif al poner sus rutinas a disposición como comandos integrados. Esto permite a los programadores combinar la fortaleza del Korn shell como un entorno de programación de sistemas Unix con el poder y la abstracción del Toolkit. El resultado es un entorno unificado para el desarrollo rápido y sencillo de software basado en gráficos.
\emph{dtksh} admite el Toolkit gráfico OSF/Motif al poner sus rutinas a disposición como comandos integrados. Esto permite a los programadores combinar la fortaleza del shell de Korn como un entorno de programación de sistemas Unix con el poder y la abstracción del Toolkit. El resultado es un entorno unificado para el desarrollo rápido y sencillo de software basado en gráficos.
Existen varias herramientas de desarrollo de GUI que permiten construir interfaces de usuario con un editor basado en gráficos en lugar de con código de lenguaje de programación. Pero tales herramientas suelen ser enormes, costosas y complejas. \emph{dtksh}, por otro lado, es económico e insuperable en cuanto a su integración suave con Unix; ¡es la única herramienta de este tipo que puedes usar como tu shell de inicio de sesión! (Bueno, casi; consulta la siguiente sección). Es una opción definitiva para los programadores de sistemas que utilizan estaciones de trabajo basadas en X y necesitan una herramienta de prototipado rápido.
@ -314,7 +314,7 @@ El siguiente libro está dedicado a \emph{dtksh}: \emph{Desktop KornShell Graphi
En 1996, mientras era estudiante de posgrado en informática en la Universidad de Princeton, el Dr. Jeffrey L. Korn \footnote{Sí, el hijo de David Korn. Ahora trabaja en el mismo centro de investigación que su padre en AT\&T Laboratories, aunque en un área diferente.}
escribió \emph{tksh}. Esta es una integración de \emph{ksh93} con Tcl/Tk. La siguiente cita (de la página web de investigación del Dr. Korn) lo resume bien:
\emph{Tksh} es un lenguaje gráfico (similar a Visual Basic o Tcl/Tk) que utiliza KornShell (\emph{ksh93}) para la creación de scripts y Tk para la interfaz gráfica de usuario. Tksh está implementado como una extensión de \emph{ksh93} y permite que las bibliotecas de Tcl, como Tk, se ejecuten sobre \emph{ksh93} sin cambios. \emph{ksh93} es adecuado para la creación de scripts gráficos porque es compatible con \emph{sh}, lo que facilita tanto el aprendizaje como la extensión de scripts existentes para proporcionar una interfaz de usuario. Tksh también permite que los scripts de Tcl se ejecuten sin modificaciones, lo que hace posible combinar componentes escritos en Tcl o \emph{ksh93}.
\emph{Tksh} es un lenguaje gráfico (similar a Visual Basic o Tcl/Tk) que utiliza KornShell (\emph{ksh93}) para la creación de scripts y Tk para la interfaz gráfica de usuario. \emph{Tksh} está implementado como una extensión de \emph{ksh93} y permite que las bibliotecas de Tcl, como Tk, se ejecuten sobre \emph{ksh93} sin cambios. \emph{ksh93} es adecuado para la creación de scripts gráficos porque es compatible con \emph{sh}, lo que facilita tanto el aprendizaje como la extensión de scripts existentes para proporcionar una interfaz de usuario. \emph{Tksh} también permite que los scripts de Tcl se ejecuten sin modificaciones, lo que hace posible combinar componentes escritos en Tcl o \emph{ksh93}.
La página de inicio de \emph{tksh} todavía está en Princeton: \url{http://www.cs.princeton.edu/\~{}jlk/tksh/}. Tiene enlaces a documentos y documentación que se pueden descargar e imprimir. Sin embargo, el enlace a los ejecutables de \emph{tksh} está desactualizado. El código fuente de \emph{tksh} está disponible en AT\&T Research como parte del paquete ast-open, que también contiene \emph{ksh93} y reimplementaciones de muchas otras herramientas de Unix. Consulta el \hyperref[sec:ApendiceC]{Apéndice C} para obtener más información.
@ -377,9 +377,9 @@ Lo interesante de \emph{tksh}, además de la interesante combinación de tecnolo
\section{pdksh}
Muchos de los sistemas tipo Unix de código abierto, como GNU/Linux, vienen con el Public Domain Korn Shell, \emph{pdksh}. \emph{pdksh} está disponible como código fuente; comienza en su página de inicio: \url{http://www.cs.mun.ca/\~{}michael/pdksh/}. Incluye instrucciones para la construcción e instalación en varias plataformas Unix.
\emph{pdksh} fue originalmente escrito por Eric Gisin, quien lo basó en el clon de dominio público del shell Bourne de la Versión 7 creado por Charles Forsyth. Es en su mayoría compatible con el Korn shell de 1988 y POSIX, con algunas extensiones propias.
\emph{pdksh} fue originalmente escrito por Eric Gisin, quien lo basó en el clon de dominio público del shell de Bourne de la Versión 7 creado por Charles Forsyth. Es en su mayoría compatible con el shell de Korn de 1988 y POSIX, con algunas extensiones propias.
Su modo de edición en \emph{emacs} es en realidad más potente que el del Korn shell de 1988. Al igual que el editor Emacs completo, puedes personalizar las teclas que invocan comandos de edición (conocidos como \emph{key bindings} en la terminología de Emacs). Los comandos de edición tienen nombres completos que puedes asociar con teclas mediante el uso del comando \emph{bind}.
Su modo de edición en \emph{emacs} es en realidad más potente que el del shell de Korn de 1988. Al igual que el editor Emacs completo, puedes personalizar las teclas que invocan comandos de edición (conocidos como \emph{key bindings} en la terminología de Emacs). Los comandos de edición tienen nombres completos que puedes asociar con teclas mediante el uso del comando \emph{bind}.
Por ejemplo, si quieres configurar CTRL-U para hacer lo mismo que CTRL-P (es decir, retroceder al comando anterior en el archivo de historial), podrías poner este comando en tu \emph{.profile}:
@ -425,9 +425,9 @@ gnu@gnu.org \\
Hoy en día, los ideales de los movimientos de Software Libre y Código Abierto, el proyecto GNU y la calidad del software GNU son bien conocidos. El sistema GNU más popular es GNU/Linux, que utiliza el núcleo Linux y las utilidades GNU para crear un entorno de computación completo, totalmente funcional y compatible con Unix y POSIX.
\emph{bash} es totalmente compatible con el estándar POSIX de 1992. Tiene varias de las características más importantes del Korn shell y las características del C shell que el Korn shell ha adoptado, incluyendo alias, funciones, notación de tilde, modos de edición emacs y vi, expresiones aritméticas, control de trabajos, etc.
\emph{bash} es totalmente compatible con el estándar POSIX de 1992. Tiene varias de las características más importantes del shell de Korn y las características del C shell que el shell de Korn ha adoptado, incluyendo alias, funciones, notación de tilde, modos de edición emacs y vi, expresiones aritméticas, control de trabajos, etc.
La superposición de características entre \emph{bash} y el Korn shell ha aumentado en los últimos años. Incluye muchas características del \emph{ksh93}. Pero no es un clon exacto de \emph{ksh}. El FAQ de \emph{bash}, publicado mensualmente por Chet Ramey, enumera las siguientes diferencias entre \emph{bash} y \emph{ksh93}. Los elementos incluidos entre corchetes (\texttt{[...]}) están listados en este libro, pero no en el FAQ.
La superposición de características entre \emph{bash} y el shell de Korn ha aumentado en los últimos años. Incluye muchas características del \emph{ksh93}. Pero no es un clon exacto de \emph{ksh}. El FAQ de \emph{bash}, publicado mensualmente por Chet Ramey, enumera las siguientes diferencias entre \emph{bash} y \emph{ksh93}. Los elementos incluidos entre corchetes (\texttt{[...]}) están listados en este libro, pero no en el FAQ.
Lo siguiente, en \emph{ksh93}, no está disponible en \emph{bash} 2.05:
@ -488,7 +488,7 @@ Lo siguiente, en \emph{ksh93}, está presente en \emph{bash} 2.05:
\emph{bash} tiene muchas características propias que lo convierten en un entorno muy potente y flexible. Aquí tienes algunas de las características destacadas:
\begin{itemize}
\item Puedes poner escapes de barra invertida en la cadena de texto del indicador primario (\texttt{PS1}), en la que bash sustituye cosas como la fecha, hora, directorio de trabajo actual, nombre de la máquina, nombre de usuario, shell, etc.
\item Puedes poner escapes de barra invertida en la cadena de texto del indicador primario (\texttt{PS1}), en la que \emph{bash} sustituye cosas como la fecha, hora, directorio de trabajo actual, nombre de la máquina, nombre de usuario, shell, etc.
\item Los comandos integrados, \emph{command} y \emph{enable}, te brindan más control sobre los pasos que sigue \emph{bash} para buscar comandos, es decir, el equivalente de \emph{bash} a la lista de pasos de búsqueda de comandos en el \hyperref[sec:Chapter7]{Capítulo 7}.
\item El modo de edición \emph{emacs} es personalizable, incluso más que su equivalente en \emph{pdksh}. Puedes usar el comando \emph{bind} para configurar tus propias preferencias de teclas, y hay varios comandos más disponibles, incluida la capacidad de deshacer tu último comando.
\item También puedes volver a asignar teclas en el modo de edición \emph{vi}.
@ -497,7 +497,7 @@ Lo siguiente, en \emph{ksh93}, está presente en \emph{bash} 2.05:
\item Muchas opciones y variables nuevas te permiten personalizar tu entorno con una flexibilidad sin precedentes. Esto incluye \texttt{set -o posix} para una conformidad estricta con POSIX.
\end{itemize}
Nos sentimos obligados a decir que muchos usuarios prefieren \emph{bash} al Korn shell. Con la creciente popularidad de GNU/Linux y varios sistemas derivados de BSD, no está claro qué shell tiene una base de usuarios más grande. En cualquier caso, \emph{bash} es definitivamente una excelente elección. Recomendamos el libro \emph{Learning the bash Shell} de Cameron Newham y Bill Rosenblatt, publicado por O'Reilly \& Associates. (Está basado en la primera edición de este libro).
Nos sentimos obligados a decir que muchos usuarios prefieren \emph{bash} al shell de Korn. Con la creciente popularidad de GNU/Linux y varios sistemas derivados de BSD, no está claro qué shell tiene una base de usuarios más grande. En cualquier caso, \emph{bash} es definitivamente una excelente elección. Recomendamos el libro \emph{Learning the bash Shell} de Cameron Newham y Bill Rosenblatt, publicado por O'Reilly \& Associates. (Está basado en la primera edición de este libro).
\section{zsh}
\emph{zsh} es un potente shell interactivo y lenguaje de secuencias de comandos con muchas características que se encuentran en \emph{ksh, bash} y \emph{tcsh}, así como varias características únicas. \emph{zsh} tiene la mayoría de las características de \emph{ksh88} pero pocas de \emph{ksh93}. Está disponible de forma gratuita y debería compilar y ejecutarse en prácticamente cualquier versión moderna de Unix. También hay versiones para otros sistemas operativos. La página principal de \emph{zsh} es \url{http://www.zsh.org}. La versión actual es 4.0.2.
@ -513,7 +513,7 @@ En esta sección cubrimos:
\end{itemize}
\subsection{Globbing extendido}
Una característica muy útil es el operador glob recursivo \texttt{**}\footnote{El \emph{globbing} es un argot técnico para la expansión de comodines.}
Una característica muy útil es el operador emph{glob} recursivo \texttt{**}\footnote{El \emph{globbing} es un argot técnico para la expansión de comodines.}
. Por ejemplo, es sencillo construir una búsqueda recursiva con \emph{grep}:
\begin{lstlisting}[language=bash]
@ -684,7 +684,7 @@ Puedes ver que \emph{bart} es un indicador de dos líneas con varios componentes
\subsection{Diferencias entre \emph{zsh} y \emph{ksh}}
Esta sección se deriva de información en el FAQ de \emph{zsh}.
La mayoría de las características de \emph{ksh88} (y, por lo tanto, también del Shell de Bourne, \emph{sh}) están implementadas en zsh; pueden surgir problemas porque la implementación es ligeramente diferente. También ten en cuenta que no todas las \emph{ksh} son iguales. Esto se basa en la versión 11/16/88f de \emph{ksh}; las diferencias con \emph{ksh93} son más sustanciales.
La mayoría de las características de \emph{ksh88} (y, por lo tanto, también del Shell de Bourne, \emph{sh}) están implementadas en \emph{zsh}; pueden surgir problemas porque la implementación es ligeramente diferente. También ten en cuenta que no todas las \emph{ksh} son iguales. Esto se basa en la versión 11/16/88f de \emph{ksh}; las diferencias con \emph{ksh93} son más sustanciales.
Como resumen del estado:
@ -696,7 +696,7 @@ Como resumen del estado:
\item También a partir de 3.0, está disponible el comando \emph{emulate}: \texttt{emulate ksh} y \texttt{emulate sh} establecen varias opciones, así como cambian el efecto de las banderas de opciones de un solo carácter, como si el shell se hubiera invocado con el nombre apropiado. Incluir el comando \texttt{emulate sh; setopt localoptions} en una función del shell activa la emulación \emph{sh} solo para esa función. En 4.0 (y en 3.0.6 a 8), esto se puede abreviar como \texttt{emulate -L sh}.
\end{enumerate}
La diferencia clásica es la división de palabras: \emph{zsh} mantiene el resultado de \texttt{\$variable} como una sola palabra, incluso si la variable contiene espacios en blanco. Esto confunde a muchos \emph{usuarios principiantes de zsh}. La respuesta es establecer \texttt{SH\_WORD\_SPLIT} para compatibilidad hacia atrás. La siguiente diferencia más clásica es que los patrones de globs no coincidentes hacen que el comando \emph{abort}; establece \texttt{NO\_NOMATCH} para evitar eso.
La diferencia clásica es la división de palabras: \emph{zsh} mantiene el resultado de \texttt{\$variable} como una sola palabra, incluso si la variable contiene espacios en blanco. Esto confunde a muchos \emph{usuarios principiantes de zsh}. La respuesta es establecer \texttt{SH\_WORD\_SPLIT} para compatibilidad hacia atrás. La siguiente diferencia más clásica es que los patrones de \emph{globs} no coincidentes hacen que el comando \emph{abort}; establece \texttt{NO\_NOMATCH} para evitar eso.
\emph{zsh} tiene un conjunto grande de opciones que aumentan la compatibilidad con \emph{ksh}, aunque tal vez disminuyan las habilidades de \emph{zsh}: consulta las entradas del manual para más detalles. Si se invoca como \emph{ksh}, el shell establece las opciones adecuadas.
@ -715,14 +715,14 @@ El manejo de los descriptores de archivo de coproceso también es diferente.
\emph{Substituciones de línea de comandos, globbing, etc.}
\begin{itemize}
\item \nmid{} La falta de coincidencia con un patrón de globbing provoca un error (usa \texttt{NO\_NOMATCH}).
\item \nmid{} La falta de coincidencia con un patrón de \emph{globbing} provoca un error (usa \texttt{NO\_NOMATCH}).
\item \nmid{} Los resultados de las sustituciones de parámetros se tratan como texto plano: \texttt{foo="*"; print \$foo} imprime todos los archivos en \emph{ksh} pero imprime * en \emph{zsh} (usa \texttt{GLOB\_SUBST}).
\item \nmid{} Las variables de indicador (por ejemplo, \texttt{PS1}) no sufren sustitución de parámetros por defecto (usa \texttt{PROMPT\_SUBST}).
\item \nmid{} El globbing estándar no permite listas de patrones al estilo \emph{ksh}. La Tabla \ref{Tab:A-1} muestra patrones equivalentes.\\
Las formas \^{}, \~{} y \# (pero no |) requieren establecer \texttt{EXTENDED\_GLOB}. A partir de la versión 3.1.3, las formas de \emph{ksh} son completamente compatibles cuando está en efecto la opción \texttt{KSH\_GLOB}; para versiones anteriores debes usar los equivalentes dados en la Tabla \ref{Tab:A-1}.
\item Las asignaciones no entrecomilladas hacen la expansión de archivos después de los dos puntos (destinado para variables de estilo \texttt{PATH}).
\item \emph{integer} no permite \texttt{-i}.
\item \emph{typeset} e integer tienen un comportamiento especial para las asignaciones en ksh, pero no en \emph{zsh}. Por ejemplo, esto no funciona en \emph{zsh}:
\item \emph{typeset} e \emph{integer} tienen un comportamiento especial para las asignaciones en \emph{ksh}, pero no en \emph{zsh}. Por ejemplo, esto no funciona en \emph{zsh}:
\begin{lstlisting}[language=bash]
integer k=$(wc -l ~/.zshrc)
@ -739,7 +739,7 @@ porque el valor de retorno de \emph{wc} incluye espacios en blanco iniciales, lo
\begin{tabular}{|m{2cm}|m{2cm}|m{11cm}|} \hline
\textbf{ksh} & \textbf{zsh} & \textbf{Significado} \\ \hline
!(foo) & \^{}foo & Cualquier cosa menos \emph{foo} \\\hline
& foo1\~{}foo2 & Cualquier cosa que coincida con foo1 pero no con foo2.\tablefootnote{Ten en cuenta que \~{} es el único operador de globbing que tiene una precedencia inferior a /. Por ejemplo, \texttt{**/foo\~{}*bar*} coincide con cualquier archivo en un subdirectorio llamado \emph{foo}, excepto donde \emph{bar} ocurrió en alguna parte de la ruta (por ejemplo, \texttt{users/barstaff/foo} será excluido por el operador \~{}). Como el operador \texttt{**} no puede agruparse (dentro de paréntesis se trata como *), esta es la manera de excluir algunos subdirectorios de hacer coincidir un \texttt{**}.} \\\hline
& foo1\~{}foo2 & Cualquier cosa que coincida con foo1 pero no con foo2.\tablefootnote{Ten en cuenta que \~{} es el único operador de \emph{globbing} que tiene una precedencia inferior a /. Por ejemplo, \texttt{**/foo\~{}*bar*} coincide con cualquier archivo en un subdirectorio llamado \emph{foo}, excepto donde \emph{bar} ocurrió en alguna parte de la ruta (por ejemplo, \texttt{users/barstaff/foo} será excluido por el operador \~{}). Como el operador \texttt{**} no puede agruparse (dentro de paréntesis se trata como *), esta es la manera de excluir algunos subdirectorios de hacer coincidir un \texttt{**}.} \\\hline
@(foo1|foo2|...) & (foo1|foo2|...) & \emph{foo1} o \emph{foo2} o ... \\\hline
?(foo) & (foo|) & Cero o una ocurrencia de \emph{foo} \\\hline
*(foo) & (foo)\# & Cero o más ocurrencias de \emph{foo} \\\hline
@ -775,9 +775,9 @@ porque el valor de retorno de \emph{wc} incluye espacios en blanco iniciales, lo
\emph{Edición}
\begin{itemize}
\item Las opciones \emph{emacs, gmacs} y \emph{viraw} no son compatibles. Usa \emph{bindkey} para cambiar el comportamiento de edición: \texttt{set -o emacs} se convierte en \texttt{bindkey -e} y \texttt{set -o vi} se convierte en \texttt{bindkey -v}; para \emph{gmacs}, ve a \emph{emacs-mode} y usa \texttt{bindkey \textbackslash\^{}t gosmacs-transpose-characters}.
\item Las opciones \emph{emacs, gmacs} y \emph{viraw} no son compatibles. Usa \emph{bindkey} para cambiar el comportamiento de edición: \texttt{set -o emacs} se convierte en \texttt{bindkey -e} y \texttt{set -o vi} se convierte en \texttt{bindkey -v}; para \emph{gmacs}, ve a \emph{emacs-moda} y usa \texttt{bindkey \textbackslash\^{}t gosmacs-transpose-characters}.
\item La opción de \emph{palabra clave} no existe y \texttt{set -k} es en su lugar \emph{interactivecomments}.
\item \nmid{} La gestión de historiales en múltiples shells es diferente: la lista de historiales no se guarda y restaura después de cada comando. La opción \texttt{SHARE\_HISTORY} apareció en 3.1.6 y se establece en el modo de compatibilidad con ksh para remediar esto.
\item \nmid{} La gestión de historiales en múltiples shells es diferente: la lista de historiales no se guarda y restaura después de cada comando. La opción \texttt{SHARE\_HISTORY} apareció en 3.1.6 y se establece en el modo de compatibilidad con \emph{ksh} para remediar esto.
\item \textbackslash{} no escapa caracteres de edición (usa CTRL-V).
\item No se establecen todos los enlaces de \emph{ksh} (por ejemplo, ESC \#; prueba ESC q).
\item \nmid{} \# en una shell interactiva no se trata como un comentario por defecto.
@ -799,7 +799,7 @@ porque el valor de retorno de \emph{wc} incluye espacios en blanco iniciales, lo
\end{itemize}
\section{Sustitutos en Plataformas PC}
La proliferación del shell Korn no se detuvo en los límites de Unix. Muchos programadores que obtuvieron su experiencia inicial en sistemas Unix y posteriormente cruzaron al mundo de PC deseaban un entorno agradable tipo Unix (especialmente cuando se enfrentaban a los horrores de la línea de comandos MS-DOS), así que no sorprende que hayan aparecido varias interfaces tipo shell Unix para sistemas operativos de pequeñas computadoras, entre ellas, emulaciones del shell Korn.
La proliferación del shell de Korn no se detuvo en los límites de Unix. Muchos programadores que obtuvieron su experiencia inicial en sistemas Unix y posteriormente cruzaron al mundo de PC deseaban un entorno agradable tipo Unix (especialmente cuando se enfrentaban a los horrores de la línea de comandos MS-DOS), así que no sorprende que hayan aparecido varias interfaces tipo shell Unix para sistemas operativos de pequeñas computadoras, entre ellas, emulaciones del shell de Korn.
En los últimos años, no solo han aparecido clones de shell, sino entornos Unix <<completo>>. Dos de ellos utilizan shells que ya hemos discutido. Dos proporcionan sus propias re-implementaciones del shell. Proporcionar listas de diferencias mayores y menores es contraproducente. En cambio, esta sección describe cada entorno a su vez (en orden alfabético), junto con información de contacto y descarga en Internet.
@ -833,7 +833,7 @@ Canadá \\
\url{http://www.mks.com}
\end{footnotesize}
MKS Toolkit viene en varias versiones dependiendo del entorno de desarrollo y la cantidad de desarrolladores que lo utilizarán. Incluye un shell que cumple con POSIX, junto con casi todas las características del shell Korn de 1988, así como más de 300 utilidades como \emph{awk, perl, vi, make,} y demás. Su biblioteca admite más de 1500 API de Unix, haciéndola extremadamente completa y facilitando la portabilidad al entorno Windows. Más información está disponible en \url{http://www.mkssoftware.com/products/tk/ds_tkpdev.asp}.
MKS Toolkit viene en varias versiones dependiendo del entorno de desarrollo y la cantidad de desarrolladores que lo utilizarán. Incluye un shell que cumple con POSIX, junto con casi todas las características del shell de Korn de 1988, así como más de 300 utilidades como \emph{awk, perl, vi, make,} y demás. Su biblioteca admite más de 1500 API de Unix, haciéndola extremadamente completa y facilitando la portabilidad al entorno Windows. Más información está disponible en \url{http://www.mkssoftware.com/products/tk/ds_tkpdev.asp}.
\subsection{Thompson Automation Software Toolkit}
Thompson Automation Software proporciona el Thompson Toolkit, que incluye un shell y más de 100 utilidades. El kit está disponible para MS-DOS 2.1 y superior, OS/2 1.2 o WARP y para Microsoft Windows 95 y superior. La información de contacto es:
@ -850,7 +850,7 @@ sales@tasoft.com \\
\url{http://www.tasoft.com/toolkit.html/}
\end{footnotesize}
El software de Thompson es conocido por su implementación de \emph{awk}, que es rápida y confiable, con muchas extensiones poderosas al lenguaje awk. El shell del toolkit es compatible con POSIX y la versión 1988 del shell Korn.
El software de Thompson es conocido por su implementación de \emph{awk}, que es rápida y confiable, con muchas extensiones poderosas al lenguaje awk. El shell del toolkit es compatible con POSIX y la versión 1988 del shell de Korn.
\subsection{AT\&T UWIN}
El paquete UWIN es un proyecto de David Korn y sus colegas para poner un entorno Unix disponible bajo Microsoft Windows. Es similar en estructura a \emph{Cygwin}, discutido anteriormente. Una biblioteca compartida, \emph{posix.dll}, proporciona emulación de las APIs de llamadas al sistema Unix. La emulación de llamadas al sistema es bastante completa. Un giro interesante es que el registro de Windows se puede acceder como un sistema de archivos bajo \texttt{/reg}. Sobre la emulación de la API de Unix, se han compilado y ejecutado \emph{ksh93} y más de 200 utilidades Unix (o más bien, re-implementaciones). El entorno UWIN depende del compilador nativo de Microsoft Visual C/C++, aunque las herramientas de desarrollo GNU están disponibles para descargar y usar con UWIN.

View File

@ -1,7 +1,7 @@
Este apéndice contiene listas de referencia para opciones de invocación, comandos incorporados y palabras clave, alias predefinidos, variables de shell incorporadas, operadores de \emph{prueba}, opciones de shell, opciones de \emph{typeset}, aritmética, comandos en modo \emph{emacs} y comandos de control en modo \emph{vi}. Además, describe cómo utilizar todas las facilidades del comando incorporado \emph{getopts}.
\section{Opciones de invocación}
Esta es una lista de las opciones que puede usar cuando invoque al shell Korn. Además de éstas, se puede utilizar cualquier opción establecida en la línea de órdenes; consulte la tabla de opciones más adelante en este apéndice. Los intérpretes de comandos de inicio de sesión suelen invocarse con las opciones \texttt{-i} (interactivo), \texttt{-s} (leer de la entrada estándar) y \texttt{-m} (habilitar el control de trabajos).
Esta es una lista de las opciones que puede usar cuando invoque al shell de Korn. Además de éstas, se puede utilizar cualquier opción establecida en la línea de órdenes; consulte la tabla de opciones más adelante en este apéndice. Los intérpretes de comandos de inicio de sesión suelen invocarse con las opciones \texttt{-i} (interactivo), \texttt{-s} (leer de la entrada estándar) y \texttt{-m} (habilitar el control de trabajos).
\begin{table}[h]
\center
@ -227,7 +227,7 @@ Los operadores \emph{-eq, -ne, -lt, -le, -gt} y \emph{-ge} se consideran obsolet
Para =, == y !=, cite el patrón para realizar comparaciones literales de strings.
\section{Opciones}
Son opciones que pueden activarse con el comando \texttt{set -o}. Todas están inicialmente desactivadas excepto donde se indique lo contrario. Las abreviaturas, cuando aparecen, son opciones de set que pueden utilizarse en lugar de la orden \texttt{set -o} completa (por ejemplo, \texttt{set -a} es una abreviatura de \texttt{set -o allexport}). En la mayoría de los casos, las abreviaturas son opciones del shell Bourne compatibles con versiones anteriores. Para desactivar una opción, utilice \texttt{set +o nombre largo} o \texttt{set +X}, donde \emph{nombre largo} y \emph{X} son la <<forma larga>> o la forma de <<un solo carácter>> de la opción, respectivamente.
Son opciones que pueden activarse con el comando \texttt{set -o}. Todas están inicialmente desactivadas excepto donde se indique lo contrario. Las abreviaturas, cuando aparecen, son opciones de set que pueden utilizarse en lugar de la orden \texttt{set -o} completa (por ejemplo, \texttt{set -a} es una abreviatura de \texttt{set -o allexport}). En la mayoría de los casos, las abreviaturas son opciones del shell de Bourne compatibles con versiones anteriores. Para desactivar una opción, utilice \texttt{set +o nombre largo} o \texttt{set +X}, donde \emph{nombre largo} y \emph{X} son la <<forma larga>> o la forma de <<un solo carácter>> de la opción, respectivamente.
\begin{longtable}[h]{|p{2cm}|p{2.5cm}|p{11.5cm}|} \hline
\textbf{Opción} & \small{\textbf{Abreviatura}} & \textbf{Significado} \\ \hline
@ -365,7 +365,7 @@ $ print $u
\texttt{< <= > >=} & Comparaciones & De izquierda a derecha \\\hline
\texttt{== !=} & Iguales y no iguales & De izquierda a derecha \\\hline
\texttt{\&} & Bit a bit <<y>> & De izquierda a derecha \\\hline
\texttt{\^{}} & <<O>> exlusivo bit a bit & de Izquierda a derecha \\\hline
\texttt{\^{}} & <<O>> exclusivo bit a bit & de Izquierda a derecha \\\hline
\texttt{|} & Bit a bit <<o>> & De izquierda a derecha \\\hline
\texttt{\&\&} & AND lógico & De izquierda a derecha \\\hline
\texttt{||} & OR lógico & De izquierda a derecha \\\hline
@ -375,7 +375,7 @@ $ print $u
\end{longtable}
\section{Comandos del modo Emacs}
Aquí tienes una lista completa de todos los comandos del modo de edición de emacs. Algunos de estos, como \texttt{ESC [ A,} representan secuencias de teclas de flecha de terminal estándar ANSI; se agregaron para \emph{ksh93h}.
Aquí tienes una lista completa de todos los comandos del modo de edición de \emph{emacs}. Algunos de estos, como \texttt{ESC [ A,} representan secuencias de teclas de flecha de terminal estándar ANSI; se agregaron para \emph{ksh93h}.
\begin{longtable}[h]{|p{3cm}|p{12cm}|} \hline
\textbf{Comando} & \textbf{Significado} \\\hline
@ -400,9 +400,9 @@ Aquí tienes una lista completa de todos los comandos del modo de edición de em
CTRL-R & Buscar hacia atrás \\\hline
CTRL-T & Intercambiar los dos caracteres a cada lado del punto \\\hline
CTRL-U & Repetir el siguiente comando cuatro veces \\\hline
CTRL-V & Imprimir la versión del shell Korn \\\hline
CTRL-V & Imprimir la versión del shell de Korn \\\hline
CTRL-W & Borrar (<<wipe>>) todos los caracteres entre el punto y la marca \\\hline
CTRL-X CTRL-E & Invocar el programa emacs en el comando actual \\\hline
CTRL-X CTRL-E & Invocar el programa \emph{emacs} en el comando actual \\\hline
CTRL-X CTRL-X & Intercambiar el punto y la marca \\\hline
CTRL-Y & Recuperar (<<yank>>) el último elemento eliminado \\\hline
CTRL-] x & Buscar hacia adelante x, donde x es cualquier carácter \\\hline
@ -523,15 +523,15 @@ v & Ejecutar el comando hist en la línea actual (en realidad, ejecutar el coman
CTRL-J & Igual que ENTER \\\hline
CTRL-L & Iniciar una nueva línea y volver a dibujar la línea actual en ella \\\hline
CTRL-M & Igual que ENTER \\\hline
CTRL-V & Imprimir la versión del shell Korn \\\hline
CTRL-V & Imprimir la versión del shell de Korn \\\hline
\# & Agregar \# (carácter de comentario) a la línea y enviarlo. Si la línea comienza con \#, quitar el \# inicial y todos los \# iniciales después de cualquier salto de línea incrustado \\\hline
@ x & Insertar expansión de alias \_x como entrada de modo de comando \\\hline
\end{longtable}
\section{Uso de getopts}
\section{Uso de \emph{getopts}}
El comando \emph{getopts} es extremadamente capaz. Con él, puedes hacer que tus scripts de shell acepten opciones largas, especificar que los argumentos son opcionales o numéricos, y proporcionar descripciones de los argumentos y valores para que las opciones \texttt{-?, --man, --html} y \texttt{--nroff} funcionen de la misma manera para tu programa que para los comandos internos de \emph{ksh93}.
El precio por este poder es la complejidad del <<lenguaje>> de descripción de opciones. Basándonos en una descripción proporcionada por el Dr. Glenn Fowler de AT\&T Research, describimos cómo evolucionaron las facilidades, cómo funcionan y resumimos cómo usarlas en tus propios programas. Usamos el comando getopts extendido en la solución para la \hyperref[box:B-1]{Tarea B-1}.
El precio por este poder es la complejidad del <<lenguaje>> de descripción de opciones. Basándonos en una descripción proporcionada por el Dr. Glenn Fowler de AT\&T Research, describimos cómo evolucionaron las facilidades, cómo funcionan y resumimos cómo usarlas en tus propios programas. Usamos el comando \emph{getopts} extendido en la solución para la \hyperref[box:B-1]{Tarea B-1}.
\begin{mybox}[Tarea B-1]\label{box:B-1}
Diseña el programa \emph{phaser4}, que combina las características de los programas \emph{phaser3} y \emph{tricorder}. Asegúrate de que sea autosuficiente.\footnote{No, las paredes de mi habitación no están cubiertas de pósters de Star Trek. Superé eso hace mucho tiempo, y además, mi esposa no me dejaría de todos modos. ADR.}
@ -691,7 +691,7 @@ while getopts "$USAGE" optchar ...
\item Finalmente, permite escapes dentro de las cadenas. \texttt{]]} representa un corchete de cierre literal cuando \emph{getopts} de otra manera podría interpretarlo como un corchete de cierre. De manera similar, ?? representa un signo de interrogación literal que de otra manera podría iniciar una descripción.
\end{enumerate}
Uff, ¡eso es mucha información! Sin embargo, verlo en el orden en que se agregó ayuda a que tenga sentido. Aquí tienes un resumen de los elementos que van en la cadena de uso, en el orden que requiere `getopts`:
Uff, ¡eso es mucha información! Sin embargo, verlo en el orden en que se agregó ayuda a que tenga sentido. Aquí tienes un resumen de los elementos que van en la cadena de uso, en el orden que requiere \emph{getopts}:
\begin{enumerate}
\item Las cadenas de identificación para la versión, autor, licencia, etc., son la primera parte. Están encerradas en corchetes y comienzan con un signo menos. El nombre del ítem, como <<author>>, sigue el signo menos y termina en un signo de interrogación. Después del signo de interrogación viene la información asociada.

View File

@ -1,12 +1,12 @@
Este apéndice describe cómo descargar binarios para \emph{ksh93}, así como cómo descargar el código fuente para \emph{ksh93} y construir una versión funcional. Deberías hacer esto si tu sistema no tiene \emph{ksh93} en absoluto o si necesitas alguna de las características que solo están disponibles en las versiones más recientes.
\section{Sitios web de Korn Shell}
El punto de partida para todo lo relacionado con el shell Korn es \url{http://www.kornshell.com}, mantenido por David Korn, con enlaces agrupados en las siguientes categorías:
El punto de partida para todo lo relacionado con el shell de Korn es \url{http://www.kornshell.com}, mantenido por David Korn, con enlaces agrupados en las siguientes categorías:
\begin{description}
\item[Información] Al hacer clic en este enlace, se accede a una descripción general de una página sobre el shell Korn.
\item[Información] Al hacer clic en este enlace, se accede a una descripción general de una página sobre el shell de Korn.
\item[Software] Al hacer clic en este enlace, se encuentran enlaces al sitio de descargas de AT\&T (ver la siguiente sección), algún código de ejemplo, un artículo en línea para \emph{dtksh} y un enlace para \emph{tksh}. Estos dos últimos se describen en el Apéndice A.
\item[Documentación] Este enlace lleva a una página con enlaces a información en línea, incluida información general, páginas de manual tanto para \emph{ksh88} como para \emph{ksh93}, libros y referencias sobre el shell Korn, y documentos sobre el shell Korn de diversas conferencias.
\item[Documentación] Este enlace lleva a una página con enlaces a información en línea, incluida información general, páginas de manual tanto para \emph{ksh88} como para \emph{ksh93}, libros y referencias sobre el shell de Korn, y documentos sobre el shell de Korn de diversas conferencias.
\item[Recursos] Una lista de enlaces a otros recursos en la web para \emph{ksh} y muchos de los otros shells descritos en el Apéndice A, como \emph{bash} y \emph{dtksh}.
\item[Diversión] David G. Korn, el programador, se encuentra con KoRN, el grupo de rock. Dicho y hecho.
\end{description}
@ -14,10 +14,10 @@ El punto de partida para todo lo relacionado con el shell Korn es \url{http://ww
\section{Lo que puedes descargar}
\url{http://www.research.att.com/sw/download} es el punto de partida para descargar el software de \emph{ksh}. El software está cubierto por una licencia de estilo de código abierto. La versión actual de la licencia se encuentra en \url{http://www.research.att.com/sw/license/ast-open.html}. Esta licencia se reproduce en el Apéndice D. Deberías leerla y entenderla primero; si sus términos no son aceptables para ti, no deberías descargar el código fuente o binarios del software desde el sitio web de AT\&T.
El software en el sitio web de AT\&T está disponible en diferentes <<paquetes>>, la mayoría de los cuales tienen nombres con el prefijo <<ast>>, que significa \emph{Advanced Software Tools} (Herramientas de Software Avanzado). Los paquetes de origen vienen como archivos tar comprimidos con \emph{gzip}, usando el sufijo de nombre de archivo \emph{.tgz}. Elige uno o más de los siguientes paquetes para descargar:
El software en el sitio web de AT\&T está disponible en diferentes <<paquetes>>, la mayoría de los cuales tienen nombres con el prefijo <<ast>>, que significa \emph{Advanced Software Tools} (Herramientas de Software Avanzado). Los paquetes de origen vienen como archivos \emph{tar} comprimidos con \emph{gzip}, usando el sufijo de nombre de archivo \emph{.tgz}. Elige uno o más de los siguientes paquetes para descargar:
\begin{description}
\item[ratz] Un programa ejecutable independiente para leer archivos tar comprimidos con \emph{gzip}. Úsalo si no tienes \emph{gzip} en tu sistema y no quieres molestarte en descargar y compilar \emph{gzip} primero. Puedes descargar el código fuente para este paquete o un ejecutable binario para cualquiera de las arquitecturas enumeradas en la Tabla \ref{Tab:C-1}.
\item[ratz] Un programa ejecutable independiente para leer archivos \emph{tar} comprimidos con \emph{gzip}. Úsalo si no tienes \emph{gzip} en tu sistema y no quieres molestarte en descargar y compilar \emph{gzip} primero. Puedes descargar el código fuente para este paquete o un ejecutable binario para cualquiera de las arquitecturas enumeradas en la Tabla \ref{Tab:C-1}.
\item[ksh] Esta es la forma más rápida de obtener un ejecutable de \emph{ksh93}. Hay versiones disponibles para las arquitecturas enumeradas en la Tabla \ref{Tab:C-1}.
\item[INIT] Este paquete debe descargarse al construir cualquiera de los siguientes paquetes fuente. Contiene los archivos y estructuras de directorio en los que dependen las herramientas y el sistema de construcción de AST.
\item[ast-ksh] Este paquete construye solo la infraestructura de soporte (bibliotecas, programas de prueba de entorno, etc.) para \emph{ksh} y el ejecutable \emph{ksh}. Es lo más sencillo de construir.

View File

@ -2,7 +2,7 @@ Usted ha utilizado su ordenador para realizar tareas sencillas, como invocar sus
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 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.
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:
@ -31,7 +31,7 @@ Recuerde que el shell en sí mismo no es Unix - sólo la interfaz de usuario par
\end{figure}
\section{Alcance de Este Libro}
En este libro, aprenderá sobre el shell 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 Korn: como interfaz de usuario y como entorno de programación.
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.
@ -39,53 +39,53 @@ Después de haber utilizado el shell durante un tiempo, sin duda encontrará cie
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 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.
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 Bourne se conoce en el sistema como sh. Aunque Unix ha pasado por muchos, muchos cambios, el shell Bourne sigue siendo popular y esencialmente sin cambios. Varias utilidades y funciones de administración de Unix dependen de él.
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 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 csh, tcsh).
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 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 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 Bourne pueden utilizarlo inmediatamente, y todas las utilidades del sistema que utilizan el shell Bourne pueden utilizar el shell Korn en su lugar. De hecho, algunos sistemas tienen el shell Korn instalado como si fuera el shell Bourne.
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 ksh93. Esta versión se distribuye con muchos sistemas Unix comerciales como parte del Entorno Común de Escritorio (CDE), normalmente como el <<shell Korn de escritorio>>, \emph{/usr/dt/bin/dtksh}.
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 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}.
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 Bourne sigue siendo conocido como el shell <<estándar>>, el shell Korn también es popular. Además de su compatibilidad con el shell 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.
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 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 Bourne no permite hacer esto en absoluto.
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 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.
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 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.
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 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 Korn de 1993. Utilice la siguiente secuencia de instrucciones para determinar qué shell tiene actualmente y si el shell Korn de 1993 existe en su sistema, y para hacer que el shell Korn de 1993 sea su shell de inicio de sesión.
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, csh, o 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 ksh, vaya al paso 3. De lo contrario, continúe con el paso 2.}
\item{Vea si existe alguna versión de ksh en su sistema en un directorio estándar. Escriba ksh. Si eso funciona (imprime un prompt \$), tiene una versión del shell Korn; continúe con el paso 3. De lo contrario, continúe con el paso 5.}
\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 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 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 ksh93. Puede utilizar esta versión; casi todo lo que se dice en este libro funcionará. Vaya al paso 7.}
\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 Korn. \\
\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.
@ -93,7 +93,7 @@ Si nada de lo anterior funciona, puede recurrir a editar el archivo \emph{/etc/p
\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 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}.}
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 Capítulo 3, el prompt puede ser cambiado.
@ -107,7 +107,7 @@ Una opción es un tipo especial de argumento que da al comando información espe
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 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:
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 -?}*)
@ -138,19 +138,19 @@ DESCRIPTION
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 \emph{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, cd --man 2>\&1 | more ejecuta la ayuda en línea a través del programa paginador more.},
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 :. Para \emph{test}, tienes que escribir \texttt{test - -man - -} para obtener la ayuda en línea.
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 ksh.
\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 Korn.
\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}
@ -163,7 +163,7 @@ Repasemos los conceptos más importantes sobre los directorios. El hecho de que
\label{fig2}
\end{figure}
La parte superior del árbol es un directorio llamado <<raíz>> o <<root>> que no tiene nombre en el sistema\footnote{La mayoría de los tutoriales introductorios de Unix dicen que root tiene el nombre /. Nos quedamos con esta explicación alternativa porque es más consistente lógicamente.}.
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}.
@ -171,14 +171,14 @@ Por ejemplo, supongamos que hay un archivo llamado \emph{memo} en el directorio
\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 root. En la actualidad, es habitual utilizar \emph{/home} como directorio principal para los directorios personales.
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 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.
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}.
@ -207,7 +207,7 @@ La Tabla \ref{tab1} muestra algunos ejemplos de comandos \emph{cd}. Cada comando
\end{tabular}
\end{table}
Los cuatro primeros son sencillos. Los dos siguientes utilizan un directorio especial llamado .. (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.
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.
@ -215,16 +215,16 @@ Los dos últimos ejemplos de la tabla utilizan una nueva forma del comando \emph
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 cd del shell 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}.
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 Bourne normal, sh.\footnote{Si tienes un sistema donde el shell 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 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:
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 Bourne}*)
$ (*\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
@ -259,7 +259,7 @@ $ pwd
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 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 Korn:
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
@ -280,7 +280,7 @@ cd .. ; pwd
/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 Korn. La mayoría de las veces, sin embargo, el posicionamiento lógico es exactamente lo que quieres.
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.
@ -293,7 +293,7 @@ Si le das a \emph{ls} argumentos de nombre de archivo, listará esos archivos, l
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 Korn para el \hyperref[sec:Chapter4]{Capítulo 4}. La Tabla \ref{tab2} lista los comodines básicos.
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
@ -369,7 +369,7 @@ Sin embargo, es importante tener en cuenta que los comandos que ejecutas sólo v
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 ls como argumentos.
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.
@ -430,13 +430,13 @@ $
\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 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.
\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 cp se usa normalmente para copiar archivos; si por alguna razón no existiera o estuviera roto, podrías usar cat de esta manera:
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
@ -446,7 +446,7 @@ 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 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).
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:
@ -454,14 +454,14 @@ Por último, es tentador utilizar el mismo fichero tanto para la entrada como pa
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 sort lo procese cuando se ejecute.
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 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.
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 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}.
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:
@ -477,7 +477,7 @@ cut -d: -f1 < /etc/passwd | sort
\newpage
El comando 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:
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
@ -528,7 +528,7 @@ Escriba \texttt{gunzip gcc-3.0.1.tar.gz \&}, y el sistema inicia un trabajo en s
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, jobs imprime una línea similar a la anterior pero con una indicación del estado del trabajo:
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
@ -561,7 +561,7 @@ Si escribe \texttt{diff warandpeace.html.old warandpeace.html \&}, el sistema le
diff warandpeace.html.antiguo warandpeace.html > wpdiff &
\end{lstlisting}
las diferencias se guardarán en el archivo \emph{wpdiff} ipara que pueda examinarlas más tarde.
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.
@ -779,4 +779,4 @@ Ya hemos visto un ejemplo de CTRL-D. Cuando estás ejecutando un comando que ace
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 Korn, que están entre sus características más interesantes.
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.

View File

@ -107,7 +107,7 @@ Cuando \emph{ulimit} imprime los límites actuales, imprime los límites blandos
\subsection{Tipos de personalización global}
El enfoque más adecuado para la personalización global disponible sería un archivo de entorno a nivel del sistema que sea independiente del archivo de entorno de cada usuario, al igual que \texttt{/etc/profile} es independiente del \emph{.profile} de cada usuario.
Desafortunadamente, el shell de Korn no tiene esta característica. Si asigna un nombre de archivo a la variable de entorno ENV, podría anularse en el \emph{.profile} de un usuario. Esto le permite proporcionar un archivo de entorno predeterminado para los usuarios que no tienen el suyo propio, pero no le permite tener un archivo de entorno a nivel del sistema que se ejecute además de los de los usuarios. Además, el archivo de entorno solo se ejecuta para shells interactivas, no para todas las shells.
Desafortunadamente, el shell de Korn no tiene esta característica. Si asigna un nombre de archivo a la variable de entorno \texttt{ENV}, podría anularse en el \emph{.profile} de un usuario. Esto le permite proporcionar un archivo de entorno predeterminado para los usuarios que no tienen el suyo propio, pero no le permite tener un archivo de entorno a nivel del sistema que se ejecute además de los de los usuarios. Además, el archivo de entorno solo se ejecuta para shells interactivas, no para todas las shells.
Sin embargo, el shell le proporciona algunas formas de configurar personalizaciones que están disponibles para todos los usuarios en todo momento. Las variables de entorno son las más obvias; su archivo \texttt{/etc/profile} seguramente contendrá definiciones para varias de ellas, incluyendo \texttt{PATH} y \texttt{TERM}.
@ -298,7 +298,7 @@ root) Cosas malas aquí # ¡Peligro, Will Robinson, peligro!
esac
\end{lstlisting}
En sí mismo, este script no puede causar daño cuando jprog está trabajando como \emph{él mismo}. El problema surge cuando \texttt{jprog} usa el comando \emph{su(1)}. Este comando permite a un usuario regular <<cambiar de usuario>> a un usuario diferente. Por defecto, permite a un usuario regular convertirse en \texttt{root} (siempre y cuando ese usuario conozca la contraseña, por supuesto). El problema es que normalmente, \emph{su} usa cualquier \texttt{PATH} que hereda.\footnote{Adquiere el hábito de usar \texttt{su - user} para cambiar al usuario como si el usuario estuviera haciendo un inicio de sesión real. Esto evita la importación del \texttt{PATH} existente.}
En sí mismo, este script no puede causar daño cuando \emph{jprog} está trabajando como \emph{él mismo}. El problema surge cuando \emph{jprog} usa el comando \emph{su(1)}. Este comando permite a un usuario regular <<cambiar de usuario>> a un usuario diferente. Por defecto, permite a un usuario regular convertirse en \texttt{root} (siempre y cuando ese usuario conozca la contraseña, por supuesto). El problema es que normalmente, \emph{su} usa cualquier \texttt{PATH} que hereda.\footnote{Adquiere el hábito de usar \texttt{su - user} para cambiar al usuario como si el usuario estuviera haciendo un inicio de sesión real. Esto evita la importación del \texttt{PATH} existente.}
En este caso, \texttt{\$PATH} incluye \texttt{\~{}jprog/bin}. Ahora, cuando \texttt{jprog}, trabajando como \texttt{root}, ejecuta \emph{grep}, en realidad ejecuta la versión del \emph{caballo de Troya} en su \emph{bin}. Esta versión ejecuta el \emph{grep} real, por lo que \texttt{jprog} obtiene los resultados que espera. Pero también ejecuta silenciosamente la parte de cosas malas aquí, como \texttt{root}. Esto significa que Unix permitirá que el script haga lo que quiera. \emph{Cualquier cosa}. Y para empeorar las cosas, al eliminar el caballo de Troya cuando ha terminado, ya no hay evidencia.
Los directorios \emph{bin} escribibles abren una puerta para los \emph{caballos de Troya}, al igual que tener un punto en el \texttt{PATH}. Tener scripts de shell escribibles en cualquier directorio bin es otra puerta. Así como cierras y aseguras las puertas de tu casa por la noche, ¡asegúrate de cerrar cualquier puerta en tu sistema!
@ -312,9 +312,9 @@ La facilidad \emph{setuid} es una característica agradable para juegos y archiv
Existe una facilidad similar a nivel de grupo, conocida (no sorprendentemente) como \emph{setgid} (set group ID). Usa \texttt{chmod 2755 nombrearchivo} para activar los permisos \emph{setgid}. Cuando haces un \texttt{ls -l} en un archivo \emph{setuid} o \emph{setgid}, la \emph{x} en el modo de permisos se reemplaza con una \emph{s}; por ejemplo, \texttt{-rws--s--x} para un archivo que es legible y escribible por el propietario, ejecutable por todos y tiene ambos bits \emph{setuid} y \emph{setgid} activados (modo octal 6711).
La sabiduría moderna de la administración del sistema dice que crear scripts de shell setuid y setgid es una muy, muy mala idea. Esto ha sido especialmente cierto bajo la C shell, porque su archivo de entorno \emph{.cshrc} introduce numerosas oportunidades para intrusiones. En particular, hay varias formas de engañar a un script de shell setuid para que se convierta en una shell \emph{interactiva} con un ID de usuario efectivo de \texttt{root}. Esto es lo mejor que un cracker podría esperar: la capacidad de ejecutar cualquier comando como \texttt{root}.
La sabiduría moderna de la administración del sistema dice que crear scripts de shell \emph{setuid} y \emph{setgid} es una muy, muy mala idea. Esto ha sido especialmente cierto bajo la C shell, porque su archivo de entorno \emph{.cshrc} introduce numerosas oportunidades para intrusiones. En particular, hay varias formas de engañar a un script de shell \emph{setuid} para que se convierta en una shell \emph{interactiva} con un ID de usuario efectivo de \texttt{root}. Esto es lo mejor que un cracker podría esperar: la capacidad de ejecutar cualquier comando como \texttt{root}.
\textbf{NOTA:} Existe una diferencia importante entre un script de shell \emph{setuid} y una shell \emph{setuid}. Esta última es una copia del ejecutable del shell, que se ha hecho pertenecer a \texttt{root} y se le ha aplicado el bit setuid. En la sección anterior sobre caballos de Troya, supongamos que la parte de \emph{cosas malas} aquí era este código:
\textbf{NOTA:} Existe una diferencia importante entre un script de shell \emph{setuid} y una shell \emph{setuid}. Esta última es una copia del ejecutable del shell, que se ha hecho pertenecer a \texttt{root} y se le ha aplicado el bit \emph{setuid}. En la sección anterior sobre caballos de Troya, supongamos que la parte de \emph{cosas malas} aquí era este código:
\begin{lstlisting}[language=bash]
cp /bin/ksh ~badguy/bin/myls
@ -324,20 +324,20 @@ chmod 4755 ~badguy/bin/myls
Recuerda, este código se ejecuta como \texttt{root}, por lo que funcionará. Cuando \texttt{badguy} ejecuta \emph{myls}, es un archivo ejecutable en código de máquina, y se honra el bit setuid. Hola shell que se ejecuta como \texttt{root}. ¡Adiós seguridad!
El \emph{modo privilegiado} fue diseñado para proteger contra scripts de shell setuid. Esta es una opción \emph{set -o} (\texttt{set -o privileged} o \texttt{set -p}), pero el shell la activa automáticamente cada vez que ejecuta un script cuyo bit \emph{setuid} está activado, es decir, cuando el ID de usuario efectivo es diferente del ID de usuario real.
El \emph{modo privilegiado} fue diseñado para proteger contra scripts de shell \emph{setuid}. Esta es una opción \emph{set -o} (\texttt{set -o privileged} o \texttt{set -p}), pero el shell la activa automáticamente cada vez que ejecuta un script cuyo bit \emph{setuid} está activado, es decir, cuando el ID de usuario efectivo es diferente del ID de usuario real.
En el \emph{modo privilegiado}, cuando se invoca un script de shell Korn \emph{setuid}, el shell ejecuta el archivo \texttt{/etc/suid\_profile}. Este archivo debe escribirse de manera que restrinja los scripts de shell setuid de manera similar a como lo hace la shell restringida. Como mínimo, debería hacer que \texttt{PATH} sea de solo lectura (\texttt{typeset -r PATH} o \texttt{readonly PATH}) y configurarlo en uno o más directorios <<seguros>>. Una vez más, esto evita que se invoquen señuelos.
En el \emph{modo privilegiado}, cuando se invoca un script de shell Korn \emph{setuid}, el shell ejecuta el archivo \texttt{/etc/suid\_profile}. Este archivo debe escribirse de manera que restrinja los scripts de shell \emph{setuid} de manera similar a como lo hace la shell restringida. Como mínimo, debería hacer que \texttt{PATH} sea de solo lectura (\texttt{typeset -r PATH} o \texttt{readonly PATH}) y configurarlo en uno o más directorios <<seguros>>. Una vez más, esto evita que se invoquen señuelos.
Dado que el modo privilegiado es una opción, es posible desactivarlo con el comando \texttt{set +o privileged} (o \texttt{set +p}). Pero esto no ayuda al posible cracker del sistema: el shell cambia automáticamente su ID de usuario efectivo para que sea igual al ID de usuario real, es decir, si desactivas el modo privilegiado, también desactivas \emph{setuid}.
Además del modo privilegiado, \emph{ksh} proporciona un programa <<agente>> especial, \texttt{/etc/suid\_exec}, que ejecuta scripts de shell setuid (o scripts de shell que son ejecutables pero no legibles).
Además del modo privilegiado, \emph{ksh} proporciona un programa <<agente>> especial, \texttt{/etc/suid\_exec}, que ejecuta scripts de shell \emph{setuid} (o scripts de shell que son ejecutables pero no legibles).
Para que esto funcione, el script no debe comenzar con \texttt{\#! /bin/ksh}. Cuando se invoca el programa, \emph{ksh} intenta ejecutar el programa como un ejecutable binario regular. Cuando el sistema operativo no puede ejecutar el script (porque no es binario y porque no tiene el nombre de un intérprete especificado con \texttt{\#!}), \emph{ksh} se da cuenta de que es un script e invoca \texttt{/etc/suid\_exec} con el nombre del script y sus argumentos. También se encarga de pasar un <<token>> de autenticación a \texttt{/etc/suid\_exec} que indica los ID de usuario y grupo reales y efectivos del script. \texttt{/etc/suid\_exec} verifica que es seguro ejecutar el script y luego se encarga de invocar \emph{ksh} con los ID de usuario y grupo reales y efectivos adecuados en el script.
Aunque la combinación de modo privilegiado y \texttt{/etc/suid\_exec} te permite evitar muchos de los ataques a scripts setuid, escribir scripts que se puedan ejecutar setuid de manera segura es un arte difícil, que requiere una buena cantidad de conocimiento y experiencia. Debería hacerse con mucho cuidado.
Aunque la combinación de modo privilegiado y \texttt{/etc/suid\_exec} te permite evitar muchos de los ataques a scripts \emph{setuid}, escribir scripts que se puedan ejecutar \emph{setuid} de manera segura es un arte difícil, que requiere una buena cantidad de conocimiento y experiencia. Debería hacerse con mucho cuidado.
De hecho, los peligros de scripts de shell setuid y setgid (al menos para shells además de \emph{ksh}) son tan grandes que los sistemas Unix modernos, tanto los sistemas Unix comerciales como los clones de software libre (derivados de 4.4-BSD y GNU/Linux), desactivan los bits setuid y setgid en scripts de shell. Incluso si aplicas los bits al archivo, el sistema operativo no los respeta. \footnote{MacOS X parece ser una notable excepción. ¡Ten mucho cuidado si ejecutas uno o más de esos sistemas!}
De hecho, los peligros de scripts de shell \emph{setuid} y \emph{setgid} (al menos para shells además de \emph{ksh}) son tan grandes que los sistemas Unix modernos, tanto los sistemas Unix comerciales como los clones de software libre (derivados de 4.4-BSD y GNU/Linux), desactivan los bits \emph{setuid} y \emph{setgid} en scripts de shell. Incluso si aplicas los bits al archivo, el sistema operativo no los respeta. \footnote{MacOS X parece ser una notable excepción. ¡Ten mucho cuidado si ejecutas uno o más de esos sistemas!}
Aunque los scripts de shell setuid no funcionan en sistemas modernos, hay ocasiones en las que el modo privilegiado sigue siendo útil. En particular, existe un programa de terceros ampliamente utilizado llamado \emph{sudo}, que, citando la página web, <<permite a un administrador del sistema dar a ciertos usuarios (o grupos de usuarios) la capacidad de ejecutar algunos (o todos) los comandos como \texttt{root} u otro usuario mientras registra los comandos y argumentos>>. La página de inicio de \emph{sudo} es \url{http://www.courtesan.com/sudo/}. Un administrador del sistema podría ejecutar fácilmente \texttt{sudo /bin/ksh -p} para obtener un entorno conocido para realizar tareas administrativas.
Aunque los scripts de shell \emph{setuid} no funcionan en sistemas modernos, hay ocasiones en las que el modo privilegiado sigue siendo útil. En particular, existe un programa de terceros ampliamente utilizado llamado \emph{sudo}, que, citando la página web, <<permite a un administrador del sistema dar a ciertos usuarios (o grupos de usuarios) la capacidad de ejecutar algunos (o todos) los comandos como \texttt{root} u otro usuario mientras registra los comandos y argumentos>>. La página de inicio de \emph{sudo} es \url{http://www.courtesan.com/sudo/}. Un administrador del sistema podría ejecutar fácilmente \texttt{sudo /bin/ksh -p} para obtener un entorno conocido para realizar tareas administrativas.
Finalmente, si deseas aprender más sobre la seguridad de Unix, recomendamos \emph{Practical UNIX \& Internet Security} de Simson Garfinkel y Gene Spafford. Está publicado por O'Reilly \& Associates.

View File

@ -6,20 +6,20 @@ En particular, no hay forma de recuperar una línea de órdenes anterior para po
eval cat \$srcname \| ccom \| optimize \| as \> \$objname
\end{lstlisting}
Si eres un usuario experimentado del shell Bourne, sin duda conoces la frustración de tener que volver a escribir líneas como ésta. Puedes usar la tecla de retroceso para editar, pero una vez que pulsas ENTER, ¡se ha ido para siempre!
Si eres un usuario experimentado del shell de Bourne, sin duda conoces la frustración de tener que volver a escribir líneas como ésta. Puedes usar la tecla de retroceso para editar, pero una vez que pulsas ENTER, ¡se ha ido para siempre!
El intérprete de comandos C ofrece una pequeña mejora a través de su mecanismo de historial, que proporciona algunas formas muy incómodas de editar comandos anteriores. Pero hay más de una persona que se ha preguntado: <<¿Por qué no puedo editar mis líneas de comandos Unix de la misma forma que puedo editar texto con un editor?>>
Esto es exactamente lo que el shell Korn te permite hacer. Tiene modos de edición que te permiten editar líneas de comandos con comandos de edición similares a los de los dos editores más populares de Unix, vi y Emacs.\footnote{Por alguna razón desconocida, la documentación sobre el modo emacs ha sido eliminada de las páginas de manual de ksh(1) en algunos sistemas Unix. Esto no significa, sin embargo, que el modo no exista o no funcione correctamente.} También proporciona un análogo mucho más extendido del mecanismo de historia del shell de C llamado \emph{hist} (por <<historia>>) que, entre otras cosas, te permite usar tu editor favorito directamente para editar tus líneas de comandos.
Esto es exactamente lo que el shell de Korn te permite hacer. Tiene modos de edición que te permiten editar líneas de comandos con comandos de edición similares a los de los dos editores más populares de Unix, \emph{vi} y Emacs.\footnote{Por alguna razón desconocida, la documentación sobre el modo \emph{emacs} ha sido eliminada de las páginas de manual de \emph{ksh(1)} en algunos sistemas Unix. Esto no significa, sin embargo, que el modo no exista o no funcione correctamente.} También proporciona un análogo mucho más extendido del mecanismo de historia del shell de C llamado \emph{hist} (por <<historia>>) que, entre otras cosas, te permite usar tu editor favorito directamente para editar tus líneas de comandos.
En este capítulo, discutiremos las características comunes a todas las facilidades comando-historial del intérprete de órdenes Korn; después trataremos cada una de esas facilidades en detalle. Si usas vi o Emacs, puede que quieras leer sólo la sección sobre el modo de emulación para el que uses.\footnote{Sacarás el máximo provecho de estas secciones si ya estás familiarizado con el/los editor/es en cuestión. Buenas fuentes para información más completa sobre los editores son Learning the vi Editor por Linda Lamb y Arnold Robbins y Learning GNU Emacs por Debra Cameron, Bill Rosenblatt, y Eric Raymond. Ambos publicados por O'Reilly \& Associates.} Si no usas ni \emph{vi} ni Emacs pero estás interesado en aprender uno de los modos de edición de todas formas, sugerimos el modo emacs, porque es más una extensión natural de la capacidad mínima de edición que obtienes con el shell desnudo.
En este capítulo, discutiremos las características comunes a todas las facilidades comando-historial del intérprete de órdenes Korn; después trataremos cada una de esas facilidades en detalle. Si usas vi o Emacs, puede que quieras leer sólo la sección sobre el modo de emulación para el que uses.\footnote{Sacarás el máximo provecho de estas secciones si ya estás familiarizado con el/los editor/es en cuestión. Buenas fuentes para información más completa sobre los editores son Learning the vi Editor por Linda Lamb y Arnold Robbins y Learning GNU Emacs por Debra Cameron, Bill Rosenblatt, y Eric Raymond. Ambos publicados por O'Reilly \& Associates.} Si no usas ni \emph{vi} ni Emacs pero estás interesado en aprender uno de los modos de edición de todas formas, sugerimos el modo \emph{emacs}, porque es más una extensión natural de la capacidad mínima de edición que obtienes con el shell desnudo.
Deberíamos mencionar por adelantado que tanto el modo emacs como el vi introducen la posibilidad de conflictos con las teclas de control establecidas por la interfaz de terminal de Unix. Recuerde las teclas de control mostradas en el \hyperref[sec:Chapter1]{Capítulo 1} en la Tabla \ref{Tab:1-7} y el ejemplo de salida del comando \emph{stty}. Las teclas de control mostradas allí anulan sus funciones en los modos de edición.
Deberíamos mencionar por adelantado que tanto el modo \emph{emacs} como el \emph{vi} introducen la posibilidad de conflictos con las teclas de control establecidas por la interfaz de terminal de Unix. Recuerde las teclas de control mostradas en el \hyperref[sec:Chapter1]{Capítulo 1} en la Tabla \ref{Tab:1-7} y el ejemplo de salida del comando \emph{stty}. Las teclas de control mostradas allí anulan sus funciones en los modos de edición.
Durante el resto de este capítulo, le advertiremos cuando un comando de edición choque con la configuración por defecto de una tecla de control de la interfaz de terminal. Pero si usted (o su administrador de sistema) elige personalizar su interfaz de terminal, como mostramos en el \hyperref[sec:Chapter8]{Capítulo 8}, usted está por su cuenta en lo que concierne a los modos de edición.
\section{Activando la Edición de Línea de Comandos}
Hay dos formas de entrar en uno u otro modo de edición. Primero, puede establecer su modo de edición usando la variable de entorno \texttt{VISUAL}. El shell Korn comprueba si esta variable termina con \texttt{vi} o {emacs}.\footnote{GNU Emacs se instala a veces como gmacs o gnumacs.} Una forma excelente de establecer \texttt{VISUAL} es poner una línea como la siguiente en su fichero \emph{.profile} o de entorno:
Hay dos formas de entrar en uno u otro modo de edición. Primero, puede establecer su modo de edición usando la variable de entorno \texttt{VISUAL}. El shell de Korn comprueba si esta variable termina con \texttt{vi} o {emacs}.\footnote{GNU Emacs se instala a veces como \emph{gmacs} o \emph{gnumacs}.} Una forma excelente de establecer \texttt{VISUAL} es poner una línea como la siguiente en su fichero \emph{.profile} o de entorno:
\begin{lstlisting}[language=bash]
@ -32,7 +32,7 @@ o
VISUAL=$(whence vi)
\end{lstlisting}
Como se verá en los Capítulos \hyperref[sec:Chapter3]{3} y \hyperref[sec:Chapter4]{4}, el comando incorporado \emph{whence} toma el nombre de otro comando como argumento y escribe la ruta completa del comando en la salida estándar; la forma \emph{\$(command)} devuelve la salida estándar generada por \emph{coamand} como un valor de cadena. Así, la línea anterior encuentra la ruta completa de tu editor favorito y la almacena en la variable de entorno \texttt{VISUAL}. La ventaja de este código es que es portable a otros sistemas, que pueden tener los ejecutables de los editores almacenados en directorios diferentes.
Como se verá en los Capítulos \hyperref[sec:Chapter3]{3} y \hyperref[sec:Chapter4]{4}, el comando incorporado \emph{whence} toma el nombre de otro comando como argumento y escribe la ruta completa del comando en la salida estándar; la forma \emph{\$(command)} devuelve la salida estándar generada por \emph{command} como un valor de cadena. Así, la línea anterior encuentra la ruta completa de tu editor favorito y la almacena en la variable de entorno \texttt{VISUAL}. La ventaja de este código es que es portable a otros sistemas, que pueden tener los ejecutables de los editores almacenados en directorios diferentes.
La segunda forma de seleccionar un modo de edición es establecer la opción explícitamente con el comando \emph{set -o}:
@ -52,10 +52,10 @@ Los usuarios de vi pueden desear añadir:
set -o viraw
\end{lstlisting}
junto con \texttt{set -o vi}. Esto permite completar TAB en versiones recientes de \emph{ksh93}. La sobrecarga adicional, particularmente en sistemas monousuario, es nominal y, en cualquier caso, no es peor que la del modo emacs. (A partir de \emph{ksh93n}, la opción \emph{viraw} se activa automáticamente cuando se utiliza el modo vi).
junto con \texttt{set -o vi}. Esto permite completar TAB en versiones recientes de \emph{ksh93}. La sobrecarga adicional, particularmente en sistemas monousuario, es nominal y, en cualquier caso, no es peor que la del modo \emph{emacs}. (A partir de \emph{ksh93n}, la opción \emph{viraw} se activa automáticamente cuando se utiliza el modo vi).
Encontrará que los modos de edición vi y emacs son buenos emulando los comandos básicos de estos editores, pero no las características avanzadas; su propósito principal es permitirle transferir <<hábitos de dedo>> de su editor favorito al shell. \emph{hist} es una facilidad poderosa; está pensada principalmente para suplantar al historial del shell C y como una <<escotilla de escape>> para usuarios de editores que no sean vi o Emacs. Por lo tanto, la sección sobre \emph{hist} se recomienda sobre todo a los usuarios del intérprete de comandos C y a aquellos que no utilizan ninguno de los dos editores estándar.
Encontrará que los modos de edición \emph{vi} y \emph{emacs} son buenos emulando los comandos básicos de estos editores, pero no las características avanzadas; su propósito principal es permitirle transferir <<hábitos de dedo>> de su editor favorito al shell. \emph{hist} es una facilidad poderosa; está pensada principalmente para suplantar al historial del shell C y como una <<escotilla de escape>> para usuarios de editores que no sean \emph{vi} o Emacs. Por lo tanto, la sección sobre \emph{hist} se recomienda sobre todo a los usuarios del intérprete de comandos C y a aquellos que no utilizan ninguno de los dos editores estándar.
Antes de entrar en detalles, vale la pena mencionar otros dos puntos que se aplican a ambos modos de edición:
@ -70,7 +70,7 @@ print this is a very long line that just runs on and >
\end{itemize}
\section{El Archivo Histórico}
Todas las facilidades del historial de comandos del shell Korn dependen de un fichero que almacena los comandos a medida que los tecleas. Este fichero es normalmente \emph{.sh\_history} en tu directorio home, pero puedes llamarlo como quieras configurando la variable de entorno \texttt{HISTFILE} (ver \hyperref[sec:Chapter3]{Capítulo 3}). Cuando ejecutas uno de los modos de edición del shell Korn, en realidad estás ejecutando un mini-editor en tu fichero histórico.
Todas las facilidades del historial de comandos del shell de Korn dependen de un fichero que almacena los comandos a medida que los tecleas. Este fichero es normalmente \emph{.sh\_history} en tu directorio home, pero puedes llamarlo como quieras configurando la variable de entorno \texttt{HISTFILE} (ver \hyperref[sec:Chapter3]{Capítulo 3}). Cuando ejecutas uno de los modos de edición del shell de Korn, en realidad estás ejecutando un mini-editor en tu fichero histórico.
Si ejecuta más de una sesión de inicio de sesión a la vez (por ejemplo, más de un \emph{xterm} en una estación de trabajo X Windows), puede encontrar ventajoso mantener un fichero de historial separado para cada sesión de inicio de sesión. Ponga la siguiente línea en su \emph{.profile}:
@ -80,12 +80,12 @@ HISTFILE=~/.hist.$(tty | sed 's;.*/;;')
Esto crea un archivo de historial cuyo nombre termina con el último componente del nombre del dispositivo de su terminal. Por ejemplo, el nombre del dispositivo de terminal de su ventana podría ser \emph{/dev/pts/42}. El comando \emph{sed} elimina todo hasta la última barra, dejando sólo el 42. El archivo histórico se convierte entonces en \emph{\~{}/.hist.com}. El archivo histórico se convierte entonces en \~{}/.hist.42. Puede eliminar el archivo de historial al cerrar la sesión, como se explica en el \hyperref[sec:Chapter4]{Capítulo 4}. O puede dejar los archivos, como se explica en el \hyperref[sec:Chapter5]{Capítulo 5}. O puede dejar los archivos, y su historial estará allí la próxima vez que inicie una ventana en el mismo dispositivo terminal. (Preservar el historial entre sesiones es el objetivo del archivo de historial, después de todo).
Una alternativa atractiva es utilizar un único fichero de historial para todas las ventanas. Cada instancia en ejecución del shell Korn es lo suficientemente inteligente como para compartir su archivo con otras instancias en ejecución; desde una segunda ventana, puede recuperar y editar los comandos ejecutados en la primera ventana.
Una alternativa atractiva es utilizar un único fichero de historial para todas las ventanas. Cada instancia en ejecución del shell de Korn es lo suficientemente inteligente como para compartir su archivo con otras instancias en ejecución; desde una segunda ventana, puede recuperar y editar los comandos ejecutados en la primera ventana.
Otra variable de entorno, \texttt{HISTSIZE}, se puede utilizar para determinar el número máximo de comandos accesibles desde el archivo de historial. El valor predeterminado es 128 (es decir, los 128 comandos más recientes), que debería ser más que suficiente.
\section{Modo de Edición Emacs}
Si eres usuario de Emacs, te resultará muy útil pensar en el modo de edición emacs como un Emacs simplificado con una única ventana de una línea. Todos los comandos básicos están disponibles para el movimiento del cursor, cortar y pegar, y buscar.
Si eres usuario de Emacs, te resultará muy útil pensar en el modo de edición \emph{emacs} como un Emacs simplificado con una única ventana de una línea. Todos los comandos básicos están disponibles para el movimiento del cursor, cortar y pegar, y buscar.
\subsection{Comando Básicos}
El modo Emacs utiliza teclas de control para las funciones de edición más básicas. Si no estás familiarizado con Emacs, puedes pensar en ellas como extensiones del rudimentario carácter <<borrar>> (normalmente retroceso o DEL) que Unix proporciona a través de su interfaz a los terminales de los usuarios. De hecho, el modo-emacs averigua cuál es tu carácter de borrado y lo usa como tecla de borrar-atrás. En aras de la consistencia, asumiremos que tu carácter de borrado es DEL a partir de ahora; si es CTRL-H o cualquier otro, necesitarás hacer una sustitución mental. Los comandos más básicos de las teclas de control se muestran en la Tabla \ref{tab2.1}.
@ -106,13 +106,13 @@ El modo Emacs utiliza teclas de control para las funciones de edición más bás
\textbf{ADVERTENCIA:} ¡Recuerda que teclear CTRL-D cuando tu línea de comandos está vacía puede cerrar tu sesión!
Los hábitos básicos del modo emacs son fáciles de aprender, pero requieren que asimiles un par de conceptos peculiares del editor Emacs.
Los hábitos básicos del modo \emph{emacs} son fáciles de aprender, pero requieren que asimiles un par de conceptos peculiares del editor Emacs.
El primero de ellos es el uso de CTRL-B y CTRL-F para avanzar y retroceder el cursor. Estas teclas tienen la ventaja de ser mnemotécnicas obvias, pero mucha gente prefiere usar las teclas de flecha que hay en casi todos los teclados hoy en día.
Desafortunadamente, el modo emacs no usa las teclas de dirección,\footnote{De hecho, como se describe en el Apéndice B, a partir de \emph{ksh93h}, si su terminal utiliza secuencias de escape estándar ANSI para las teclas de flecha, puede utilizarlas.} porque los códigos que transmiten al ordenador no están completamente estandarizados; el modo emacs fue diseñado para funcionar en la mayor variedad posible de terminales sin la pesada personalización que necesita el Emacs completo. Casi los únicos requisitos de hardware del modo emacs son que el carácter ESPACIO sobrescriba el carácter sobre el que se escribe, y que RETROCESO se mueva a la izquierda sin sobrescribir el carácter actual.
Desafortunadamente, el modo \emph{emacs} no usa las teclas de dirección,\footnote{De hecho, como se describe en el Apéndice B, a partir de \emph{ksh93h}, si su terminal utiliza secuencias de escape estándar ANSI para las teclas de flecha, puede utilizarlas.} porque los códigos que transmiten al ordenador no están completamente estandarizados; el modo \emph{emacs} fue diseñado para funcionar en la mayor variedad posible de terminales sin la pesada personalización que necesita el Emacs completo. Casi los únicos requisitos de hardware del modo \emph{emacs} son que el carácter ESPACIO sobrescriba el carácter sobre el que se escribe, y que RETROCESO se mueva a la izquierda sin sobrescribir el carácter actual.
En modo emacs, el punto (a veces también llamado punto) es un lugar imaginario justo a la izquierda del carácter sobre el que está el cursor. En las descripciones de los comandos de la Tabla 2-1, algunos dicen <<hacia delante>> mientras que otros dicen <<hacia atrás>>. Piensa en adelante como <<a la derecha del punto>> y atrás como <<a la izquierda del punto>>.
En modo \emph{emacs}, el punto (a veces también llamado punto) es un lugar imaginario justo a la izquierda del carácter sobre el que está el cursor. En las descripciones de los comandos de la Tabla 2-1, algunos dicen <<hacia delante>> mientras que otros dicen <<hacia atrás>>. Piensa en adelante como <<a la derecha del punto>> y atrás como <<a la izquierda del punto>>.
Por ejemplo, digamos que tecleas una línea y, en lugar de teclear ENTER, tecleas CTRL-B y lo mantienes pulsado para que se repita. El cursor se moverá hacia la izquierda hasta situarse sobre el primer carácter de la línea, de esta forma:
@ -137,7 +137,7 @@ En este punto, teclear CTRL-D no haría nada, pero pulsar DEL borraría la s fin
Si haces varios borrados seguidos, CTRL-Y te devuelve todo lo que has borrado. Su memoria se remonta a la última pulsación que no haya sido un borrado; los borrados no tienen por qué ser del mismo tipo. Por ejemplo, si escribes DEL SPACE DEL SPACE CTRL-D CTRL-K, al escribir CTRL-Y recuperas el resultado de las tres últimas operaciones, pero no el primer borrado.
\subsection{Comandos de palabras}
Los comandos básicos son realmente todo lo que necesitas para moverte por una línea de comandos, pero un conjunto de comandos más avanzados te permite hacerlo con menos pulsaciones. Estos comandos operan sobre \emph{palabras} en lugar de sobre caracteres sueltos; el modo emacs define una palabra como una secuencia de uno o más caracteres alfanuméricos o guiones bajos. (Para el resto de esta discusión, será útil pensar en el guión bajo como una letra, aunque realmente no lo sea).
Los comandos básicos son realmente todo lo que necesitas para moverte por una línea de comandos, pero un conjunto de comandos más avanzados te permite hacerlo con menos pulsaciones. Estos comandos operan sobre \emph{palabras} en lugar de sobre caracteres sueltos; el modo \emph{emacs} define una palabra como una secuencia de uno o más caracteres alfanuméricos o guiones bajos. (Para el resto de esta discusión, será útil pensar en el guión bajo como una letra, aunque realmente no lo sea).
Los comandos de palabra se muestran en la Tabla \ref{tab2.2}. Mientras que los comandos básicos son todos de un solo carácter, los comandos de palabra consisten en dos pulsaciones de tecla, ESC seguida de una letra. Notará que el comando ESC X, donde X es cualquier letra, a menudo hace para una palabra lo que CTRL-X hace para un solo carácter. La multiplicidad de opciones para borrar-palabra-atrás surge del hecho de que tu carácter de borrado puede ser CTRL-H o DEL.
@ -187,7 +187,7 @@ $ grep -l Dave< ~pete/wk/names
El comando CTRL-Y <<undelete>> recuperará una palabra entera, en lugar de un carácter, si una palabra fue lo último que se borró.
\subsection{Comandos de línea}
Todavía hay formas más eficientes de moverse por una línea de órdenes en modo emacs. Unos pocos comandos se ocupan de toda la línea; se muestran en la Tabla \ref{tab2.3}.
Todavía hay formas más eficientes de moverse por una línea de órdenes en modo \emph{emacs}. Unos pocos comandos se ocupan de toda la línea; se muestran en la Tabla \ref{tab2.3}.
\begin{table}[h]
\center
@ -225,7 +225,7 @@ Ahora sabemos cómo movernos eficientemente por la línea de comandos y hacer ca
\end{tabular}
\end{table}
CTRL-P es, con diferencia, la que usarás más a menudo: es la tecla de <<he cometido un error; déjame volver atrás y arreglarlo>>. Puedes utilizarla tantas veces como desees para desplazarte hacia atrás por el historial. Si quieres volver al último comando que introdujiste, puedes mantener pulsado CTRL-N hasta que el shell Korn emita un pitido, o simplemente teclear ESC >. Por ejemplo, pulsa ENTER para ejecutar el comando anterior, pero aparece un mensaje de error que le indica que la letra de la opción era incorrecta. Quieres cambiarla sin volver a escribir todo. Primero, teclearías CTRL-P para recuperar el comando incorrecto. Lo recuperas con punto al final:
CTRL-P es, con diferencia, la que usarás más a menudo: es la tecla de <<he cometido un error; déjame volver atrás y arreglarlo>>. Puedes utilizarla tantas veces como desees para desplazarte hacia atrás por el historial. Si quieres volver al último comando que introdujiste, puedes mantener pulsado CTRL-N hasta que el shell de Korn emita un pitido, o simplemente teclear ESC >. Por ejemplo, pulsa ENTER para ejecutar el comando anterior, pero aparece un mensaje de error que le indica que la letra de la opción era incorrecta. Quieres cambiarla sin volver a escribir todo. Primero, teclearías CTRL-P para recuperar el comando incorrecto. Lo recuperas con punto al final:
\begin{lstlisting}[language=bash]
$ grep -l Dave < ~pete/wk/names
@ -251,16 +251,16 @@ $ fgrep -l Bob < ~pete/wk/names
Escribir CTRL-R sin un argumento (es decir, sólo CTRL-R seguido de ENTER) hace que el shell repita su última búsqueda hacia atrás. Si intentas el comando \emph{fgrep} pulsando ENTER de nuevo, ocurren dos cosas. Primero, por supuesto, el comando se ejecuta. Segundo, la línea de comando ejecutada se introduce en el archivo de historial al final, y su <<línea actual>> también estará al final. Ya no estarás en medio del fichero histórico.
CTRL-P y CTRL-R son claramente los comandos más importantes del modo emacs que tienen que ver con el fichero histórico, y puede que utilices CTRL-N ocasionalmente. Los otros son menos útiles, y sospechamos que se incluyeron principalmente por compatibilidad con el editor Emacs completo.
CTRL-P y CTRL-R son claramente los comandos más importantes del modo \emph{emacs} que tienen que ver con el fichero histórico, y puede que utilices CTRL-N ocasionalmente. Los otros son menos útiles, y sospechamos que se incluyeron principalmente por compatibilidad con el editor Emacs completo.
Los usuarios de Emacs también deberían tener en cuenta que las capacidades de búsqueda <<de lujo>> del editor completo, como la búsqueda incremental y de expresiones regulares, no están disponibles en el modo emacs de el Shell de Korn -- con una pequeña excepción: si usas CTRL-R y precedes tu cadena de búsqueda con un \^{} (carácter de intercalación), sólo coincidirá con comandos que tengan la cadena de búsqueda al principio de la línea.
Los usuarios de Emacs también deberían tener en cuenta que las capacidades de búsqueda <<de lujo>> del editor completo, como la búsqueda incremental y de expresiones regulares, no están disponibles en el modo \emph{emacs} de el Shell de Korn -- con una pequeña excepción: si usas CTRL-R y precedes tu cadena de búsqueda con un \^{} (carácter de intercalación), sólo coincidirá con comandos que tengan la cadena de búsqueda al principio de la línea.
\subsection{Nombre de archivo y finalización y expansión de variable}
Una de las funciones más potentes (y normalmente infrautilizadas) del modo emacs es su función de \emph{completado de names} de archivo, inspirada en funciones similares del editor Emacs completo, el intérprete de comandos C y (originalmente) el antiguo sistema operativo DEC TOPS-20.
Una de las funciones más potentes (y normalmente infrautilizadas) del modo \emph{emacs} es su función de \emph{completado de nombres} de archivo, inspirada en funciones similares del editor Emacs completo, el intérprete de comandos C y (originalmente) el antiguo sistema operativo DEC TOPS-20.
La premisa detrás del completado de names de archivo es que cuando necesites escribir un nombre de archivo, no deberías tener que escribir más de lo necesario para identificar el archivo sin ambigüedades. Se trata de una función excelente; existe una análoga en el modo vi. Te recomendamos que la domines, ya que te ahorrará bastante tecleo.
La premisa detrás del completado de nombres de archivo es que cuando necesites escribir un nombre de archivo, no deberías tener que escribir más de lo necesario para identificar el archivo sin ambigüedades. Se trata de una función excelente; existe una análoga en el modo vi. Te recomendamos que la domines, ya que te ahorrará bastante tecleo.
Hay tres comandos en modo emacs relacionados con la compleción de names de archivo. El más importante es TAB. (A los usuarios de Emacs les resultará familiar; es lo mismo que completar el minibuffer con la tecla TAB). Cuando escribe una palabra de texto seguida de TAB, el shell Korn intenta completar el nombre de un fichero en el directorio actual. Entonces puede ocurrir una de estas cuatro cosas:
Hay tres comandos en modo \emph{emacs} relacionados con la autocompletado de nombres de archivo. El más importante es TAB. (A los usuarios de Emacs les resultará familiar; es lo mismo que completar el minibuffer con la tecla TAB). Cuando escribe una palabra de texto seguida de TAB, el shell de Korn intenta completar el nombre de un fichero en el directorio actual. Entonces puede ocurrir una de estas cuatro cosas:
\begin{enumerate}
\item{Si no hay ningún fichero cuyo nombre empiece por la palabra, el shell emite un pitido y no ocurre nada más.}
@ -269,7 +269,7 @@ Hay tres comandos en modo emacs relacionados con la compleción de names de arch
\item{Si hay más de una forma de completar el nombre de archivo, el shell lo completa con el prefijo común más largo entre las opciones disponibles.}
\end{enumerate}
Por ejemplo, suponga que tiene un directorio con los archivos \emph{program.c} y \emph{problem.c}. Desea compilar el primero de ellos escribiendo \texttt{cc programa.c}. Escriba \texttt{cc pr} seguido de TAB. Se trata de un prefijo ambiguo, ya que el prefijo <<pro>> es común a ambos names de archivo, por lo que el intérprete de comandos sólo completa \texttt{cc pro}. Necesitas escribir más letras para desambiguar, así que escribes g y pulsas TAB de nuevo. Entonces el intérprete de comandos completa a <<\texttt{cc program.c}>>, dejando el espacio extra para que usted escriba otros names de archivo u opciones.
Por ejemplo, suponga que tiene un directorio con los archivos \emph{program.c} y \emph{problem.c}. Desea compilar el primero de ellos escribiendo \texttt{cc programa.c}. Escriba \texttt{cc pr} seguido de TAB. Se trata de un prefijo ambiguo, ya que el prefijo <<pro>> es común a ambos nombres de archivo, por lo que el intérprete de comandos sólo completa \texttt{cc pro}. Necesitas escribir más letras para desambiguar, así que escribes g y pulsas TAB de nuevo. Entonces el intérprete de comandos completa a <<\texttt{cc program.c}>>, dejando el espacio extra para que usted escriba otros nombres de archivo u opciones.
Un comando relacionado es ESC *, que expande el prefijo a todas las opciones posibles. ESC * actúa como el carácter comodín estándar * del shell, excepto que expande las opciones para que las veas y no ejecuta el comando. En el ejemplo anterior, si escribes ESC * en lugar de TAB, el shell se expandirá a <<\texttt{cc problem.c program.c}>>, Si escribe ESC = en lugar de ESC *, verá una lista numerada de expansiones impresa en el error estándar.
@ -279,11 +279,11 @@ Cuando se usan TAB, ESC * y ESC = en la primera palabra de la línea de comandos
Por compatibilidad con \emph{ksh88} y versiones de \emph{ksh93} anteriores a \emph{ksh93h}, puede escribir ESC ESC para completar el nombre de archivo y el comando.
A partir de \emph{ksh93l}, los modos de edición entienden las reglas de entrecomillado de \emph{ksh}; las expansiones se ignoran dentro de las comillas. Sin embargo, si ha escrito una comilla inicial pero aún no ha cerrado las comillas, los comandos de finalización funcionan. Además, las tres expansiones funcionan también con names de variables. (Las variables se tratan en el \hyperref[sec:Chapter4]{Capítulo 4}.) Cuando \emph{ksh} ve un \$ o ''\$ y parte de un nombre de variable, puede usar cualquiera de las tres expansiones para ver qué names de variables coinciden con lo que ha escrito.
A partir de \emph{ksh93l}, los modos de edición entienden las reglas de entrecomillado de \emph{ksh}; las expansiones se ignoran dentro de las comillas. Sin embargo, si ha escrito una comilla inicial pero aún no ha cerrado las comillas, los comandos de finalización funcionan. Además, las tres expansiones funcionan también con nombres de variables. (Las variables se tratan en el \hyperref[sec:Chapter4]{Capítulo 4}.) Cuando \emph{ksh} ve un \$ o ''\$ y parte de un nombre de variable, puede usar cualquiera de las tres expansiones para ver qué nombres de variables coinciden con lo que ha escrito.
\newpage
\subsection{Comandos misceláneos}
Varios comandos misceláneos completan el modo de edición de emacs; se muestran en la Tabla \ref{tab2.5}.
Varios comandos misceláneos completan el modo de edición de \emph{emacs}; se muestran en la Tabla \ref{tab2.5}.
\begin{table}[h]
\center
@ -295,11 +295,11 @@ Varios comandos misceláneos completan el modo de edición de emacs; se muestran
CTRL-L & Vuelve a mostrar la línea. \\\hline
CTRL-M & Igual que ENTER. \\\hline
CTRL-O & Igual que ENTER, luego muestra la línea siguiente en el archivo histórico. \\\hline
CTRL-T & Transpone los caracteres a ambos lados del punto. Es como GNU Emacs.\tablefootnote{Esta es una diferencia con \emph{ksh88}, que transpone dos caracteres a la derecha del punto y mueve el punto uno hacia adelante. CTRL-T se comporta de forma ligeramente diferente si pones \texttt{set -o gmacs} (en lugar de \texttt{emacs}) en tu \emph{.profile}. En este caso, transpone los dos caracteres a la izquierda del punto, dejando el punto sin mover. Esta es la única diferencia entre los modos emacs y gmacs; este último se ajusta a la versión de James Gosling del editor Emacs (también conocido como Unipress Emacs, que ya no está disponible).} \\\hline
CTRL-T & Transpone los caracteres a ambos lados del punto. Es como GNU Emacs.\tablefootnote{Esta es una diferencia con \emph{ksh88}, que transpone dos caracteres a la derecha del punto y mueve el punto uno hacia adelante. CTRL-T se comporta de forma ligeramente diferente si pones \texttt{set -o gmacs} (en lugar de \texttt{emacs}) en tu \emph{.profile}. En este caso, transpone los dos caracteres a la izquierda del punto, dejando el punto sin mover. Esta es la única diferencia entre los modos \emph{emacs} y \emph{gmacs}; este último se ajusta a la versión de James Gosling del editor Emacs (también conocido como Unipress Emacs, que ya no está disponible).} \\\hline
CTRL-U & Repite el siguiente comando cuatro veces. \\\hline
CTRL-V & Imprime la versión del shell Korn. \\\hline
CTRL-V & Imprime la versión del shell de Korn. \\\hline
CTRL-W & Borra (<<wipe>>) todos los caracteres entre punto y <<mark>>. <<Marcar>> se trata más adelante en esta sección. \\\hline
CTRL-X CTRL-E & Invoca un editor -- normalmente el programa emacs -- en el comando actual. \\\hline
CTRL-X CTRL-E & Invoca un editor -- normalmente el programa \emph{emacs} -- en el comando actual. \\\hline
CTRL-X CTRL-X & Intercambia punto y marca. \\\hline
CTRL-[ & Igual que ESC (la mayoría de los teclados). \\\hline
CTRL-] x & Busca x hacia adelante en la línea actual, donde x es cualquier carácter. \\\hline
@ -315,15 +315,15 @@ Varios comandos misceláneos completan el modo de edición de emacs; se muestran
\end{tabular}
\end{table}
Varios de estos comandos pueden entrar en conflicto con las teclas de control de la interfaz de terminal de su sistema. CTRL-U es la tecla por defecto para <<kill line>> en la mayoría de las versiones de Unix. Los sistemas Unix modernos utilizan CTRL-V y CTRL-W como ajustes por defecto para las funciones de interfaz de terminal <<citar siguiente carácter>> y <<borrar palabra>>, respectivamente. CTRL-V es particularmente confuso, ya que está pensado para anular otras teclas de control de la interfaz de terminal pero no tiene efecto sobre los comandos de emacs-mode. Sin embargo, emacs-mode funciona interpretando directamente cada carácter que escribes, por lo que la configuración de \emph{stty} se ignora en gran medida.
Varios de estos comandos pueden entrar en conflicto con las teclas de control de la interfaz de terminal de su sistema. CTRL-U es la tecla por defecto para <<kill line>> en la mayoría de las versiones de Unix. Los sistemas Unix modernos utilizan CTRL-V y CTRL-W como ajustes por defecto para las funciones de interfaz de terminal <<citar siguiente carácter>> y <<borrar palabra>>, respectivamente. CTRL-V es particularmente confuso, ya que está pensado para anular otras teclas de control de la interfaz de terminal pero no tiene efecto sobre los comandos de \emph{emacs-mode}. Sin embargo, \emph{emacs-mode} funciona interpretando directamente cada carácter que escribes, por lo que la configuración de \emph{stty} se ignora en gran medida.
Vale la pena discutir algunos comandos misceláneos, aunque no estén entre los comandos más útiles de emacs-mode.
Vale la pena discutir algunos comandos misceláneos, aunque no estén entre los comandos más útiles de \emph{emacs-mode}.
CTRL-O es útil para repetir una secuencia de comandos que ya has introducido. Simplemente vuelve al primer comando de la secuencia y pulsa CTRL-O en lugar de ENTER. Esto ejecuta el comando y muestra el siguiente comando en el archivo de historial. Pulsa CTRL-O de nuevo para ejecutar este comando y que aparezca el siguiente. Repite esto hasta que veas el último comando de la secuencia; entonces simplemente pulsa ENTER.
CTRL-U, si no realiza la función de borrado de línea de la interfaz de terminal de tu sistema, repite el siguiente comando cuatro veces. Si tecleas CTRL-U dos veces, el factor de repetición se convierte en 16; para 3 CTRL-Us es 64; y así sucesivamente. CTRL-U es posiblemente más útil cuando navegas a través de tu archivo histórico. Si quieres recordar un comando que introdujiste hace un rato, puedes teclear CTRL-U CTRL-P para retroceder cuatro líneas a la vez a través del archivo histórico; puedes pensar en esto como un <<rebobinado rápido>> a través de tu historial de comandos.
Otro posible uso de CTRL-U es cuando quieres ir de un extremo a otro de una ruta larga. A diferencia del modo vi, el modo emacs no tiene un concepto de <<palabra>> lo suficientemente flexible como para distinguir entre names de ruta y componentes de names de archivo. Los comandos de movimiento de palabra de emacs-mode (ESC b y ESC f) se mueven a través de un nombre de ruta sólo un componente a la vez, porque emacs-mode trata la barra como un separador de palabras. Puedes usar CTRL-U para evitar esta limitación. Si tienes una línea como esta:
Otro posible uso de CTRL-U es cuando quieres ir de un extremo a otro de una ruta larga. A diferencia del modo vi, el modo \emph{emacs} no tiene un concepto de <<palabra>> lo suficientemente flexible como para distinguir entre nombres de ruta y componentes de nombres de archivo. Los comandos de movimiento de palabra de \emph{emacs-mode} (ESC b y ESC f) se mueven a través de un nombre de ruta sólo un componente a la vez, porque \emph{emacs-mode} trata la barra como un separador de palabras. Puedes usar CTRL-U para evitar esta limitación. Si tienes una línea como esta:
\begin{lstlisting}[language=bash]
$ ls -l /a/very/long/pathname/filename
@ -349,7 +349,7 @@ $ ls -l /a/really(*\highlight{/}*)long/pathname/filename
El uso juicioso de CTRL-U puede ahorrarte algunas pulsaciones, pero teniendo en cuenta la pequeña cantidad de información que manipulas cuando editas líneas de comandos, probablemente no sea una función increíblemente vital. A menudo, mantener pulsada una tecla para repetirla es tan eficaz como CTRL-U. Dado que probablemente tendrás que utilizar el comando \emph{stty} para redefinir la tecla de borrado de línea del controlador de terminal antes de poder utilizar CTRL-U, probablemente sea mejor prescindir de ella.
La marca mencionada en la explicación de CTRL-W debería ser familiar para los usuarios de Emacs, pero su función en emacs-mode es un subconjunto de la que tiene en el editor completo. El modo Emacs mantiene un registro del lugar en el que se realizó la última operación de borrado (ya sea un carácter, palabra, línea o lo que sea); este lugar se llama \emph{marca}. Si no se ha borrado nada en la línea actual, la marca por defecto es el principio de la línea. También puede establecer la marca en el lugar donde se encuentra el cursor escribiendo ESC ESPACIO (o, alternativamente, CTRL-@). CTRL-X CTRL-X (CTRL-X pulsado dos veces) hace que el shell Korn intercambie el punto y la marca, es decir, que mueva el cursor a donde está la marca y vuelva a poner la marca donde estaba el cursor antes de teclear CTRL-X CTRL-X.
La marca mencionada en la explicación de CTRL-W debería ser familiar para los usuarios de Emacs, pero su función en \emph{emacs-mode} es un subconjunto de la que tiene en el editor completo. El modo Emacs mantiene un registro del lugar en el que se realizó la última operación de borrado (ya sea un carácter, palabra, línea o lo que sea); este lugar se llama \emph{marca}. Si no se ha borrado nada en la línea actual, la marca por defecto es el principio de la línea. También puede establecer la marca en el lugar donde se encuentra el cursor escribiendo ESC ESPACIO (o, alternativamente, CTRL-@). CTRL-X CTRL-X (CTRL-X pulsado dos veces) hace que el shell de Korn intercambie el punto y la marca, es decir, que mueva el cursor a donde está la marca y vuelva a poner la marca donde estaba el cursor antes de teclear CTRL-X CTRL-X.
El concepto de marca no es extremadamente útil debido a la poca <<distancia>> que hay que recorrer en las líneas de comandos. Pero si alguna vez tienes que hacer una serie de cambios en el mismo lugar de una línea, CTRL-X CTRL-X te llevará de vuelta allí. En el ejemplo anterior, si quisieras cambiar <<really>> por <<monumentalily>>, una forma sería escribir CTRL-X CTRL-X para volver al principio de <<really>>:
@ -369,14 +369,14 @@ ESC . y ESC \_ son útiles si desea ejecutar varios comandos en un archivo dado.
$ more myfilewithaverylongname
\end{lstlisting}
Luego decides que quieres imprimirlo, usando el comando de impresión \emph{lp}. Puede evitar teclear el nombre muy largo escribiendo \emph{lp} seguido de un espacio y luego ESC . o ESC \_; el shell Korn inserta \emph{myfilewithaverylongname} por usted.
Luego decides que quieres imprimirlo, usando el comando de impresión \emph{lp}. Puede evitar teclear el nombre muy largo escribiendo \emph{lp} seguido de un espacio y luego ESC . o ESC \_; el shell de Korn inserta \emph{myfilewithaverylongname} por usted.
Si eres un verdadero experto en Emacs y el modo incorporado no te funciona, usa CTRL-X CTRL-E para invocar el programa editor \emph{emacs} en tu línea de comandos. Cuando salgas del editor, si realmente hiciste cambios en el archivo, el shell ejecutará la línea de comandos final.
\subsection{Expansión de Macros con Alias}
A medida que te acostumbres a usar el modo emacs, puede que te des cuenta de que hay secuencias de comandos que ejecutas una y otra vez. Escribir estos comandos repetidamente es difícil y una pérdida de tiempo. Es mejor definir una \emph{macro} para ellos. Una macro es un nombre corto que, cuando se introduce, se expande en la secuencia completa de comandos.
A medida que te acostumbres a usar el modo \emph{emacs}, puede que te des cuenta de que hay secuencias de comandos que ejecutas una y otra vez. Escribir estos comandos repetidamente es difícil y una pérdida de tiempo. Es mejor definir una \emph{macro} para ellos. Una macro es un nombre corto que, cuando se introduce, se expande en la secuencia completa de comandos.
El shell Korn proporciona una función de macro, utilizando el mecanismo de alias (descrito en el siguiente capítulo), que le permite establecer una secuencia de comandos y luego invocarla con un único comando en modo emacs. Funciona de la siguiente manera: si defines un alias llamado \emph{\_x}, donde x es una letra, entonces cuando tecleas ESC x, emacs-mode expande el alias, y lo lee como entrada. El valor del alias puede contener texto normal, comandos emacs-mode, o ambos.
El shell de Korn proporciona una función de macro, utilizando el mecanismo de alias (descrito en el siguiente capítulo), que le permite establecer una secuencia de comandos y luego invocarla con un único comando en modo \emph{emacs}. Funciona de la siguiente manera: si defines un alias llamado \emph{\_x}, donde x es una letra, entonces cuando tecleas ESC x, \emph{emacs-mode} expande el alias, y lo lee como entrada. El valor del alias puede contener texto normal, comandos \emph{emacs-mode}, o ambos.
Por ejemplo, suponga que quiere que un comando ponga en mayúscula la primera letra de la palabra actual. Podrías definir un alias como sigue
@ -392,9 +392,9 @@ $ print here is a W(*\highlight{o}*)rd
\end{lstlisting}
\section{Modo de Edición Vi}
Al igual que emacs-mode, vi-mode crea esencialmente una ventana de edición de una línea en el archivo de historial. El modo vi es popular porque vi es el editor más estándar de Unix. Pero la función para la que fue diseñado vi, escribir programas en C, tiene unos requisitos de edición diferentes a los de los intérpretes de comandos. Como resultado, aunque es posible hacer cosas complejas en vi con relativamente pocas pulsaciones de tecla, las cosas relativamente simples que necesitas hacer en el shell Korn a veces requieren demasiadas pulsaciones de tecla.
Al igual que \emph{emacs-mode}, \emph{vi-mode} crea esencialmente una ventana de edición de una línea en el archivo de historial. El modo vi es popular porque vi es el editor más estándar de Unix. Pero la función para la que fue diseñado vi, escribir programas en C, tiene unos requisitos de edición diferentes a los de los intérpretes de comandos. Como resultado, aunque es posible hacer cosas complejas en vi con relativamente pocas pulsaciones de tecla, las cosas relativamente simples que necesitas hacer en el shell de Korn a veces requieren demasiadas pulsaciones de tecla.
Al igual que \emph{vi}, vi-mode tiene dos modos propios: modo de entrada y modo de control. El primero es para teclear comandos (como en el uso normal del shell Korn); el segundo es para moverse por la línea de comandos y el fichero histórico. Cuando estás en modo de entrada, puedes escribir comandos y pulsar ENTER para ejecutarlos. Además, tiene capacidades mínimas de edición a través de caracteres de control, que se resumen en la Tabla \ref{tab2.6}.
Al igual que \emph{vi}, \emph{vi-mode} tiene dos modos propios: modo de entrada y modo de control. El primero es para teclear comandos (como en el uso normal del shell de Korn); el segundo es para moverse por la línea de comandos y el fichero histórico. Cuando estás en modo de entrada, puedes escribir comandos y pulsar ENTER para ejecutarlos. Además, tiene capacidades mínimas de edición a través de caracteres de control, que se resumen en la Tabla \ref{tab2.6}.
\begin{table}[h]
\center
@ -410,12 +410,12 @@ Al igual que \emph{vi}, vi-mode tiene dos modos propios: modo de entrada y modo
\end{tabular}
\end{table}
\textbf{NOTA:} Al menos algunos de estos comandos de edición -- dependiendo de la versión de Unix que tenga -- son los mismos que los proporcionados por los sistemas Unix modernos en la interfaz de terminal. Vi-mode usa su caracter <<erase>> como la tecla <<delete previous character>> (borrar caracter previo); usualmente se establece en DEL o CTRL-H (BACKSPACE). CTRL-V hace que el siguiente carácter que escriba aparezca en la línea de comandos tal cual; es decir, si es un comando de edición (o un carácter especial como CTRL-D), se le quita su significado especial.
\textbf{NOTA:} Al menos algunos de estos comandos de edición -- dependiendo de la versión de Unix que tenga -- son los mismos que los proporcionados por los sistemas Unix modernos en la interfaz de terminal. \emph{Vi-mode} usa su caracter <<erase>> como la tecla <<delete previous character>> (borrar caracter previo); usualmente se establece en DEL o CTRL-H (BACKSPACE). CTRL-V hace que el siguiente carácter que escriba aparezca en la línea de comandos tal cual; es decir, si es un comando de edición (o un carácter especial como CTRL-D), se le quita su significado especial.
En circunstancias normales, sólo tiene que permanecer en el modo de entrada. Pero si quieres volver atrás y hacer cambios en tu línea de comandos, o si quieres recuperar comandos anteriores, necesitas ir al modo de control. Para ello, pulsa ESC.
\subsection{Comandos de Modo de Control Simple}
En el modo de control tienes a tu disposición una amplia gama de comandos de edición de \emph{vi}. Los más sencillos te mueven por la línea de comandos\footnote{Al igual que con el modo emacs, desde ksh93h, puede utilizar secuencias de teclas de flecha estándar ANSI para moverse hacia adelante y hacia atrás en la línea de comandos, y hacia arriba y hacia abajo dentro de la lista del historial.} y se resumen en la Tabla \ref{Tab:2-7}. El modo vi contiene dos conceptos de <<palabra>>. El más simple es cualquier secuencia de caracteres que no sean espacios en blanco; lo llamaremos \emph{palabra no en blanco}. El otro es cualquier secuencia de sólo caracteres alfanuméricos (letras y dígitos) o cualquier secuencia de sólo caracteres no alfanuméricos; llamaremos a esto una \emph{palabra}.\footnote{Ninguna de estas definiciones es la misma que la definición de palabra en modo emacs.}
En el modo de control tienes a tu disposición una amplia gama de comandos de edición de \emph{vi}. Los más sencillos te mueven por la línea de comandos\footnote{Al igual que con el modo \emph{emacs}, desde \emph{ksh93h}, puede utilizar secuencias de teclas de flecha estándar ANSI para moverse hacia adelante y hacia atrás en la línea de comandos, y hacia arriba y hacia abajo dentro de la lista del historial.} y se resumen en la Tabla \ref{Tab:2-7}. El modo vi contiene dos conceptos de <<palabra>>. El más simple es cualquier secuencia de caracteres que no sean espacios en blanco; lo llamaremos \emph{palabra no en blanco}. El otro es cualquier secuencia de sólo caracteres alfanuméricos (letras y dígitos) o cualquier secuencia de sólo caracteres no alfanuméricos; llamaremos a esto una \emph{palabra}.\footnote{Ninguna de estas definiciones es la misma que la definición de palabra en modo \emph{emacs}.}
\begin{table}[h]
\center
@ -487,7 +487,7 @@ Y escribiendo una \emph{w} adicional te lleva a:
$ fgrep -l Bob < ~pete(*\highlight{/}*)wk/names
\end{lstlisting}
Por otro lado, \texttt{E} te lleva al final de la palabra actual no en blanco -- en este caso, el final de la línea. (Aunque a primera vista los comandos pueden parecer no nemotécnicos, generalmente hay cierto orden en la elección de las letras de los comandos. Cada letra de comando suele ser la primera letra de la palabra inglesa correspondiente a la operación. Las minúsculas sirven para las palabras, mientras que las mayúsculas sirven para las palabras que no están en blanco. Entender esto es sin duda más difícil si el inglés no es tu lengua materna, pero eso también se aplica a los comandos del modo emacs).
Por otro lado, \texttt{E} te lleva al final de la palabra actual no en blanco -- en este caso, el final de la línea. (Aunque a primera vista los comandos pueden parecer no nemotécnicos, generalmente hay cierto orden en la elección de las letras de los comandos. Cada letra de comando suele ser la primera letra de la palabra inglesa correspondiente a la operación. Las minúsculas sirven para las palabras, mientras que las mayúsculas sirven para las palabras que no están en blanco. Entender esto es sin duda más difícil si el inglés no es tu lengua materna, pero eso también se aplica a los comandos del modo \emph{emacs}).
\subsection{Introducción y cambio de texto}
Ahora que ya sabes cómo entrar en el modo de control y moverte por la línea de comandos, necesitas saber cómo volver al modo de entrada para poder hacer cambios y escribir comandos adicionales. Una serie de comandos le llevan del modo de control al modo de entrada; se enumeran en la Tabla \ref{tab2.8}. Todos ellos entran en el modo de entrada de forma un poco diferente. Todos ellos entran en el modo de entrada de forma un poco diferente.
@ -585,7 +585,7 @@ La mayoría de la gente tiende a usar \texttt{D} para borrar hasta el final de l
\end{tabular}
\end{table}
Todo buen editor proporciona comandos <<undelete>> así como comandos de borrado, y vi-mode no es una excepción. Vi-mode mantiene un \emph{buffer de borrado} que almacena todas las modificaciones al texto en la línea actual solamente (note que esto es diferente del editor vi completo). El comando \texttt{u} deshace sólo el último comando de modificación de texto, mientras que \texttt{U} deshace todos los comandos de este tipo en la línea actual. Así que si haces un cambio y quieres deshacerlo, teclea \texttt{u}; si haces muchos cambios y encuentras que el original se acerca más a lo que quieres, puedes deshacerlo todo tecleando \texttt{U}. Un comando relacionado es . (punto), que rehace el último comando de modificación de texto.
Todo buen editor proporciona comandos <<undelete>> así como comandos de borrado, y \emph{vi-mode} no es una excepción. \emph{Vi-mode} mantiene un \emph{buffer de borrado} que almacena todas las modificaciones al texto en la línea actual solamente (note que esto es diferente del editor vi completo). El comando \texttt{u} deshace sólo el último comando de modificación de texto, mientras que \texttt{U} deshace todos los comandos de este tipo en la línea actual. Así que si haces un cambio y quieres deshacerlo, teclea \texttt{u}; si haces muchos cambios y encuentras que el original se acerca más a lo que quieres, puedes deshacerlo todo tecleando \texttt{U}. Un comando relacionado es . (punto), que rehace el último comando de modificación de texto.
También hay una forma de guardar texto en el búfer de borrado sin haberlo borrado en primer lugar: simplemente teclea un comando de borrado pero utiliza \texttt{y} (<<yank>>) en lugar de d. Esto no modifica nada, pero te permite recuperar el texto yankado tantas veces como quieras más adelante. El comando para recuperar el texto arrancado es \texttt{p}, que inserta (<<pone>>) el texto en la línea actual a la derecha del cursor. La versión en mayúsculas, P, coloca el texto a la izquierda del cursor. Los distintos comandos de cortar y pegar se resumen en la Tabla \ref{tab2.11}.
@ -672,7 +672,7 @@ Bill Joy desarrolló originalmente \emph{vi} para ejecutarse en terminales Lear-
Otra razón (parcial) para la elección de los comandos es que CTRL-H es la tecla tradicional de retroceso, y CTRL-J denota salto de línea. La razón principal para estas elecciones, sin embargo, es que con estas teclas, nunca es necesario mover las manos de la <<fila de inicio>> del teclado.
Puede que + y - sean mejores mnemotécnicos que \texttt{j} y \texttt{k}, pero estos últimos tienen la ventaja de ser más accesibles para los mecanógrafos táctiles. En cualquier caso, estos comandos son los más básicos para moverse por el historial. Para ver cómo funcionan, tomemos los mismos ejemplos que usamos al hablar del modo emacs.
Puede que + y - sean mejores mnemotécnicos que \texttt{j} y \texttt{k}, pero estos últimos tienen la ventaja de ser más accesibles para los mecanógrafos táctiles. En cualquier caso, estos comandos son los más básicos para moverse por el historial. Para ver cómo funcionan, tomemos los mismos ejemplos que usamos al hablar del modo \emph{emacs}.
Introduce el comando de ejemplo (ENTER funciona tanto en modo de entrada como de control, al igual que newline o CTRL-J):
@ -746,9 +746,9 @@ El comando \% es muy útil para encontrar el carácter <<pair>> coincidente cuan
Un último comando completa los comandos del modo de control de \emph{vi} para desplazarse por la línea actual: puede utilizar el carácter de tubería (|) para desplazarse a una columna específica, cuyo número viene dado por un argumento de prefijo numérico. El recuento de columnas comienza en 1; cuente sólo su entrada, no el espacio ocupado por la cadena de texto. La cuenta de repetición por defecto es 1, por supuesto, lo que significa que teclear | por sí mismo equivale a 0 (ver Tabla \ref{Tab:2-7}).
\subsection{Nombre de Archivo y Finalización y Expansión de Variables}
El modo vi proporciona una característica adicional que creemos que utilizarás con bastante frecuencia: el completado de names de archivo. Esta característica no forma parte del editor \emph{vi} real, y sin duda se inspiró en características similares de Emacs y, originalmente, en el sistema operativo TOPS-20 para mainframes DEC.
El modo vi proporciona una característica adicional que creemos que utilizarás con bastante frecuencia: el completado de nombres de archivo. Esta característica no forma parte del editor \emph{vi} real, y sin duda se inspiró en características similares de Emacs y, originalmente, en el sistema operativo TOPS-20 para mainframes DEC.
La lógica detrás del completado de names de fichero es simple: debería tener que teclear sólo lo necesario de un nombre de fichero para distinguirlo de otros names de fichero en el mismo directorio. La barra invertida (\textbackslash{}) es el comando que indica al shell Korn que complete el nombre de fichero en modo vi. Si teclea una palabra, teclea ESC para entrar en modo de control, y luego teclea \textbackslash{}, una de cuatro cosas sucede; son las mismas que para TAB (o ESC ESC) en modo emacs:
La lógica detrás del completado de nombres de fichero es simple: debería tener que teclear sólo lo necesario de un nombre de fichero para distinguirlo de otros nombres de fichero en el mismo directorio. La barra invertida (\textbackslash{}) es el comando que indica al shell de Korn que complete el nombre de fichero en modo vi. Si teclea una palabra, teclea ESC para entrar en modo de control, y luego teclea \textbackslash{}, una de cuatro cosas sucede; son las mismas que para TAB (o ESC ESC) en modo \emph{emacs}:
\begin{enumerate}
\item{Si no hay ningún fichero cuyo nombre empiece por la palabra, el intérprete de comandos emite un pitido y no ocurre nada más.}
@ -757,11 +757,11 @@ La lógica detrás del completado de names de fichero es simple: debería tener
\item{Si hay más de una forma de completar el nombre de archivo, el shell lo completa con el prefijo común más largo entre las opciones disponibles.}
\end{enumerate}
Como en el modo emacs, a partir de \emph{ksh93h}, puede usar TAB en lugar de ESC \textbackslash{}. Sin embargo, esto sólo funciona si utiliza \emph{set -o viraw} además de \emph{set -o vi}. (La opción \emph{viraw} consume un poco más de CPU -- aunque probablemente no de forma notable -- y es necesaria en algunos sistemas Unix antiguos para que el modo vi funcione). Afortunadamente, a partir de \emph{ksh93n}, la opción \emph{viraw} se activa automáticamente cuando se utiliza el modo vi.
Como en el modo \emph{emacs}, a partir de \emph{ksh93h}, puede usar TAB en lugar de ESC \textbackslash{}. Sin embargo, esto sólo funciona si utiliza \emph{set -o viraw} además de \emph{set -o vi}. (La opción \emph{viraw} consume un poco más de CPU -- aunque probablemente no de forma notable -- y es necesaria en algunos sistemas Unix antiguos para que el modo vi funcione). Afortunadamente, a partir de \emph{ksh93n}, la opción \emph{viraw} se activa automáticamente cuando se utiliza el modo vi.
Un comando relacionado es *, que es el mismo que ESC * en modo emacs como se describió anteriormente en este capítulo \footnote{Si contamos la ESC necesaria para salir del modo de entrada, el comando vi-mode es idéntico a emacs-mode.}. Se comporta de forma similar a ESC \textbackslash{}, pero si hay más de una posibilidad de finalización (número cuatro en la lista anterior), enumera todas ellas y le permite seguir escribiendo. Por lo tanto, se asemeja al carácter comodín del shell *.
Un comando relacionado es *, que es el mismo que ESC * en modo \emph{emacs} como se describió anteriormente en este capítulo \footnote{Si contamos la ESC necesaria para salir del modo de entrada, el comando \emph{vi-mode} es idéntico a \emph{emacs-mode}.}. Se comporta de forma similar a ESC \textbackslash{}, pero si hay más de una posibilidad de finalización (número cuatro en la lista anterior), enumera todas ellas y le permite seguir escribiendo. Por lo tanto, se asemeja al carácter comodín del shell *.
Por último, el comando = realiza el mismo tipo de expansión de nombre de archivo que el comodín de shell *, pero de forma diferente. En lugar de expandir los names de archivo en la línea de comandos, los imprime en una lista numerada con un nombre de archivo en cada línea. Luego te devuelve el prompt del shell y vuelve a escribir lo que había en tu línea de comandos antes de que teclearas =. Por ejemplo, si los archivos de tu directorio incluyen \emph{program.c} y \emph{problem.c}, y tecleas pro seguido de ESC y luego =, verás esto:
Por último, el comando = realiza el mismo tipo de expansión de nombre de archivo que el comodín de shell *, pero de forma diferente. En lugar de expandir los nombres de archivo en la línea de comandos, los imprime en una lista numerada con un nombre de archivo en cada línea. Luego te devuelve el prompt del shell y vuelve a escribir lo que había en tu línea de comandos antes de que teclearas =. Por ejemplo, si los archivos de tu directorio incluyen \emph{program.c} y \emph{problem.c}, y tecleas pro seguido de ESC y luego =, verás esto:
\begin{lstlisting}[language=bash, escapeinside={(*}{*)}]]
$ cc pro # ESC = escrito en este punto
@ -782,7 +782,7 @@ Si desea \emph{program.c}, basta con escribir 2 =, y el intérprete de comandos
$ cc programa.c
\end{lstlisting}
Como en el modo emacs, también puedes completar comandos desde el modo vi. Los comandos *, \textbackslash{} y =, cuando se usan en la primera palabra de la línea de comandos, expanden alias, funciones y comandos. También como en el modo emacs, a partir de \emph{ksh93l}, estas expansiones funcionan cuando has abierto una cadena entrecomillada pero aún no la has cerrado, y para expansiones de variables con \texttt{\$} y \texttt{''\$}.
Como en el modo \emph{emacs}, también puedes completar comandos desde el modo \emph{vi}. Los comandos *, \textbackslash{} y =, cuando se usan en la primera palabra de la línea de comandos, expanden alias, funciones y comandos. También como en el modo \emph{emacs}, a partir de \emph{ksh93l}, estas expansiones funcionan cuando has abierto una cadena entrecomillada pero aún no la has cerrado, y para expansiones de variables con \texttt{\$} y \texttt{''\$}.
\subsection{Comandos Misceláneos}
Varios comandos misceláneos completan el modo vi; algunos de ellos son bastante esotéricos. Se enumeran en la Tabla \ref{tab2.14}.
@ -795,20 +795,20 @@ Varios comandos misceláneos completan el modo vi; algunos de ellos son bastante
\textbf{Comando} & \textbf{Descripción} \\ \hline
\~{} & Invertir (<<twiddle>>) el caso del carácter(es) actual(es). \\\hline
\_ & Añade la última palabra del comando anterior; entra en modo de entrada. Una cuenta repetida añade la enésima palabra dada, empezando desde el principio del comando. \\\hline
v & Ejecuta el comando hist en la línea actual (en realidad, ejecuta el comando \texttt{hist -e \$\{VISUAL:-\$\{EDITOR:-vi\}\}}); normalmente esto significa ejecutar el vi completo en la línea actual. \\\hline
v & Ejecuta el comando \emph{hist} en la línea actual (en realidad, ejecuta el comando \texttt{hist -e \$\{VISUAL:-\$\{EDITOR:-vi\}\}}); normalmente esto significa ejecutar el vi completo en la línea actual. \\\hline
CTRL-L & Inicia una nueva línea y vuelve a dibujar la línea actual en ella; bueno para cuando tu pantalla se vuelve confusa. \\\hline
CTRL-V & Imprime la versión del shell Korn. \\\hline
CTRL-V & Imprime la versión del shell de Korn. \\\hline
\# & Antepone \# (carácter de comentario) a la línea y la envía al fichero de historial;\tablefootnote{La línea también es <<ejecutada>> por el shell. Sin embargo, \# es el carácter de comentario del shell, por lo que ésta lo ignora.} útil para guardar un comando y ejecutarlo más tarde sin tener que volver a escribirlo. Si la línea ya empieza con \#, elimina el \# inicial y cualquier otro carácter de comentario que siga a nuevas líneas en un comando multilínea. \\\hline
@x & Inserta la expansión del alias \_x como entrada en modo comando (ver texto). \\\hline
\end{tabular}
\end{table}
El primero de ellos puede ir precedido de una cuenta de repetición. Una cuenta de repetición de \emph{n} precediendo al \~{} cambia el caso de los \emph{n} caracteres siguientes. \footnote{Esto, en nuestra opinión, es un defecto de diseño en el editor vi que los autores del shell Korn podrían haber corregido. Permitir al usuario añadir un comando de movimiento a ~ y hacer que se comporte de forma análoga a d o y habría sido mucho más útil; de esa forma, se podría cambiar de mayúsculas a minúsculas una palabra con sólo dos pulsaciones de tecla.} El cursor avanza en consecuencia.
El primero de ellos puede ir precedido de una cuenta de repetición. Una cuenta de repetición de \emph{n} precediendo al \~{} cambia el caso de los \emph{n} caracteres siguientes. \footnote{Esto, en nuestra opinión, es un defecto de diseño en el editor vi que los autores del shell de Korn podrían haber corregido. Permitir al usuario añadir un comando de movimiento a ~ y hacer que se comporte de forma análoga a d o y habría sido mucho más útil; de esa forma, se podría cambiar de mayúsculas a minúsculas una palabra con sólo dos pulsaciones de tecla.} El cursor avanza en consecuencia.
Un conteo de repeticiones que precede a \_ hace que la \emph{n} -ésima palabra del comando anterior se inserte en la línea actual; sin el conteo, se usa la última palabra. Omitir el recuento de repeticiones es útil porque un nombre de archivo suele ser lo último en una línea de comandos de Unix y porque los usuarios suelen ejecutar varios comandos seguidos en el mismo archivo. Con esta función, puede escribir todos los comandos (excepto el primero) seguidos de ESC \_ y el shell inserta el nombre del archivo.
\subsection{Expansión de Macros con Alias}
Tal como se describió anteriormente para el modo emacs, puede utilizar la función de alias del shell (descrita en el siguiente capítulo) para crear \emph{macros}, es decir, abreviaturas de una sola letra para secuencias más largas de comandos. Si crea un alias llamado \_x, donde x es una letra, entonces cuando escriba @ x, el modo vi expande el alias y lo lee como entrada del modo comando.
Tal como se describió anteriormente para el modo \emph{emacs}, puede utilizar la función de alias del shell (descrita en el siguiente capítulo) para crear \emph{macros}, es decir, abreviaturas de una sola letra para secuencias más largas de comandos. Si crea un alias llamado \_x, donde x es una letra, entonces cuando escriba @ x, el modo vi expande el alias y lo lee como entrada del modo comando.
Como antes, suponga que quiere que un comando ponga en mayúscula la primera letra de la palabra actual. Podría definir un alias como sigue:
@ -833,13 +833,13 @@ La opción \emph{-l} para \emph{hist} lista los comandos anteriores. Toma argume
\item{Si das dos argumentos, sirven como la primera y la última orden a mostrar.}
\item{Si especifica un argumento numérico, sólo se muestra la orden con ese número.}
\item{Con un único argumento de cadena, \emph{hist} busca el comando más reciente que empiece por esa cadena y le muestra todo desde ese comando hasta el comando más reciente.}
\item{Si no especifica ningún argumento, verá los últimos 16 comandos introducidos. Así, \texttt{hist -l} por sí mismo es equivalente al comando \emph{history} del shell C, y de hecho el shell Korn define un alias incorporado history como:
\item{Si no especifica ningún argumento, verá los últimos 16 comandos introducidos. Así, \texttt{hist -l} por sí mismo es equivalente al comando \emph{history} del shell C, y de hecho el shell de Korn define un alias incorporado \emph{history} como:
\begin{lstlisting}[language=bash]
alias history='hist -l'
\end{lstlisting}
Como verá en el \hyperref[sec:Chapter3]{Capítulo 3}, esto significa que puede escribir history y el shell Korn ejecutará el comando \texttt{hist -l.}
Como verá en el \hyperref[sec:Chapter3]{Capítulo 3}, esto significa que puede escribir \emph{history} y el shell de Korn ejecutará el comando \texttt{hist -l.}
}
\end{itemize}
@ -869,7 +869,7 @@ Los números de historial negativos indican valores relativos al número de coma
La opción \emph{-l} de \emph{hist} no es particularmente útil, excepto como una forma rápida de recordar qué comandos ha escrito recientemente. Utilice el alias \texttt{history} si es un usuario experimentado del shell C.
La otra opción importante de \emph{hist} es \emph{-e} para <<editar>>. Es útil como <<escotilla de escape>> de los modos vi- y emacs si no estás acostumbrado a ninguno de esos editores. Puede especificar la ruta de su editor favorito y editar comandos desde su archivo de historial; entonces, cuando haya hecho los cambios, el shell ejecutará las nuevas líneas.
La otra opción importante de \emph{hist} es \emph{-e} para <<editar>>. Es útil como <<escotilla de escape>> de los modos \emph{vi} y \emph{emacs} si no estás acostumbrado a ninguno de esos editores. Puede especificar la ruta de su editor favorito y editar comandos desde su archivo de historial; entonces, cuando haya hecho los cambios, el shell ejecutará las nuevas líneas.
Digamos que tu editor favorito es una pequeña joya casera llamada \emph{zed}. Podrías editar tus comandos escribiendo:
@ -877,7 +877,7 @@ Digamos que tu editor favorito es una pequeña joya casera llamada \emph{zed}. P
$ hist -e /usr/local/bin/zed
\end{lstlisting}
se obtiene \emph{zed} al invocar \emph{hist}. HISTEDIT utiliza por defecto el antiguo editor de líneas ed, de modo que el valor general por defecto es también ed.\footnote{El valor por defecto es en realidad un poco complicado en \emph{ksh93}. \texttt{hist -e} ejecuta \texttt{\$\{HISTEDIT:-\$FCEDIT\}} para editar la línea de comandos. Esto preserva la compatibilidad con \emph{ksh88}, donde la variable para el comando \emph{fc} era, no sorprendentemente, \texttt{FCEDIT}. Si no se establece ninguna de las dos variables, se obtiene \emph{/bin/ed}. (La construcción \texttt{\$\{HISTEDIT:-\$FCEDIT\}} se explica en el \hyperref[sec:Chapter4]{Capítulo 4}.) El resultado es utilizar el editor especificado por la variable \texttt{HISTEDIT} si está establecida; de lo contrario, utilice el valor de la variable \texttt{FCEDIT}).}
se obtiene \emph{zed} al invocar \emph{hist}. HISTEDIT utiliza por defecto el antiguo editor de líneas \emph{ed}, de modo que el valor general por defecto es también \emph{ed}.\footnote{El valor por defecto es en realidad un poco complicado en \emph{ksh93}. \texttt{hist -e} ejecuta \texttt{\$\{HISTEDIT:-\$FCEDIT\}} para editar la línea de comandos. Esto preserva la compatibilidad con \emph{ksh88}, donde la variable para el comando \emph{fc} era, no sorprendentemente, \texttt{FCEDIT}. Si no se establece ninguna de las dos variables, se obtiene \emph{/bin/ed}. (La construcción \texttt{\$\{HISTEDIT:-\$FCEDIT\}} se explica en el \hyperref[sec:Chapter4]{Capítulo 4}.) El resultado es utilizar el editor especificado por la variable \texttt{HISTEDIT} si está establecida; de lo contrario, utilice el valor de la variable \texttt{FCEDIT}).}
\emph{hist} se utiliza normalmente para arreglar un comando reciente. Por lo tanto, maneja los argumentos de manera un poco diferente a como lo hace para la variación \texttt{hist -l} anterior:
@ -888,7 +888,7 @@ se obtiene \emph{zed} al invocar \emph{hist}. HISTEDIT utiliza por defecto el an
\item{Con dos argumentos a \emph{hist}, los argumentos especifican el principio y el final de un rango de comandos, como arriba.}
\end{itemize}
Recuerde que \emph{hist} ejecuta los comandos después de que usted los edite. Por lo tanto, la última opción puede ser peligrosa. El shell Korn intenta ejecutar todos los comandos en el rango que especifique cuando salga de su editor. Si ha escrito alguna construcción multilínea (como las que veremos en el \hyperref[sec:Chapter5]{Capítulo 5}), los resultados pueden ser incluso más peligrosos. Aunque estas pueden parecer formas válidas de generar <<programas de shell instantáneos>>, una estrategia mucho mejor sería dirigir la salida de \texttt{hist -nl} con los mismos argumentos a un archivo; luego edite ese archivo y ejecute los comandos cuando esté satisfecho con ellos:
Recuerde que \emph{hist} ejecuta los comandos después de que usted los edite. Por lo tanto, la última opción puede ser peligrosa. El shell de Korn intenta ejecutar todos los comandos en el rango que especifique cuando salga de su editor. Si ha escrito alguna construcción multilínea (como las que veremos en el \hyperref[sec:Chapter5]{Capítulo 5}), los resultados pueden ser incluso más peligrosos. Aunque estas pueden parecer formas válidas de generar <<programas de shell instantáneos>>, una estrategia mucho mejor sería dirigir la salida de \texttt{hist -nl} con los mismos argumentos a un archivo; luego edite ese archivo y ejecute los comandos cuando esté satisfecho con ellos:
\begin{lstlisting}[language=bash]
$ hist -nl cp > lastcommands # Listar todos los comandos que empiezan por cp en lastcommands
@ -898,9 +898,9 @@ $ . lastcommands # Ejecuta los comandos que contiene
En este caso, ¡el shell no intentará ejecutar el fichero cuando abandones el editor!
Hay un último uso para \emph{hist}. Si especifica la opción \emph{-s} (es decir, \emph{type hist -s}), el shell Korn se saltará la parte de edición y sólo ejecutará el/los comando(s) especificado(s) por el/los argumento(s). ¿Por qué es útil? Por un lado, simplemente tecleando hist \emph{-s} hace que el comando anterior se repita, igual que el comando !! del shell C. El shell Korn proporciona el alias incorporado \emph{r} para esto, de modo que si escribe \texttt{r} y pulsa ENTER, repetirá el último comando.
Hay un último uso para \emph{hist}. Si especifica la opción \emph{-s} (es decir, \emph{type hist -s}), el shell de Korn se saltará la parte de edición y sólo ejecutará el/los comando(s) especificado(s) por el/los argumento(s). ¿Por qué es útil? Por un lado, simplemente tecleando hist \emph{-s} hace que el comando anterior se repita, igual que el comando !! del shell C. El shell de Korn proporciona el alias incorporado \emph{r} para esto, de modo que si escribe \texttt{r} y pulsa ENTER, repetirá el último comando.
Esta forma de \emph{hist} permite aún otro tipo de argumento, de la forma \emph{old=new}, que significa <<cambia las ocurrencias de \emph{old} en el comando anterior especificado a \emph{new} y luego ejecútalo>>. (Desafortunadamente, no puede hacer que el shell Korn haga este tipo de sustitución más de una vez; sólo cambia la primera ocurrencia de \emph{old} a \emph{new}). Por ejemplo, suponga que está usando troff y sus preprocesadores para trabajar en un documento.\footnote{Si es así, ¡eres de una raza rara!} Si accidentalmente ejecuta el preprocesador tbl con este comando:
Esta forma de \emph{hist} permite aún otro tipo de argumento, de la forma \emph{old=new}, que significa <<cambia las ocurrencias de \emph{old} en el comando anterior especificado a \emph{new} y luego ejecútalo>>. (Desafortunadamente, no puede hacer que el shell de Korn haga este tipo de sustitución más de una vez; sólo cambia la primera ocurrencia de \emph{old} a \emph{new}). Por ejemplo, suponga que está usando \emph{troff} y sus preprocesadores para trabajar en un documento.\footnote{Si es así, ¡eres de una raza rara!} Si accidentalmente ejecuta el preprocesador \emph{tbl} con este comando:
\begin{lstlisting}[language=bash]
tbl ch2.tr | troff -ms -Tps > ch2.ps
@ -912,22 +912,22 @@ pero necesitabas ejecutar \emph{eqn}, puedes volver a hacerlo escribiendo \textt
eqn ch2.tr | troff -ms -Tps > ch2.ps
\end{lstlisting}
El shell Korn imprime el comando modificado antes de ejecutarlo.
El shell de Korn imprime el comando modificado antes de ejecutarlo.
\section{Hábitos de los Dedos}
Parafraseando el viejo adagio, los viejos hábitos de los dedos son difíciles de erradicar. De hecho, esa es la razón principal de la elección de vi y Emacs para los modos de edición del shell Korn. Si eres un usuario experimentado de uno de estos editores, utiliza el modo de edición correspondiente del shell Korn. Si eres un mago del vi, probablemente sepas cómo navegar entre dos puntos cualesquiera de una línea en tres pulsaciones de tecla o menos.
Parafraseando el viejo adagio, los viejos hábitos de los dedos son difíciles de erradicar. De hecho, esa es la razón principal de la elección de \emph{vi} y Emacs para los modos de edición del shell de Korn. Si eres un usuario experimentado de uno de estos editores, utiliza el modo de edición correspondiente del shell de Korn. Si eres un mago del \emph{vi}, probablemente sepas cómo navegar entre dos puntos cualesquiera de una línea en tres pulsaciones de tecla o menos.
Pero si no lo eres, deberías plantearte seriamente adoptar hábitos dactilares en modo emacs. Dado que se basa en las teclas de control, al igual que el soporte de edición mínimo que ya habrás utilizado con el shell Bourne o C, el modo emacs te resultará más fácil de asimilar. Aunque el Emacs completo es un editor extremadamente potente, su estructura de comandos se presta muy bien a pequeños subconjuntos: hay varios editores estilo <<mini-emacs>> flotando por ahí para Unix, MS-DOS y otros sistemas.
Pero si no lo eres, deberías plantearte seriamente adoptar hábitos dactilares en modo \emph{emacs}. Dado que se basa en las teclas de control, al igual que el soporte de edición mínimo que ya habrás utilizado con el shell de Bourne o C, el modo \emph{emacs} te resultará más fácil de asimilar. Aunque el Emacs completo es un editor extremadamente potente, su estructura de comandos se presta muy bien a pequeños subconjuntos: hay varios editores estilo <<mini-emacs>> flotando por ahí para Unix, MS-DOS y otros sistemas.
No se puede decir lo mismo de \emph{vi}, porque su estructura de comandos está realmente pensada para usarse en un editor a pantalla completa. \emph{vi} es bastante potente también, a su manera, pero su potencia se hace evidente sólo cuando se usa para propósitos similares a aquellos para los que fue diseñado: editar código fuente en C y LISP. Hacer cosas complicadas en \emph{vi} requiere relativamente pocas pulsaciones. Pero hacer cosas sencillas requiere más pulsaciones en modo \emph{vi} que en modo emacs. Por desgracia, la capacidad de hacer cosas sencillas con un número mínimo de pulsaciones es lo más deseado en un intérprete de comandos, especialmente hoy en día, cuando los usuarios pasan más tiempo dentro de las aplicaciones y menos trabajando con el intérprete de comandos.
No se puede decir lo mismo de \emph{vi}, porque su estructura de comandos está realmente pensada para usarse en un editor a pantalla completa. \emph{vi} es bastante potente también, a su manera, pero su potencia se hace evidente sólo cuando se usa para propósitos similares a aquellos para los que fue diseñado: editar código fuente en C y LISP. Hacer cosas complicadas en \emph{vi} requiere relativamente pocas pulsaciones. Pero hacer cosas sencillas requiere más pulsaciones en modo \emph{vi} que en modo \emph{emacs}. Por desgracia, la capacidad de hacer cosas sencillas con un número mínimo de pulsaciones es lo más deseado en un intérprete de comandos, especialmente hoy en día, cuando los usuarios pasan más tiempo dentro de las aplicaciones y menos trabajando con el intérprete de comandos.
Ambos modos de edición del intérprete de comandos Korn tienen bastantes comandos; sin duda desarrollarás hábitos de digitación que incluyen sólo algunos de ellos. Si usas el modo emacs y no estás familiarizado con el Emacs completo, aquí tienes un subconjunto que es fácil de aprender pero que te permite hacer casi cualquier cosa:
Ambos modos de edición del intérprete de comandos Korn tienen bastantes comandos; sin duda desarrollarás hábitos de digitación que incluyen sólo algunos de ellos. Si usas el modo \emph{emacs} y no estás familiarizado con el Emacs completo, aquí tienes un subconjunto que es fácil de aprender pero que te permite hacer casi cualquier cosa:
\begin{itemize}
\item{Para mover el cursor por la línea de comandos, usa CTRL-A y CTRL-E para empezar y terminar la línea, y CTRL-F y CTRL-B para moverte por ella.}
\item{Borra con DEL (o la tecla de borrado que tengas) y CTRL-D; al igual que con CTRL-F y CTRL-B, mantén pulsada la tecla para repetir si es necesario. Usa CTRL-C para borrar toda la línea.}
\item{Utiliza CTRL-P para recuperar el último comando si cometes un error.}
\item{Usa CTRL-R para buscar un comando que necesites ejecutar de nuevo.} \item{Utiliza TAB para completar names de archivo, comandos y variables.}
\item{Usa CTRL-R para buscar un comando que necesites ejecutar de nuevo.} \item{Utiliza TAB para completar nombres de archivo, comandos y variables.}
\end{itemize}
Tras unas horas aprendiendo estos hábitos, te preguntarás cómo has podido vivir sin la edición en línea de comandos.

View File

@ -6,7 +6,7 @@ Puedes personalizar el aspecto de tu escritorio colocando los bolígrafos donde
De forma similar, los shells de Unix te presentan conceptos como ficheros, directorios y entrada y salida estándar, mientras que el propio Unix te da herramientas para trabajar con ellos, como comandos de manipulación de ficheros, editores de texto y colas de impresión. El aspecto de tu entorno Unix viene determinado por tu teclado y pantalla, por supuesto, pero también por cómo configuras tus directorios, dónde colocas cada tipo de fichero y qué nombres das a los ficheros, directorios y comandos. También hay formas más sofisticadas de personalizar tu entorno shell.
Los medios más básicos de personalización que proporciona el shell Korn son estos:
Los medios más básicos de personalización que proporciona el shell de Korn son estos:
\begin{description}
\item[Alias:] Sinónimos de comandos o cadenas de comandos que puede definir para mayor comodidad.
\item[Opciones:] Controles para varios aspectos de tu entorno, que puedes activar y desactivar.
@ -15,10 +15,10 @@ Los medios más básicos de personalización que proporciona el shell Korn son e
También hay formas más complejas de personalizar tu entorno, principalmente la capacidad de programar el shell, que veremos en capítulos posteriores. En este capítulo, cubrimos las técnicas listadas arriba.
Mientras que la mayoría de las personalizaciones obtenibles con las técnicas anteriores son sencillas y se aplican al uso diario de Unix, otras son más bien arcanas y requieren un profundo conocimiento técnico para entenderlas. La mayor parte de este capítulo se concentra en las primeras. Debido a que queremos explicar las cosas desde la perspectiva de las tareas que puede querer realizar, más que desde la de las características específicas del shell Korn, puede que se nos escapen algunos pequeños detalles (como opciones varias para ciertos comandos). Le sugerimos que busque este tipo de información en el Apéndice B.
Mientras que la mayoría de las personalizaciones obtenibles con las técnicas anteriores son sencillas y se aplican al uso diario de Unix, otras son más bien arcanas y requieren un profundo conocimiento técnico para entenderlas. La mayor parte de este capítulo se concentra en las primeras. Debido a que queremos explicar las cosas desde la perspectiva de las tareas que puede querer realizar, más que desde la de las características específicas del shell de Korn, puede que se nos escapen algunos pequeños detalles (como opciones varias para ciertos comandos). Le sugerimos que busque este tipo de información en el Apéndice B.
\section{El Archivo .profile}
Si quieres personalizar tu entorno, lo más importante es que conozcas un fichero llamado \emph{.profile} en tu directorio home (login). Este es un archivo de comandos de shell, también llamado script de shell, que el shell Korn lee y ejecuta cada vez que inicias sesión en tu sistema.
Si quieres personalizar tu entorno, lo más importante es que conozcas un fichero llamado \emph{.profile} en tu directorio home (login). Este es un archivo de comandos de shell, también llamado script de shell, que el shell de Korn lee y ejecuta cada vez que inicias sesión en tu sistema.
Si utilizas una máquina grande en una oficina o departamento, lo más probable es que el administrador del sistema ya haya configurado un fichero \emph{.profile} para ti que contiene algunas cosas estándar. Este es uno de los ficheros <<ocultos>> mencionados en el \hyperref[sec:Chapter1]{Capítulo 1}; otros ficheros ocultos comunes son \emph{.xinitrc} (para el sistema X Window), \emph{.emacs} (para el editor GNU Emacs) y \emph{.mailrc} (para el programa de correo de Unix).
@ -39,18 +39,18 @@ Estos comandos configuran un entorno básico para ti, así que probablemente no
\subsection{El Archivo \texttt{/etc/profile}}
Cada usuario tiene un archivo \emph{.profile} personal en el directorio home. Aunque es posible que el administrador del sistema le haya proporcionado un archivo \emph{.profile} inicial cuando se configuró su cuenta por primera vez, usted es libre de personalizarlo como considere oportuno.
Existe un archivo de personalización adicional, para todo el sistema, conocido como \emph{/etc/profile}. Si este archivo existe, el shell Korn lo lee y ejecuta como la primera cosa que hace, incluso antes de leer su archivo personal \emph{.profile}. Aquí es donde el administrador del sistema coloca los comandos que deben ser ejecutados por cada usuario al iniciar sesión, y donde él o ella coloca los valores por defecto de todo el sistema, tales como añadir directorios adicionales a la variable \texttt{PATH} (que, como verá más adelante en este capítulo, le dice al shell dónde buscar programas para ejecutar).
Existe un archivo de personalización adicional, para todo el sistema, conocido como \emph{/etc/profile}. Si este archivo existe, el shell de Korn lo lee y ejecuta como la primera cosa que hace, incluso antes de leer su archivo personal \emph{.profile}. Aquí es donde el administrador del sistema coloca los comandos que deben ser ejecutados por cada usuario al iniciar sesión, y donde él o ella coloca los valores por defecto de todo el sistema, tales como añadir directorios adicionales a la variable \texttt{PATH} (que, como verá más adelante en este capítulo, le dice al shell dónde buscar programas para ejecutar).
ale la pena estar al tanto de este archivo, ya que puede contener configuraciones que usted podría desear anular en su propio archivo \emph{.profile}. (Si el archivo existe, será legible y contendrá comandos de shell, al igual que su \emph{.profile}. Puede valer la pena examinar la versión en su sistema; puede aprender algo de esa manera.
Vale la pena estar al tanto de este archivo, ya que puede contener configuraciones que usted podría desear anular en su propio archivo \emph{.profile}. (Si el archivo existe, será legible y contendrá comandos de shell, al igual que su \emph{.profile}. Puede valer la pena examinar la versión en su sistema; puede aprender algo de esa manera.
\section{Alias}
Quizás el tipo de personalización más fácil y popular es el \emph{alias}, que es un sinónimo de un comando o cadena de comandos. Esta es una de varias características del shell Korn que fueron apropiadas del shell C.\footnote{Los usuarios del shell C deberían tener en cuenta que la característica alias del shell Korn no soporta argumentos en las expansiones de alias, como hacen los alias del shell C.} Usted define un alias introduciendo (o añadiendo a su \emph{.profile}) una línea con la siguiente forma:
Quizás el tipo de personalización más fácil y popular es el \emph{alias}, que es un sinónimo de un comando o cadena de comandos. Esta es una de varias características del shell de Korn que fueron apropiadas del shell C.\footnote{Los usuarios del shell C deberían tener en cuenta que la característica alias del shell de Korn no soporta argumentos en las expansiones de alias, como hacen los alias del shell C.} Usted define un alias introduciendo (o añadiendo a su \emph{.profile}) una línea con la siguiente forma:
\begin{lstlisting}[language=bash]
alias new=original
\end{lstlisting}
(Observe que no hay espacios a ambos lados del signo igual (=); es la sintaxis requerida). El comando \emph{alias} define \emph{new} como un alias de \emph{original}; cada vez que escriba \emph{new}, el shell Korn sustituirá internamente a \emph{original}. (No puede utilizar ninguno de los caracteres especiales del shell, como *, \$, =, etc., en los nombres de alias).
(Observe que no hay espacios a ambos lados del signo igual (=); es la sintaxis requerida). El comando \emph{alias} define \emph{new} como un alias de \emph{original}; cada vez que escriba \emph{new}, el shell de Korn sustituirá internamente a \emph{original}. (No puede utilizar ninguno de los caracteres especiales del shell, como *, \$, =, etc., en los nombres de alias).
Existen varias formas básicas de utilizar un alias. La primera, y más sencilla, es utilizar un nombre más mnemotécnico para una orden existente. Muchos comandos Unix de uso común tienen nombres que son mnemotécnicos pobres y por lo tanto son excelentes candidatos para alias; el ejemplo clásico es:
@ -58,7 +58,7 @@ Existen varias formas básicas de utilizar un alias. La primera, y más sencilla
alias search=grep
\end{lstlisting}
\emph{grep}, la utilidad de búsqueda de archivos de Unix, deriva su nombre del comando <<g/re/p>> del editor de texto \emph{ed} original, que hace esencialmente lo mismo que grep. (El código de búsqueda de expresiones regulares se eliminó de ed para crear un programa independiente).\footnote{Gracias a Dennis Ritchie y Brian Kernighan, de los laboratorios Bell, por verificarlo. ADR.} Este acrónimo puede significar algo para un informático, pero probablemente no para el administrador de una oficina que tiene que encontrar a \texttt{Fred} en una lista de números de teléfono. Si tiene que encontrar a \texttt{Fred}, y tiene la palabra \emph{search} definida como alias de \emph{grep}, puede escribir:
\emph{grep}, la utilidad de búsqueda de archivos de Unix, deriva su nombre del comando <<g/re/p>> del editor de texto \emph{ed} original, que hace esencialmente lo mismo que \emph{grep}. (El código de búsqueda de expresiones regulares se eliminó de \emph{ed} para crear un programa independiente).\footnote{Gracias a Dennis Ritchie y Brian Kernighan, de los laboratorios Bell, por verificarlo. ADR.} Este acrónimo puede significar algo para un informático, pero probablemente no para el administrador de una oficina que tiene que encontrar a \texttt{Fred} en una lista de números de teléfono. Si tiene que encontrar a \texttt{Fred}, y tiene la palabra \emph{search} definida como alias de \emph{grep}, puede escribir:
\begin{lstlisting}[language=bash]
search Fred phonelist
@ -70,7 +70,7 @@ Otro alias popular evita \emph{exit} en favor de un comando más utilizado para
alias logout=exit
\end{lstlisting}
Si eres un usuario del shell C, puede que estés acostumbrado a tener un fichero \emph{.logout} de comandos que el shell ejecuta justo antes de cerrar la sesión. El shell Korn no tiene esta característica como tal, pero puedes imitarla fácilmente usando un alias:
Si eres un usuario del shell C, puede que estés acostumbrado a tener un fichero \emph{.logout} de comandos que el shell ejecuta justo antes de cerrar la sesión. El shell de Korn no tiene esta característica como tal, pero puedes imitarla fácilmente usando un alias:
\begin{lstlisting}[language=bash]
alias logout='. ~/.ksh\_logout; exit'
@ -108,7 +108,7 @@ Por ejemplo, una opción útil del comando \emph{ls} es \emph{-F}: pone una barr
alias lf='ls -F'
\end{lstlisting}
Es importante recordar algunas cosas sobre los alias. En primer lugar, el shell Korn hace una sustitución textual del alias por aquello a lo que está poniendo el alias; puede ayudar imaginarse a ksh pasando su comando a través de un editor de texto o procesador de textos y emitiendo un comando <<change>> o <<substitute>> antes de interpretarlo y ejecutarlo.
Es importante recordar algunas cosas sobre los alias. En primer lugar, el shell de Korn hace una sustitución textual del alias por aquello a lo que está poniendo el alias; puede ayudar imaginarse a \emph{ksh} pasando su comando a través de un editor de texto o procesador de textos y emitiendo un comando <<change>> o <<substitute>> antes de interpretarlo y ejecutarlo.
Esto, a su vez, significa que cualquier carácter especial (como comodines como * y ?) que resulten cuando se expande el alias son interpretados correctamente por el shell. Esto lleva a un corolario importante: los comodines y otros caracteres especiales no pueden utilizarse en los nombres de los alias, es decir, a la izquierda del signo igual. Por ejemplo, para facilitar la impresión de todos los archivos de su directorio, podría definir el alias:
@ -128,7 +128,7 @@ El alias recursivo hace posible establecer un <<bucle infinito>> de definiciones
alias ls='ls -l'
\end{lstlisting}
crea un posible bucle infinito. Por suerte, el shell tiene un mecanismo para protegerse de estos peligros. El comando anterior funciona como se espera (al teclear ls se obtiene una larga lista con permisos, tamaños, propietarios, etc.). Incluso funcionan situaciones más patológicas, como éstas:
crea un posible bucle infinito. Por suerte, el shell tiene un mecanismo para protegerse de estos peligros. El comando anterior funciona como se espera (al teclear \emph{ls} se obtiene una larga lista con permisos, tamaños, propietarios, etc.). Incluso funcionan situaciones más patológicas, como éstas:
\begin{lstlisting}[language=bash]
alias listfile=ls
@ -137,15 +137,15 @@ alias ls=listfile
Si escribes \emph{listfile}, ls se ejecuta.
Los alias sólo pueden utilizarse al principio de una cadena de comandos, aunque con algunas excepciones. En el ejemplo anterior de cd, es posible que desee definir un alias sólo para el nombre del directorio, no para todo el comando. Pero si define:
Los alias sólo pueden utilizarse al principio de una cadena de comandos, aunque con algunas excepciones. En el ejemplo anterior de \emph{cd}, es posible que desee definir un alias sólo para el nombre del directorio, no para todo el comando. Pero si define:
\begin{lstlisting}[language=bash]
alias cm=work/projects/devtools/windows/confman
\end{lstlisting}
y luego escriba \texttt{cd cm}, el shell Korn probablemente imprimirá un mensaje como \texttt{ksh: cd: cm: [No such file or directory]}.
y luego escriba \texttt{cd cm}, el shell de Korn probablemente imprimirá un mensaje como \texttt{ksh: cd: cm: [No such file or directory]}.
Una característica oscura y bastante fea de la facilidad de alias del shell Korn -- que no está presente en la característica análoga del shell C -- proporciona una forma de evitar este problema. Si el valor de un alias (el lado derecho del signo igual) termina en un espacio o en un tabulador, entonces el shell Korn intenta hacer la sustitución del alias en la siguiente palabra de la línea de órdenes. Para hacer que el valor de un alias termine en un espacio, debe rodearlo con comillas.
Una característica oscura y bastante fea de la facilidad de alias del shell de Korn -- que no está presente en la característica análoga del shell C -- proporciona una forma de evitar este problema. Si el valor de un alias (el lado derecho del signo igual) termina en un espacio o en un tabulador, entonces el shell de Korn intenta hacer la sustitución del alias en la siguiente palabra de la línea de órdenes. Para hacer que el valor de un alias termine en un espacio, debe rodearlo con comillas.
Esta característica existe para que sea posible tener alias para comandos que a su vez ejecutan otros comandos, como \emph{nohup} y \emph{nice}. Por ejemplo, \emph{nohup} tiene el alias \texttt{'nohup '}. De esta forma, cuando escribes
@ -161,9 +161,9 @@ A continuación se muestra cómo utilizar esta capacidad para permitir alias par
alias cd='cd '
\end{lstlisting}
Esto hace que el shell Korn busque un alias para el argumento de nombre de directorio a \emph{cd}, que en el ejemplo anterior le permitiría expandir el alias \emph{cm} correctamente.
Esto hace que el shell de Korn busque un alias para el argumento de nombre de directorio a \emph{cd}, que en el ejemplo anterior le permitiría expandir el alias \emph{cm} correctamente.
El shell Korn proporciona una característica de eficiencia llamada <<alias rastreados>>. Retrasaremos la discusión de estos hasta la Sección 3.4.2.8. Además, varios alias están predefinidos por el shell; están listados en el Apéndice B.
El shell de Korn proporciona una característica de eficiencia llamada <<alias rastreados>>. Retrasaremos la discusión de estos hasta la Sección 3.4.2.8. Además, varios alias están predefinidos por el shell; están listados en el Apéndice B.
Por último, existen algunos complementos útiles para el comando \emph{alias} básico. Si escribe \texttt{alias name} sin un signo igual (=) y value, el shell imprime el valor del alias o \emph{name:} \texttt{alias not found} si no está definido. Si escribe \emph{alias} sin ningún argumento, obtendrá una lista de todos los alias que haya definido, así como de varios que están incorporados. Si escribe \texttt{alias -p}, el shell imprime todos sus alias, con cada uno precedido por la palabra clave \emph{alias}. Esto es útil para guardar todos sus alias de forma que el shell pueda volver a leerlos en otro momento. El comando \texttt{unalias} \emph{name} elimina cualquier definición de alias para su argumento. Si escribe \texttt{unalias -a}, el shell elimina todos los alias.
@ -174,7 +174,7 @@ Aunque los alias le permiten crear nombres convenientes para los comandos, en re
Los comandos básicos relacionados con las opciones son \emph{set -o optionnames} y \emph{set +o optionnames}, donde \emph{optionnames} es una lista de nombres de opciones separados por espacios en blanco. El uso de los signos más (+) y menos (-) es contradictorio: el - activa la opción nombrada, mientras que el + la desactiva. La razón de esta incongruencia es que el guión (-) es la forma convencional de Unix de especificar opciones a un comando, mientras que el uso de + es una ocurrencia posterior.
La mayoría de las opciones también tienen abreviaturas de una letra que pueden utilizarse en lugar del comando \emph{set -o}; por ejemplo, \emph{set -o noglob} puede abreviarse \emph{set -f}. Estas abreviaturas provienen del shell Bourne. Al igual que otras características <<extra>> del shell Korn, existen para asegurar la compatibilidad; de lo contrario, no se recomienda su uso.
La mayoría de las opciones también tienen abreviaturas de una letra que pueden utilizarse en lugar del comando \emph{set -o}; por ejemplo, \emph{set -o noglob} puede abreviarse \emph{set -f}. Estas abreviaturas provienen del shell de Bourne. Al igual que otras características <<extra>> del shell de Korn, existen para asegurar la compatibilidad; de lo contrario, no se recomienda su uso.
\newpage
@ -191,14 +191,14 @@ La Tabla \ref{tab3.1} lista las opciones que son útiles para los usuarios gener
\emph{ignoreeof} & No permitir el uso de CTRL-D para cerrar la sesión; requerir el comando exit. \\\hline
\emph{markdirs} & Al expandir los comodines de nombre de archivo, añada una barra (/) a los directorios. \\\hline
\emph{noclobber} & No permita que la redirección de salida (>) destruya un archivo existente. \\\hline
\emph{noglob} & No expanda los comodines de nombre de archivo como * y ? (la expansión de comodines a veces se denomina globbing). \\\hline
\emph{noglob} & No expanda los comodines de nombre de archivo como * y ? (la expansión de comodines a veces se denomina \emph{globbing}). \\\hline
\emph{nounset} & Indicar un error al intentar utilizar una variable que no está definida. \\\hline
\emph{trackall} & Activar el seguimiento de alias. (En realidad, el shell ignora la configuración de esta opción; el seguimiento de alias siempre está activado. Esto se discute en la Sección 3.4.2.8, más adelante en este capítulo). \\\hline
\emph{vi} & Entra en el modo de edición vi. \\\hline
\end{tabular}
\end{table}
Existen otras opciones (22 en total; el Apéndice B las enumera). Para comprobar el estado de una opción, escriba \emph{set -o}. El shell Korn imprime una lista de todas las opciones junto con su configuración. No existe un comando para probar opciones individuales, pero aquí hay una simple función del shell para hacerlo:
Existen otras opciones (22 en total; el Apéndice B las enumera). Para comprobar el estado de una opción, escriba \emph{set -o}. El shell de Korn imprime una lista de todas las opciones junto con su configuración. No existe un comando para probar opciones individuales, pero aquí hay una simple función del shell para hacerlo:
\begin{lstlisting}[language=bash]
function testopt {
@ -215,7 +215,7 @@ Las funciones de shell se tratan en el próximo capítulo. Por ahora, sin embarg
\section{Variables de Shell}
Hay varias características de su entorno que puede que desee personalizar pero que no pueden expresarse como una opción on/off. Las características de este tipo se especifican en variables de shell. Las variables de shell pueden especificarlo todo, desde la cadena del prompt hasta la frecuencia con la que el shell comprueba si hay correo nuevo.
Al igual que un alias, una variable de shell es un nombre que tiene un valor asociado. El shell Korn mantiene un registro de varias variables del shell incorporadas; los programadores del shell pueden añadir las suyas propias. Por convención, las variables incorporadas tienen nombres en mayúsculas. La sintaxis para definir variables es similar a la sintaxis para alias:
Al igual que un alias, una variable de shell es un nombre que tiene un valor asociado. El shell de Korn mantiene un registro de varias variables del shell incorporadas; los programadores del shell pueden añadir las suyas propias. Por convención, las variables incorporadas tienen nombres en mayúsculas. La sintaxis para definir variables es similar a la sintaxis para alias:
\begin{lstlisting}[language=bash]
varname=value
@ -223,9 +223,9 @@ varname=value
No debe haber ningún espacio a ambos lados del signo igual, y si el valor tiene más de una palabra, debe ir entre comillas. Para utilizar el valor de una variable en un comando, preceda su nombre con un signo de dólar (\$).
Puede eliminar una variable con el comando \texttt{unset varname}. Normalmente, esto no es útil, ya que se supone que todas las variables que no existen son nulas, es decir, iguales a la cadena vacía ''''. Pero si utiliza la opción \texttt{nounset} (véase la Tabla 3-1), que hace que el shell indique un error cuando encuentra una variable indefinida, puede interesarle unset.
Puede eliminar una variable con el comando \texttt{unset varname}. Normalmente, esto no es útil, ya que se supone que todas las variables que no existen son nulas, es decir, iguales a la cadena vacía ''''. Pero si utiliza la opción \texttt{nounset} (véase la Tabla \ref{tab3.1}), que hace que el shell indique un error cuando encuentra una variable indefinida, puede interesarle unset.
La forma más sencilla de comprobar el valor de una variable es utilizar el comando integrado \texttt{print}\footnote{El shell Korn soporta el antiguo comando \texttt{echo}, que hace prácticamente lo mismo, por razones de compatibilidad con versiones anteriores. Sin embargo, recomendamos encarecidamente \texttt{print} porque sus opciones son las mismas en todos los sistemas Unix, mientras que las opciones de \texttt{echo} difieren entre las diferentes versiones de Unix. No es probable que esto cambie; el estándar POSIX dice que las opciones de \texttt{echo} están definidas por la implementación.}. Todo lo que hace \texttt{print} es imprimir sus argumentos, pero no hasta que el shell los haya evaluado. Esto incluye -- entre otras cosas que se discutirán más adelante -- tomar los valores de las variables y expandir los comodines de nombre de archivo. Así, si la variable \emph{fred} tiene el valor \texttt{bob}, escribir lo siguiente hace que el shell simplemente imprima \texttt{bob}:
La forma más sencilla de comprobar el valor de una variable es utilizar el comando integrado \texttt{print}\footnote{El shell de Korn soporta el antiguo comando \texttt{echo}, que hace prácticamente lo mismo, por razones de compatibilidad con versiones anteriores. Sin embargo, recomendamos encarecidamente \texttt{print} porque sus opciones son las mismas en todos los sistemas Unix, mientras que las opciones de \texttt{echo} difieren entre las diferentes versiones de Unix. No es probable que esto cambie; el estándar POSIX dice que las opciones de \texttt{echo} están definidas por la implementación.}. Todo lo que hace \texttt{print} es imprimir sus argumentos, pero no hasta que el shell los haya evaluado. Esto incluye -- entre otras cosas que se discutirán más adelante -- tomar los valores de las variables y expandir los comodines de nombre de archivo. Así, si la variable \emph{fred} tiene el valor \texttt{bob}, escribir lo siguiente hace que el shell simplemente imprima \texttt{bob}:
\begin{lstlisting}[language=bash]
print "$fred"
@ -246,7 +246,7 @@ The value of $fred is "bob".
\subsection{Variables y Citas}
Fíjese en que hemos utilizado comillas dobles alrededor de las variables (y de las cadenas que las contienen) en estos ejemplos de \emph{impresión}. En el \hyperref[sec:Chapter1]{Capítulo 1} dijimos que algunos caracteres especiales entre comillas dobles se interpretan (mientras que ninguno se interpreta entre comillas simples).
Quizás el carácter especial más importante que <<sobrevive>> a las comillas dobles es el signo del dólar, que significa que las variables se evalúan. Es posible prescindir de las comillas dobles en algunos casos; por ejemplo, podríamos haber escrito la orden print anterior de esta forma:
Quizás el carácter especial más importante que <<sobrevive>> a las comillas dobles es el signo del dólar, que significa que las variables se evalúan. Es posible prescindir de las comillas dobles en algunos casos; por ejemplo, podríamos haber escrito la orden \emph{print} anterior de esta forma:
\begin{lstlisting}[language=bash]
print The value of \$varname is \"$varname\".
@ -284,7 +284,7 @@ Al igual que con las opciones, algunas variables incorporadas al shell son signi
\subsubsection{Edición de Variables de Modo}
Varias variables del shell se relacionan con los modos de edición de la línea de comandos que vimos en el capítulo anterior. Éstas se enumeran en la Tabla \ref{tab3.2}.
Las dos primeras son usadas a veces por editores de texto y otros programas orientados a pantalla, que dependen de que las variables estén configuradas correctamente. Aunque el shell Korn y la mayoría de los sistemas de ventanas deberían saber cómo establecerlas correctamente, debería mirar los valores de \texttt{COLUMNS} y \texttt{LINES} si tiene problemas de visualización con un programa orientado a pantalla.
Las dos primeras son usadas a veces por editores de texto y otros programas orientados a pantalla, que dependen de que las variables estén configuradas correctamente. Aunque el shell de Korn y la mayoría de los sistemas de ventanas deberían saber cómo establecerlas correctamente, debería mirar los valores de \texttt{COLUMNS} y \texttt{LINES} si tiene problemas de visualización con un programa orientado a pantalla.
\begin{table}[h]
\center
@ -302,7 +302,7 @@ Las dos primeras son usadas a veces por editores de texto y otros programas orie
\end{table}
\subsubsection{Variables de Correo}
Dado que el programa de correo no se ejecuta todo el tiempo, no hay forma de que le informe cuando recibe correo nuevo; por lo tanto, el intérprete de órdenes hace esto en su lugar\footnote{El comúnmente disponible comando \emph{biff} hace un mejor trabajo en este sentido; mientras que el shell Korn sólo imprime mensajes de <<tiene correo>> justo antes de imprimir las indicaciones de comandos, \emph{biff} puede decirle de quién es el correo.}. El intérprete de órdenes no puede comprobar realmente si hay correo entrante, pero puede mirar su fichero de correo periódicamente y determinar si el fichero ha sido modificado desde la última comprobación. Las variables listadas en la Tabla \ref{tab3.3} le permiten controlar cómo funciona esto.
Dado que el programa de correo no se ejecuta todo el tiempo, no hay forma de que le informe cuando recibe correo nuevo; por lo tanto, el intérprete de órdenes hace esto en su lugar\footnote{El comúnmente disponible comando \emph{biff} hace un mejor trabajo en este sentido; mientras que el shell de Korn sólo imprime mensajes de <<tiene correo>> justo antes de imprimir las indicaciones de comandos, \emph{biff} puede decirle de quién es el correo.}. El intérprete de órdenes no puede comprobar realmente si hay correo entrante, pero puede mirar su fichero de correo periódicamente y determinar si el fichero ha sido modificado desde la última comprobación. Las variables listadas en la Tabla \ref{tab3.3} le permiten controlar cómo funciona esto.
\begin{table}[h]
\center
@ -325,7 +325,7 @@ MAIL=/var/mail/yourname
Si su administrador del sistema no lo ha hecho ya por usted, ponga una línea como ésta en su \emph{.profile}.
Sin embargo, algunas personas utilizan mailers no estándar que usan múltiples ficheros de correo; \texttt{MAILPATH} fue diseñado para acomodar esto. El shell Korn utiliza el valor de \texttt{MAIL} como el nombre del fichero a comprobar, a menos que se establezca \texttt{MAILPATH}, en cuyo caso el shell comprueba cada fichero de la lista \texttt{MAILPATH} en busca de correo nuevo. Puede utilizar este mecanismo para que el shell imprima un mensaje diferente para cada archivo de correo: para cada nombre de archivo de correo en \texttt{MAILPATH}, añada un signo de interrogación seguido del mensaje que desea imprimir.
Sin embargo, algunas personas utilizan \emph{mailers} no estándar que usan múltiples ficheros de correo; \texttt{MAILPATH} fue diseñado para acomodar esto. El shell de Korn utiliza el valor de \texttt{MAIL} como el nombre del fichero a comprobar, a menos que se establezca \texttt{MAILPATH}, en cuyo caso el shell comprueba cada fichero de la lista \texttt{MAILPATH} en busca de correo nuevo. Puede utilizar este mecanismo para que el shell imprima un mensaje diferente para cada archivo de correo: para cada nombre de archivo de correo en \texttt{MAILPATH}, añada un signo de interrogación seguido del mensaje que desea imprimir.
Por ejemplo, supongamos que tienes un sistema de correo que ordena automáticamente el correo en archivos según el nombre de usuario del remitente. Tiene archivos de correo llamados \emph{/var/mail/usted/fritchie}, \emph{/var/mail/usted/droberts}, \emph{/var/mail/usted/jphelps}, etc. Usted define su \texttt{MAILPATH} como sigue:
@ -334,7 +334,7 @@ MAILPATH=/var/mail/you/fritchie:/var/mail/you/droberts:\
/var/mail/you/jphelps
\end{lstlisting}
Si recibe correo de Jennifer Phelps, el archivo \emph{/var/mail/you/jphelps} cambia. El shell Korn se da cuenta del cambio en 10 minutos e imprime el mensaje:
Si recibe correo de Jennifer Phelps, el archivo \emph{/var/mail/you/jphelps} cambia. El shell de Korn se da cuenta del cambio en 10 minutos e imprime el mensaje:
\begin{lstlisting}[language=bash]
you have mail in /var/mail/you/jphelps.
@ -399,13 +399,13 @@ _ is /tmp/junk
\subsubsection{Variables de prompt}
Si has visto trabajar a suficientes usuarios experimentados de Unix, puede que ya te hayas dado cuenta de que el prompt del shell no está grabado en piedra. Parece que uno de los pasatiempos favoritos de los programadores profesionales de Unix es pensar en cadenas de prompt bonitas o innovadoras. Te daremos algo de la información que necesitas para hacer la tuya aquí; el resto viene en el próximo capítulo.
En realidad, el shell Korn utiliza cuatro cadenas de prompt. Se almacenan en las variables \texttt{PS1}, \texttt{PS2}, \texttt{PS3} y \texttt{PS4}. La primera de ellas se llama prompt primario; es el prompt habitual del shell, y su valor por defecto es \texttt{"\$ "} (un signo de dólar seguido de un espacio). A mucha gente le gusta establecer su prompt primario a algo que contenga su nombre de usuario. Esta es una forma de hacerlo:
En realidad, el shell de Korn utiliza cuatro cadenas de prompt. Se almacenan en las variables \texttt{PS1}, \texttt{PS2}, \texttt{PS3} y \texttt{PS4}. La primera de ellas se llama prompt primario; es el prompt habitual del shell, y su valor por defecto es \texttt{"\$ "} (un signo de dólar seguido de un espacio). A mucha gente le gusta establecer su prompt primario a algo que contenga su nombre de usuario. Esta es una forma de hacerlo:
\begin{lstlisting}[language=bash]
PS1="($LOGNAME)-> "
\end{lstlisting}
\texttt{LOGNAME} es otra variable incorporada en el shell, que se establece con tu nombre de usuario cuando te conectas\footnote{Algunos sistemas muy antiguos utilizan \texttt{USER} en su lugar. Afortunadamente, estos sistemas son cada vez más raros.}. Así, \texttt{PS1} se convierte en un paréntesis a la izquierda, seguido de tu nombre de usuario, seguido de \texttt{")-> "}. Si su nombre de usuario es fred, su prompt será \texttt{"(fred)-> "}.Si usted es un usuario del shell C y, como muchas de esas personas, está acostumbrado a tener un número de comando en su prompt string, el shell Korn puede hacer esto de forma similar al shell C: si hay un signo de exclamación en la prompt string, sustituye el número de comando. Así, si define su cadena de comandos como la siguiente, sus comandos se verán como \texttt{(fred 1)->}, \texttt{(fred 2)->} , y así sucesivamente:
\texttt{LOGNAME} es otra variable incorporada en el shell, que se establece con tu nombre de usuario cuando te conectas\footnote{Algunos sistemas muy antiguos utilizan \texttt{USER} en su lugar. Afortunadamente, estos sistemas son cada vez más raros.}. Así, \texttt{PS1} se convierte en un paréntesis a la izquierda, seguido de tu nombre de usuario, seguido de \texttt{")-> "}. Si su nombre de usuario es fred, su prompt será \texttt{"(fred)-> "}.Si usted es un usuario del shell C y, como muchas de esas personas, está acostumbrado a tener un número de comando en su cadena del prompt, el shell de Korn puede hacer esto de forma similar al shell C: si hay un signo de exclamación en la cadena del prompt, sustituye el número de comando. Así, si define su cadena de comandos como la siguiente, sus comandos se verán como \texttt{(fred 1)->}, \texttt{(fred 2)->} , y así sucesivamente:
\begin{lstlisting}[language=bash]
PS1="($LOGNAME !)->"
@ -485,14 +485,14 @@ Si no tiene éxito, \emph{ls} no imprimirá nada, y tendrá que hacer otra supos
Por el contrario, \emph{terminfo} puede tener varias entradas relacionadas con su terminal, para submodelos, modos especiales, etc. Si puede elegir qué entrada utilizar como valor de \texttt{TERM}, le sugerimos que pruebe cada una de ellas con su editor de texto o cualquier otro programa orientado a pantalla que utilice y vea cuál funciona mejor.
El proceso es mucho más sencillo si estás utilizando un sistema de ventanas, en el que tus <<terminales>> son porciones lógicas de la pantalla en lugar de dispositivos físicos. En este caso, el software dependiente del sistema operativo fue escrito para controlar su(s) ventana(s) de terminal, por lo que las probabilidades son muy buenas de que si sabe cómo manejar el cambio de tamaño de la ventana y el complejo movimiento del cursor, sea capaz de lidiar con cosas simples como \texttt{TERM}. El sistema X Window, por ejemplo, establece automáticamente <<xterm>> como valor para \texttt{TERM} en una ventana de terminal xterm.
El proceso es mucho más sencillo si estás utilizando un sistema de ventanas, en el que tus <<terminales>> son porciones lógicas de la pantalla en lugar de dispositivos físicos. En este caso, el software dependiente del sistema operativo fue escrito para controlar su(s) ventana(s) de terminal, por lo que las probabilidades son muy buenas de que si sabe cómo manejar el cambio de tamaño de la ventana y el complejo movimiento del cursor, sea capaz de lidiar con cosas simples como \texttt{TERM}. El sistema X Window, por ejemplo, establece automáticamente <<xterm>> como valor para \texttt{TERM} en una ventana de terminal \emph{xterm}.
\subsubsection{Ruta de Búsqueda de Comandos}
Otra variable importante es \texttt{PATH}, que ayuda al shell a encontrar los comandos que introduzcas.
Como probablemente sepas, cada comando que utilizas es en realidad un archivo que contiene código para que tu máquina lo ejecute.\footnote{A menos que sea un comando incorporado (como \emph{cd} y \emph{print}), en cuyo caso el código es simplemente parte del archivo ejecutable para todo el shell.} Estos archivos se denominan archivos ejecutables o simplemente ejecutables. Se almacenan en varios directorios. Algunos directorios, como \emph{/bin} o \emph{/usr/bin}, son estándar en todos los sistemas Unix; otros dependen de la versión concreta de Unix que estés utilizando; algunos son exclusivos de tu máquina; si eres programador, algunos pueden ser incluso tuyos. En cualquier caso, no hay ninguna razón por la que debas saber dónde está el archivo ejecutable de un comando para poder ejecutarlo.
Aquí es donde entra \texttt{PATH}. Su valor es una lista de directorios que el shell busca cada vez que usted introduce un nombre de comando que no contiene una barra; los nombres de directorio están separados por dos puntos (:), igual que los archivos en \texttt{MAILPATH}. Por ejemplo, si escribe print \texttt{\$PATH}, verá algo como esto:
Aquí es donde entra \texttt{PATH}. Su valor es una lista de directorios que el shell busca cada vez que usted introduce un nombre de comando que no contiene una barra; los nombres de directorio están separados por dos puntos (:), igual que los archivos en \texttt{MAILPATH}. Por ejemplo, si escribe \texttt{print \$PATH}, verá algo como esto:
\begin{lstlisting}[language=bash]
/sbin:/usr/sbin:/usr/bin:/etc:/usr/X11R6/bin:/local/bin
@ -512,7 +512,7 @@ Hay un detalle adicional importante que hay que entender sobre cómo funciona el
\begin{lstlisting}[language=bash]
PATH=:$HOME/bin:/usr/bin:/usr/local/bin # Buscar primero en el directorio actual
PATH=$HOME/bin:/usr/bin:/usr/local/bin: # Ultima busqueda en el directorio actual
PATH=$HOME/bin:/usr/bin:/usr/local/bin: # Ultima búsqueda en el directorio actual
PATH=$HOME/bin::/usr/bin:/usr/local/bin # Segunda busqueda en el directorio actual
\end{lstlisting}
@ -545,21 +545,21 @@ El uso apropiado de \texttt{PATH} es sólo uno de los muchos aspectos de la segu
\subsubsection{PATH y Alias Rastreados}
Vale la pena señalar que una búsqueda a través de los directorios en su \texttt{PATH} puede tomar tiempo. No morirá exactamente si aguanta la respiración durante el tiempo que la mayoría de los ordenadores tardan en buscar en su \texttt{PATH}, pero el gran número de operaciones de E/S de disco implicadas en algunas búsquedas en el \texttt{PATH} pueden llevar más tiempo que el que tarda en ejecutarse el comando invocado.
El shell Korn proporciona una forma de eludir las búsquedas \texttt{PATH}, llamada alias rastreado. En primer lugar, observe que si especifica un comando indicando su ruta completa, el intérprete de órdenes ni siquiera utilizará su \texttt{PATH}, sino que irá directamente al archivo ejecutable. Los alias rastreados hacen esto automáticamente. La primera vez que invocas un comando, el shell busca el ejecutable de la forma normal (a través de \texttt{PATH}). A continuación, crea un alias para la ruta completa, de modo que la próxima vez que invoque el comando, el intérprete de comandos utilice la ruta completa y no se preocupe por el \texttt{PATH}. Si alguna vez cambias tu \texttt{PATH}, el shell marca los alias rastreados como <<indefinidos>>, de modo que vuelve a buscar las rutas completas cuando invoques los comandos correspondientes.
El shell de Korn proporciona una forma de eludir las búsquedas \texttt{PATH}, llamada alias rastreado. En primer lugar, observe que si especifica un comando indicando su ruta completa, el intérprete de órdenes ni siquiera utilizará su \texttt{PATH}, sino que irá directamente al archivo ejecutable. Los alias rastreados hacen esto automáticamente. La primera vez que invocas un comando, el shell busca el ejecutable de la forma normal (a través de \texttt{PATH}). A continuación, crea un alias para la ruta completa, de modo que la próxima vez que invoque el comando, el intérprete de comandos utilice la ruta completa y no se preocupe por el \texttt{PATH}. Si alguna vez cambias tu \texttt{PATH}, el shell marca los alias rastreados como <<indefinidos>>, de modo que vuelve a buscar las rutas completas cuando invoques los comandos correspondientes.
De hecho, puedes añadir alias rastreados con el único propósito de evitar la búsqueda en el \texttt{PATH} de comandos que utilizas con especial frecuencia. Sólo tienes que poner un <<alias trivial>> de la forma \texttt{alias -t command} en tu archivo \emph{.profile} o de entorno; el shell sustituye el nombre de ruta completo por sí mismo.
Por ejemplo, la primera vez que invocas emacs, el shell hace una búsqueda \texttt{PATH}. Al encontrar la ubicación de emacs (digamos \emph{/usr/local/bin/emacs}), el shell crea un alias rastreado:
Por ejemplo, la primera vez que invocas \emph{emacs}, el shell hace una búsqueda \texttt{PATH}. Al encontrar la ubicación de \emph{emacs} (digamos \emph{/usr/local/bin/emacs}), el shell crea un alias rastreado:
\begin{lstlisting}[language=bash]
alias -t emacs=/usr/local/bin/emacs # Alias de seguimiento automatico
\end{lstlisting}
La próxima vez que ejecute emacs, el intérprete de comandos expande el alias emacs en la ruta completa /usr/local/bin/emacs, y ejecuta el programa directamente, sin molestarse con una búsqueda PATH.
La próxima vez que ejecute \emph{emacs}, el intérprete de comandos expande el alias \emph{emacs} en la ruta completa /usr/local/bin/emacs, y ejecuta el programa directamente, sin molestarse con una búsqueda PATH.
También puede definir alias rastreados individuales usted mismo, con la opción \emph{-t} del comando alias, y puede listar todos esos alias rastreados escribiendo \texttt{alias -t} por sí mismo. (Por compatibilidad con el shell Bourne del Sistema V, ksh predefine el alias \texttt{hash='alias -t --'}; el comando hash en ese shell muestra la tabla interna de comandos encontrados. El mecanismo de alias rastreado del shell Korn es más flexible).
También puede definir alias rastreados individuales usted mismo, con la opción \emph{-t} del comando alias, y puede listar todos esos alias rastreados escribiendo \texttt{alias -t} por sí mismo. (Por compatibilidad con el shell de Bourne del Sistema V, \emph{ksh} predefine el alias \texttt{hash='alias -t --'}; el comando hash en ese shell muestra la tabla interna de comandos encontrados. El mecanismo de alias rastreado del shell de Korn es más flexible).
Aunque la documentación del shell y la opción trackall indican que puede activar y desactivar el rastreo de alias, el comportamiento real del shell es diferente: el rastreo de alias siempre está activado. \emph{alias -t} lista todos los alias rastreados creados automáticamente. Sin embargo, \emph{alias -p} no imprime los alias rastreados. Esto se debe a que, conceptualmente, los alias rastreados son sólo una mejora del rendimiento; en realidad no están relacionados con los alias que se definen para la personalización.
Aunque la documentación del shell y la opción \emph{trackall} indican que puede activar y desactivar el rastreo de alias, el comportamiento real del shell es diferente: el rastreo de alias siempre está activado. \emph{alias -t} lista todos los alias rastreados creados automáticamente. Sin embargo, \emph{alias -p} no imprime los alias rastreados. Esto se debe a que, conceptualmente, los alias rastreados son sólo una mejora del rendimiento; en realidad no están relacionados con los alias que se definen para la personalización.
\subsubsection{Ruta de Búsqueda de Directorios}
\texttt{CDPATH} es una variable cuyo valor, como el de \texttt{PATH}, es una lista de directorios separados por dos puntos. Su propósito es aumentar la funcionalidad del comando incorporado \emph{cd}.
@ -612,7 +612,7 @@ Esta dicotomía plantea una pregunta importante: ¿qué <<cosas>> del caparazón
La respuesta es bastante simple. Los subprocesos heredan solo variables de entorno. Están disponibles automáticamente, sin que el subproceso tenga que realizar ninguna acción explícita. Todas las demás <<cosas>> (opciones de shell, alias y funciones) deben estar explícitamente disponibles. El archivo de entorno es cómo se hace esto. Además, solo los shells interactivos procesan el archivo de entorno. Las siguientes dos secciones describen las variables de entorno y el archivo de entorno, respectivamente.
\subsection{Variables de Entorno}
Por defecto, sólo una clase de cosas es conocida por todas las clases de subprocesos: una clase especial de variables del shell llamadas variables de entorno. Algunas de las variables incorporadas que hemos visto son en realidad variables de entorno: HISTFILE, HOME, LOGNAME, PATH, PWD, OLDPWD, SHELL y TERM.
Por defecto, sólo una clase de cosas es conocida por todas las clases de subprocesos: una clase especial de variables del shell llamadas variables de entorno. Algunas de las variables incorporadas que hemos visto son en realidad variables de entorno: \texttt{HISTFILE, HOME, LOGNAME, PATH, PWD, OLDPWD, SHELL} y \texttt{TERM}.
Debería estar claro por qué estas y otras variables necesitan ser conocidas por los subprocesos. Ya hemos visto el ejemplo más obvio: los editores de texto como vi y Emacs necesitan saber qué tipo de terminal estás usando; \texttt{TERM} es su forma de determinarlo. Como otro ejemplo, la mayoría de los programas de correo de Unix le permiten editar un mensaje con su editor de texto favorito. ¿Cómo sabe \emph{mail} qué editor usar? El valor de \texttt{EDITOR} (o a veces \texttt{VISUAL}).
@ -636,7 +636,7 @@ También puedes definir variables para que estén sólo en el entorno de un subp
varname=value command
\end{lstlisting}
Puedes poner tantas asignaciones antes del comando como quieras.\footnote{Existe una oscura opción, \emph{keyword}, que (si está activada) te permite poner este tipo de definición de variable de entorno en cualquier parte de la línea de comandos, no sólo al principio.} Por ejemplo, supongamos que está utilizando el editor Emacs. Está teniendo problemas para que funcione con su terminal, así que está experimentando con diferentes valores de TERM. Usted puede hacer esto más fácilmente mediante la introducción de comandos que se parecen:
Puedes poner tantas asignaciones antes del comando como quieras.\footnote{Existe una oscura opción, \emph{keyword}, que (si está activada) te permite poner este tipo de definición de variable de entorno en cualquier parte de la línea de comandos, no sólo al principio.} Por ejemplo, supongamos que está utilizando el editor Emacs. Está teniendo problemas para que funcione con su terminal, así que está experimentando con diferentes valores de \emph{TERM}. Usted puede hacer esto más fácilmente mediante la introducción de comandos que se parecen:
\begin{lstlisting}[language=bash]
TERM=trythisone emacs filename
@ -652,9 +652,9 @@ SHELL=/bin/ksh
export EDITOR SHELL
\end{lstlisting}
Por alguna razón, el shell Korn no hace de \texttt{EDITOR} una variable de entorno por defecto. Esto significa, entre otras cosas, que mail no sabrá qué editor usar cuando quieras editar un mensaje.\footnote{En realidad, por defecto será el editor de líneas ed. No quieres eso, ¿verdad?} Por lo tanto, tendría que exportarlo usted mismo utilizando el comando \emph{export} en su \emph{.profile}.
Por alguna razón, el shell de Korn no hace de \texttt{EDITOR} una variable de entorno por defecto. Esto significa, entre otras cosas, que \emph{mail} no sabrá qué editor usar cuando quieras editar un mensaje.\footnote{En realidad, por defecto será el editor de líneas \emph{ed}. No quieres eso, ¿verdad?} Por lo tanto, tendría que exportarlo usted mismo utilizando el comando \emph{export} en su \emph{.profile}.
La segunda línea del código anterior está pensada para sistemas que no tienen el shell Korn instalado como shell por defecto, es decir, como \emph{/bin/sh}. Algunos programas ejecutan shells como subprocesos dentro de sí mismos (por ejemplo, muchos programas de correo y el modo shell del editor Emacs); por convención, utilizan la variable \texttt{SHELL} para determinar qué shell utilizar.
La segunda línea del código anterior está pensada para sistemas que no tienen el shell de Korn instalado como shell por defecto, es decir, como \emph{/bin/sh}. Algunos programas ejecutan shells como subprocesos dentro de sí mismos (por ejemplo, muchos programas de correo y el modo shell del editor Emacs); por convención, utilizan la variable \texttt{SHELL} para determinar qué shell utilizar.
Puede averiguar qué variables son de entorno y cuáles son sus valores escribiendo \emph{export} sin argumentos.
@ -672,14 +672,14 @@ export ENV
\end{lstlisting}
Es importante que el valor de \texttt{ENV} sea exportado, para que los subprocesos del shell puedan encontrarlo.}
\item{Para que los cambios surtan efecto inmediatamente, cierre la sesión y vuelva a iniciarla.\footnote{Esto asume que el shell Korn está definido como su shell de inicio de sesión. Si no es así, debe hacer que el administrador del sistema lo instale como shell de inicio de sesión.} (No puede utilizar simplemente \texttt{. \~{}/.profile}; el shell no vuelve a ejecutar el archivo \texttt{\$ENV} cuando cambia el valor de \texttt{ENV}).}
\item{Para que los cambios surtan efecto inmediatamente, cierre la sesión y vuelva a iniciarla.\footnote{Esto asume que el shell de Korn está definido como su shell de inicio de sesión. Si no es así, debe hacer que el administrador del sistema lo instale como shell de inicio de sesión.} (No puede utilizar simplemente \texttt{. \~{}/.profile}; el shell no vuelve a ejecutar el archivo \texttt{\$ENV} cuando cambia el valor de \texttt{ENV}).}
\end{enumerate}
La idea del fichero de entorno viene del fichero \emph{.cshrc} del shell C; por lo tanto, muchos usuarios del shell Korn que vinieron del mundo del shell C llaman a sus ficheros de entorno \emph{.kshrc}. (El sufijo rc para los ficheros de inicialización es prácticamente universal en todo el mundo Unix. Significa <<ejecutar comandos>> y entró en el léxico de Unix a través del Sistema Compatible de Tiempo Compartido (CTSS) del MIT).
La idea del fichero de entorno viene del fichero \emph{.cshrc} del shell C; por lo tanto, muchos usuarios del shell de Korn que vinieron del mundo del shell C llaman a sus ficheros de entorno \emph{.kshrc}. (El sufijo \emph{rc} para los ficheros de inicialización es prácticamente universal en todo el mundo Unix. Significa <<ejecutar comandos>> y entró en el léxico de Unix a través del Sistema Compatible de Tiempo Compartido (CTSS) del MIT).
Como regla general, debería poner tan pocas definiciones como sea posible en \emph{.profile} y tantas como sea posible en su fichero de entorno. Debido a que las definiciones agregan a un entorno en lugar de quitarlo, hay pocas posibilidades de que causen que algo en un subproceso no funcione correctamente. (Una excepción podrían ser los choques de nombres si te pasas con los alias).
Las únicas cosas que realmente necesitan estar en \emph{.profile} son los comandos que no son definiciones sino que realmente se ejecutan o producen salida cuando te conectas. Las definiciones de opciones y alias deberían ir en el fichero de entorno. De hecho, hay muchos usuarios del shell Korn que tienen archivos \emph{.profile} diminutos, por ejemplo:
Las únicas cosas que realmente necesitan estar en \emph{.profile} son los comandos que no son definiciones sino que realmente se ejecutan o producen salida cuando te conectas. Las definiciones de opciones y alias deberían ir en el fichero de entorno. De hecho, hay muchos usuarios del shell de Korn que tienen archivos \emph{.profile} diminutos, por ejemplo:
\begin{lstlisting}[language=bash]
stty stop ^S intr ^C erase ^?
@ -688,16 +688,16 @@ from
export ENV=~/.kshrc
\end{lstlisting}
(El comando from, en algunas versiones de Unix, comprueba si tiene correo e imprime una lista de las cabeceras de los mensajes en caso afirmativo). Aunque este es un pequeño \emph{.profile}, el fichero de entorno de este usuario podría ser enorme.
(El comando \emph{from}, en algunas versiones de Unix, comprueba si tiene correo e imprime una lista de las cabeceras de los mensajes en caso afirmativo). Aunque este es un pequeño \emph{.profile}, el fichero de entorno de este usuario podría ser enorme.
Hay una diferencia importante entre \emph{ksh88} y \emph{ksh93}. En \emph{ksh88}, el fichero de entorno se ejecuta siempre. En \emph{ksh93}, sólo los shells interactivos (aquellos que no leen desde un script, sino desde un terminal) ejecutan el fichero de entorno. Por lo tanto, es mejor que el archivo de entorno contenga sólo comandos que sean útiles para el uso interactivo, como la configuración de alias y opciones.
Otra diferencia entre las dos versiones del shell es que \emph{ksh88} sólo hace sustitución de variables en el valor de ENV, mientras que \emph{ksh93} hace sustitución de variables, comandos y aritmética en su valor. (La sustitución de comandos se describe en el \hyperref[sec:Chapter4]{Capítulo 4}. La sustitución aritmética se describe en el \hyperref[sec:Chapter5]{Capítulo 5}.) La sustitución aritmética se describe en el \hyperref[sec:Chapter6]{Capítulo 6}).
Otra diferencia entre las dos versiones del shell es que \emph{ksh88} sólo hace sustitución de variables en el valor de \emph{ENV}, mientras que \emph{ksh93} hace sustitución de variables, comandos y aritmética en su valor. (La sustitución de comandos se describe en el \hyperref[sec:Chapter4]{Capítulo 4}. La sustitución aritmética se describe en el \hyperref[sec:Chapter5]{Capítulo 5}.) La sustitución aritmética se describe en el \hyperref[sec:Chapter6]{Capítulo 6}).
\section{Sugerencias de Personalización}
No dudes en probar cualquiera de las técnicas presentadas en este capítulo. La mejor estrategia es probar algo escribiéndolo en el intérprete de comandos durante su sesión de inicio de sesión; si decide que quiere convertirlo en una parte permanente de su entorno, añádalo a su \emph{.profile}.
Una forma agradable e indolora de añadir a su \emph{.profile} sin entrar en un editor de texto hace uso del comando \emph{print} y uno de los modos de edición del shell Korn. Si escribe un comando de personalización y más tarde decide añadirlo a su \emph{.profile}, puede recuperarlo mediante CTRL-P o CTRL-R (en modo emacs) o j, -, o / (modo vi). Digamos que la línea es:
Una forma agradable e indolora de añadir a su \emph{.profile} sin entrar en un editor de texto hace uso del comando \emph{print} y uno de los modos de edición del shell de Korn. Si escribe un comando de personalización y más tarde decide añadirlo a su \emph{.profile}, puede recuperarlo mediante CTRL-P o CTRL-R (en modo \emph{emacs}) o j, -, o / (modo vi). Digamos que la línea es:
\begin{lstlisting}[language=bash]
PS1="($LOGNAME !)->"

View File

@ -1,23 +1,23 @@
Si te has familiarizado con las técnicas de personalización que presentamos en el capítulo anterior, probablemente te habrás encontrado con varias modificaciones en tu entorno que quieres hacer pero no puedes - todavía. La programación Shell las hace posibles.
El shell Korn tiene algunas de las capacidades de programación más avanzadas de cualquier intérprete de comandos de su tipo. Aunque su sintaxis no es ni de lejos tan elegante o consistente como la de la mayoría de los lenguajes de programación convencionales, su potencia y flexibilidad son comparables. De hecho, el shell Korn puede utilizarse como un entorno completo para escribir prototipos de software.
El shell de Korn tiene algunas de las capacidades de programación más avanzadas de cualquier intérprete de comandos de su tipo. Aunque su sintaxis no es ni de lejos tan elegante o consistente como la de la mayoría de los lenguajes de programación convencionales, su potencia y flexibilidad son comparables. De hecho, el shell de Korn puede utilizarse como un entorno completo para escribir prototipos de software.
Algunos aspectos de la programación en el shell Korn son realmente extensiones de las técnicas de personalización que ya hemos visto, mientras que otros se asemejan a las características de los lenguajes de programación tradicionales. Hemos estructurado este capítulo de forma que si no eres programador, puedes leer este capítulo y hacer bastante más de lo que podrías hacer con la información del capítulo anterior. La experiencia con un lenguaje de programación convencional como Pascal o C es útil (aunque no estrictamente necesaria) para los capítulos siguientes. A lo largo del resto del libro, nos encontraremos ocasionalmente con problemas de programación, llamados <<tareas>>, cuyas soluciones hacen uso de los conceptos que cubrimos.
Algunos aspectos de la programación en el shell de Korn son realmente extensiones de las técnicas de personalización que ya hemos visto, mientras que otros se asemejan a las características de los lenguajes de programación tradicionales. Hemos estructurado este capítulo de forma que si no eres programador, puedes leer este capítulo y hacer bastante más de lo que podrías hacer con la información del capítulo anterior. La experiencia con un lenguaje de programación convencional como Pascal o C es útil (aunque no estrictamente necesaria) para los capítulos siguientes. A lo largo del resto del libro, nos encontraremos ocasionalmente con problemas de programación, llamados <<tareas>>, cuyas soluciones hacen uso de los conceptos que cubrimos.
\section{Scripts y Funciones del Shell}\label{sec:4.1}
Un \emph{script}, o archivo que contiene comandos del shell, es un programa del shell. Sus archivos \emph{.profile} y de entorno, discutidos en el \hyperref[sec:Chapter3]{Capítulo 3}, son scripts de shell.
Puedes crear un script utilizando el editor de texto que prefieras. Una vez que hayas creado uno, hay varias maneras de ejecutarlo. Una, que ya hemos cubierto, es escribir \texttt{. scriptname} (es decir, el comando es un punto). Esto hace que los comandos del script sean leídos y ejecutados como si los hubieras tecleado.
Otras dos formas son escribir \texttt{ksh script} o \texttt{ksh < script}. Estos invocan explícitamente el shell Korn en el script, requiriendo que usted (y sus usuarios) sean conscientes de que son scripts.
Otras dos formas son escribir \texttt{ksh script} o \texttt{ksh < script}. Estos invocan explícitamente el shell de Korn en el script, requiriendo que usted (y sus usuarios) sean conscientes de que son scripts.
La última forma de ejecutar un script es simplemente escribir su nombre y pulsar ENTER, como si estuviera invocando un comando integrado. Esta, por supuesto, es la forma más conveniente. Este método hace que el script se parezca a cualquier otro comando Unix, y de hecho varios comandos <<normales>> se implementan como scripts de shell (es decir, no como programas escritos originalmente en C o algún otro lenguaje), incluyendo \emph{spell}, \emph{man} en algunos sistemas, y varios comandos para administradores de sistemas. La consiguiente falta de distinción entre <<archivos de comandos de usuario>> y <<comandos incorporados>> es uno de los factores que explican la extensibilidad de Unix y, por tanto, su favoritismo entre los programadores.
Puede ejecutar un script tecleando su nombre sólo si . (el directorio actual) forma parte de su ruta de búsqueda de comandos, es decir, si está incluido en su variable PATH (como se explica en el \hyperref[sec:Chapter3]{Capítulo 3}). Si . no está en su ruta, debe teclear \texttt{./ nombredelscript}, que es realmente lo mismo que teclear la ruta relativa del script (ver \hyperref[sec:Chapter1]{Capítulo 1}).
Antes de que pueda invocar el script de shell por su nombre, también debe darle permiso de <<ejecución>>. Si está familiarizado con el sistema de archivos Unix, sabrá que los archivos tienen tres tipos de permisos (lectura, escritura y ejecución) y que esos permisos se aplican a tres categorías de usuarios (el propietario del archivo, un grupo de usuarios y todos los demás). Normalmente, cuando creas un archivo con un editor de texto, el archivo se configura con permiso de lectura y escritura para ti y permiso de sólo lectura para todos los demás\footnote{En realidad, esto depende de la configuración de tu umask, una función avanzada que se describe en el \hyperref[sec:Chapter10]{Capítulo 10}.}.
Antes de que pueda invocar el script de shell por su nombre, también debe darle permiso de <<ejecución>>. Si está familiarizado con el sistema de archivos Unix, sabrá que los archivos tienen tres tipos de permisos (lectura, escritura y ejecución) y que esos permisos se aplican a tres categorías de usuarios (el propietario del archivo, un grupo de usuarios y todos los demás). Normalmente, cuando creas un archivo con un editor de texto, el archivo se configura con permiso de lectura y escritura para ti y permiso de sólo lectura para todos los demás\footnote{En realidad, esto depende de la configuración de tu \emph{umask}, una función avanzada que se describe en el \hyperref[sec:Chapter10]{Capítulo 10}.}.
Por lo tanto, debe dar a su script permiso de ejecución explícitamente, utilizando el comando chmod(1). La forma más sencilla de hacerlo es así:
Por lo tanto, debe dar a su script permiso de ejecución explícitamente, utilizando el comando \emph{chmod(1)}. La forma más sencilla de hacerlo es así:
\begin{lstlisting}[language=bash]
chmod +x scriptname
@ -47,7 +47,7 @@ El uso de subprocesos de shell tiene muchas ramificaciones. Una importante es qu
Otras cuestiones relacionadas con los subprocesos del shell son demasiado complejas para entrar en ellas ahora; consulte el \hyperref[sec:Chapter7]{Capítulo 7} y el \hyperref[sec:Chapter8]{Capítulo 8} para obtener más detalles sobre la E/S de los subprocesos y las características de los procesos, respectivamente. Por ahora, sólo tenga en cuenta que un script normalmente se ejecuta en un subproceso del shell.
\subsection{Funciones}
La característica de función del shell Korn es una versión ampliada de una facilidad similar en el shell Bourne del Sistema V y algunos otros shells. Una función es una especie de script dentro de un script; se usa para definir algún código del shell por su nombre y almacenarlo en la memoria del shell, para ser invocado y ejecutado más tarde.
La característica de función del shell de Korn es una versión ampliada de una facilidad similar en el shell de Bourne del Sistema V y algunos otros shells. Una función es una especie de script dentro de un script; se usa para definir algún código del shell por su nombre y almacenarlo en la memoria del shell, para ser invocado y ejecutado más tarde.
Las funciones mejoran significativamente la programabilidad del shell, por dos razones principales. En primer lugar, cuando invoca una función, ésta ya se encuentra en la memoria del shell (excepto en el caso de las funciones cargadas automáticamente; consulte la Sección 4.1.1.1, más adelante en este capítulo); por lo tanto, una función se ejecuta más rápidamente. Los ordenadores modernos tienen mucha memoria, así que no hay necesidad de preocuparse por la cantidad de espacio que ocupa una función típica. Por esta razón, la mayoría de la gente define tantas funciones como sea posible en lugar de tener muchos scripts a su alrededor.
@ -69,18 +69,18 @@ function () { Semántica POSIX
}
\end{lstlisting}
La primera forma proporciona acceso a toda la potencia y programabilidad del shell Korn. La segunda es compatible con la sintaxis para funciones de shell introducida en el shell Bourne de la versión 2 del sistema V. Esta forma obedece a la semántica del estándar POSIX, que es menos potente que las funciones completas estilo shell Korn. (En este libro utilizaremos siempre la primera forma. Puede borrar una definición de función con el comando \texttt{unset -f nombrefuncion}.
La primera forma proporciona acceso a toda la potencia y programabilidad del shell de Korn. La segunda es compatible con la sintaxis para funciones de shell introducida en el shell de Bourne de la versión 2 del sistema V. Esta forma obedece a la semántica del estándar POSIX, que es menos potente que las funciones completas estilo shell de Korn. (En este libro utilizaremos siempre la primera forma. Puede borrar una definición de función con el comando \texttt{unset -f nombrefuncion}.
Cuando define una función, le indica al shell que almacene su nombre y definición (es decir, los comandos del shell que contiene) en la memoria. Si desea ejecutar la función más tarde, sólo tiene que escribir su nombre seguido de los argumentos, como si se tratara de un script del shell.
Puede averiguar qué funciones están definidas en su sesión de inicio de sesión escribiendo \texttt{functions}\footnote{Se trata en realidad de un alias de typeset -f; véase el capítulo 6.}. (Observe la s al final del nombre del comando.) El shell imprimirá no sólo los nombres sino también las definiciones de todas las funciones, en orden alfabético por nombre de función. Dado que esto puede resultar en una salida larga, es posible que desee canalizar la salida a través de más o redirigirla a un archivo para su examen con un editor de texto.
Puede averiguar qué funciones están definidas en su sesión de inicio de sesión escribiendo \texttt{functions}\footnote{Se trata en realidad de un alias de \emph{typeset -f}; véase el capítulo 6.}. (Observe la s al final del nombre del comando.) El shell imprimirá no sólo los nombres sino también las definiciones de todas las funciones, en orden alfabético por nombre de función. Dado que esto puede resultar en una salida larga, es posible que desee canalizar la salida a través de más o redirigirla a un archivo para su examen con un editor de texto.
Aparte de las ventajas, hay dos diferencias importantes entre las funciones y los scripts. En primer lugar, las funciones no se ejecutan en procesos separados, como hacen los scripts cuando los invocas por su nombre; la <<semántica>> de la ejecución de una función es más parecida a la de tu perfil \emph{.profile} cuando te conectas o a la de cualquier script cuando se invoca con el comando <<dot>>. En segundo lugar, si una función tiene el mismo nombre que un script o programa ejecutable, la función tiene preferencia.
Este es un buen momento para mostrar el orden de precedencia de las distintas fuentes de comandos. Cuando escribes un comando en el shell, éste busca en los siguientes lugares hasta que encuentra una coincidencia:
\begin{enumerate}
\item{Palabras clave, como function y algunas otras (por ejemplo, \emph{if} y \emph{for}) que veremos en el \hyperref[sec:Chapter5]{Capítulo 5}.}
\item{Palabras clave, como \emph{function} y algunas otras (por ejemplo, \emph{if} y \emph{for}) que veremos en el \hyperref[sec:Chapter5]{Capítulo 5}.}
\item{Alias (aunque no puede definir un alias cuyo nombre sea una palabra clave del shell, puede definir un alias que se expanda a una palabra clave, por ejemplo, \texttt{alias aslongas=while}; consulte el \hyperref[sec:Chapter7]{Capítulo 7} para obtener más detalles)}
\item{Complementos especiales, como \emph{break} y \emph{continue} (la lista completa es \texttt{. (punto), :, alias, break, continue, eval, exec, exit, export, login, newgrp, readonly, return, set, shift, trap, typeset, unalias, y unset)}}
\item{Funciones}
@ -103,7 +103,7 @@ $ whence -v ll
ll is an alias for 'ls -l'
\end{lstlisting}
Por compatibilidad con el shell Bourne del Sistema V, el shell Korn predefine el alias \texttt{type='whence -v'}. Esto definitivamente hace la transición al shell Korn más fácil para los antiguos usuarios del shell Bourne; \emph{type} es similar a \emph{whence}. El comando whence en realidad tiene varias opciones, descritas en la Tabla \ref{Tab: whence}.
Por compatibilidad con el shell de Bourne del Sistema V, el shell de Korn predefine el alias \texttt{type='whence -v'}. Esto definitivamente hace la transición al shell de Korn más fácil para los antiguos usuarios del shell de Bourne; \emph{type} es similar a \emph{whence}. El comando whence en realidad tiene varias opciones, descritas en la Tabla \ref{Tab: whence}.
\begin{table}[h]
\center
@ -113,7 +113,7 @@ Por compatibilidad con el shell Bourne del Sistema V, el shell Korn predefine el
\textbf{Opción} & \textbf{Significado} \\ \hline
-a & Imprime todas las interpretaciones del nombre dado. \\\hline
-f & Omitir funciones en la búsqueda del nombre. \\\hline
-p & Busca en \$PATH, incluso si el nombre es un built-in o una función. \\\hline
-p & Busca en \$PATH, incluso si el nombre es un \emph{built-in} o una función. \\\hline
-v & Imprime una descripción más detallada del nombre. \\\hline
\end{tabular}
\end{table}
@ -148,7 +148,7 @@ $ cat > whoson
}
\end{enumerate}
Ahora, la primera vez que escriba \texttt{whoson}, el shell buscará un comando llamado whoson usando el orden de búsqueda descrito anteriormente. No se encontrará como un built-in especial, como una función o como un built-in normal. El intérprete de comandos inicia entonces una búsqueda a lo largo de \texttt{\$PATH}. Cuando finalmente encuentra \emph{\~}\emph{/funcs/whoson}, el shell se da cuenta de que \emph{\~/funcs} también está en \texttt{\$FPATH}. (''¡Ajá!'' dice el shell.) Cuando este es el caso, el shell espera encontrar la definición de la función llamada \emph{whoson} dentro del archivo. Lee y ejecuta todo el contenido del archivo y sólo entonces ejecuta la función \emph{whoson}, con cualquier argumento suministrado. (Si el archivo encontrado tanto en \texttt{\$PATH} como en \texttt{\$FPATH} no define realmente la función, obtendrá un mensaje de error <<no encontrado>>).
Ahora, la primera vez que escriba \texttt{whoson}, el shell buscará un comando llamado whoson usando el orden de búsqueda descrito anteriormente. No se encontrará como un \emph{built-in} especial, como una función o como un \emph{built-in} normal. El intérprete de comandos inicia entonces una búsqueda a lo largo de \texttt{\$PATH}. Cuando finalmente encuentra \emph{\~}\emph{/funcs/whoson}, el shell se da cuenta de que \emph{\~/funcs} también está en \texttt{\$FPATH}. (''¡Ajá!'' dice el shell.) Cuando este es el caso, el shell espera encontrar la definición de la función llamada \emph{whoson} dentro del archivo. Lee y ejecuta todo el contenido del archivo y sólo entonces ejecuta la función \emph{whoson}, con cualquier argumento suministrado. (Si el archivo encontrado tanto en \texttt{\$PATH} como en \texttt{\$FPATH} no define realmente la función, obtendrá un mensaje de error <<no encontrado>>).
La próxima vez que escriba \emph{whoson}, la función ya estará definida, por lo que el shell la encontrará inmediatamente, sin necesidad de buscar la ruta.
@ -158,7 +158,7 @@ Por último, a partir de \emph{ksh93m}, cada directorio nombrado en PATH puede c
Además, se puede asignar otra variable de entorno. Su uso previsto es especificar una ruta relativa o absoluta para un directorio de bibliotecas que contenga las bibliotecas compartidas para los ejecutables en el directorio bin actual. En muchos sistemas Unix, esta variable es \texttt{LD\_LIBRARY\_PATH}, pero algunos sistemas tienen una variable diferente - consulte su documentación local. El valor dado se añade al valor existente de la variable cuando se ejecuta la orden. (Este mecanismo puede abrir brechas de seguridad. Los administradores de sistemas deben utilizarlo con precaución).
Por ejemplo, el grupo AT\&T Advanced Software Tools que distribuye \emph{ksh93} también tiene muchas otras herramientas, a menudo instaladas en un directorio \emph{ast/bin} separado. Esta característica permite a los programas ast encontrar sus bibliotecas compartidas, sin que el usuario tenga que ajustar manualmente \texttt{LD\_LIBRARY\_PATH} en el archivo \emph{.profile}\footnote{Las versiones h a l+ de ksh93 utilizaban un mecanismo similar pero más restringido, a través de un fichero llamado .fpath, e incorporaban la configuración de la variable de ruta de la biblioteca. Como esta característica no estaba muy extendida, se generalizó en un único archivo a partir de la versión m.}. Por ejemplo, si un comando se encuentra en \emph{/usr/local/ast/bin}, y el archivo \emph{.paths} en ese directorio contiene la asignación \texttt{LD\_LIBRARY\_PATH=../lib}, el shell añade \texttt{/usr/local/ast/lib:} al valor de \texttt{LD\_LIBRARY\_PATH} antes de ejecutar el comando.
Por ejemplo, el grupo AT\&T Advanced Software Tools que distribuye \emph{ksh93} también tiene muchas otras herramientas, a menudo instaladas en un directorio \emph{ast/bin} separado. Esta característica permite a los programas ast encontrar sus bibliotecas compartidas, sin que el usuario tenga que ajustar manualmente \texttt{LD\_LIBRARY\_PATH} en el archivo \emph{.profile}\footnote{Las versiones h a l+ de \emph{ksh93} utilizaban un mecanismo similar pero más restringido, a través de un fichero llamado \emph{.fpath}, e incorporaban la configuración de la variable de ruta de la biblioteca. Como esta característica no estaba muy extendida, se generalizó en un único archivo a partir de la versión m.}. Por ejemplo, si un comando se encuentra en \emph{/usr/local/ast/bin}, y el archivo \emph{.paths} en ese directorio contiene la asignación \texttt{LD\_LIBRARY\_PATH=../lib}, el shell añade \texttt{/usr/local/ast/lib:} al valor de \texttt{LD\_LIBRARY\_PATH} antes de ejecutar el comando.
Los lectores familiarizados con \emph{ksh88} notarán que esta parte del comportamiento del shell ha cambiado significativamente. Dado que \emph{ksh88} siempre leía el fichero de entorno, tanto si el shell era interactiva como si no, lo más sencillo era limitarse a poner allí las definiciones de las funciones. Sin embargo, esto podía dar lugar a un archivo grande y difícil de manejar. Para evitar esto, puedes crear archivos en uno o más directorios listados en \texttt{\$FPATH}. Luego, en el archivo de entorno, se marcarían las funciones como de \emph{carga automática}:
@ -167,12 +167,12 @@ autoload whoson
...
\end{lstlisting}
Marcar una función con \emph{autoload}\footnote{autoload es en realidad un alias de typeset -fu.} le dice al shell que este nombre es una función, y que encuentre la definición buscando en \texttt{\$FPATH}. La ventaja de esto es que la función no se carga en la memoria del shell si no se necesita. La desventaja es que tienes que listar explícitamente todas tus funciones en tu fichero de entorno.
Marcar una función con \emph{autoload}\footnote{\emph{autoload} es en realidad un alias de \emph{typeset -fu}.} le dice al shell que este nombre es una función, y que encuentre la definición buscando en \texttt{\$FPATH}. La ventaja de esto es que la función no se carga en la memoria del shell si no se necesita. La desventaja es que tienes que listar explícitamente todas tus funciones en tu fichero de entorno.
La integración de \emph{ksh93} de la búsqueda en PATH y FPATH simplifica así la forma de añadir funciones del intérprete de órdenes a su <<biblioteca>> personal de funciones del intérprete de órdenes.
\subsubsection{Funciones POSIX}
Como se mencionó anteriormente, las funciones definidas usando la sintaxis POSIX obedecen a la semántica POSIX y no a la semántica del shell Korn:
Como se mencionó anteriormente, las funciones definidas usando la sintaxis POSIX obedecen a la semántica POSIX y no a la semántica del shell de Korn:
\begin{lstlisting}[language=bash]
functname () {
@ -180,18 +180,18 @@ functname () {
}
\end{lstlisting}
La mejor manera de entender esto es pensar en una función POSIX como si fuera un punto script. Las acciones dentro del cuerpo de la función afectan a todo el estado del script actual. En contraste, las funciones del shell Korn tienen mucho menos estado compartido con el shell padre, aunque no son idénticas a scripts totalmente separados.
La mejor manera de entender esto es pensar en una función POSIX como si fuera un punto script. Las acciones dentro del cuerpo de la función afectan a todo el estado del script actual. En contraste, las funciones del shell de Korn tienen mucho menos estado compartido con el shell padre, aunque no son idénticas a scripts totalmente separados.
Los detalles técnicos siguen; incluyen información que aún no hemos cubierto. Así que vuelva y relea esta sección después de haber aprendido sobre el comando \emph{typeset} en el \hyperref[sec:Chapter6]{Capítulo 6} y sobre traps en el \hyperref[sec:Chapter8]{Capítulo 8}.
\begin{itemize}
\item{Las funciones POSIX comparten variables con el script padre. Las funciones del shell Korn pueden tener sus propias variables locales.}
\item{Las funciones POSIX comparten trampas con el script padre. Las funciones del shell Korn pueden tener sus propias trampas locales.}
\item{Las funciones POSIX no pueden ser recursivas (llamarse a sí mismas)\footnote{Esta es una restricción impuesta por el shell Korn, no por el estándar POSIX.}. Las funciones del shell Korn sí pueden.}
\item{Las funciones POSIX comparten variables con el script padre. Las funciones del shell de Korn pueden tener sus propias variables locales.}
\item{Las funciones POSIX comparten trampas con el script padre. Las funciones del shell de Korn pueden tener sus propias trampas locales.}
\item{Las funciones POSIX no pueden ser recursivas (llamarse a sí mismas)\footnote{Esta es una restricción impuesta por el shell de Korn, no por el estándar POSIX.}. Las funciones del shell de Korn sí pueden.}
\item{Cuando se ejecuta una función POSIX, \texttt{\$0} no se cambia por el nombre de la función.}
\end{itemize}
Si utiliza el comando dot con el nombre de una función del shell Korn, dicha función obedecerá la semántica POSIX, afectando a todo el estado (variables y traps) del shell padre:
Si utiliza el comando \emph{dot} con el nombre de una función del shell de Korn, dicha función obedecerá la semántica POSIX, afectando a todo el estado (variables y traps) del shell padre:
\begin{lstlisting}[language=bash]
$ function demo { # Define una función de Korn Shell
@ -209,13 +209,13 @@ global: myvar is 3
\end{lstlisting}
\section{Variables del Shell}
Una parte importante de la funcionalidad de programación del shell Korn está relacionada con las variables del shell. Ya hemos visto los conceptos básicos de las variables. Para recapitular brevemente: son lugares con nombre para almacenar datos, normalmente en forma de cadenas de caracteres, y sus valores pueden obtenerse precediendo sus nombres con signos de dólar (\$). Ciertas variables, llamadas variables de entorno, se nombran convencionalmente en mayúsculas, y sus valores se dan a conocer (con la sentencia export) a los subprocesos.
Una parte importante de la funcionalidad de programación del shell de Korn está relacionada con las variables del shell. Ya hemos visto los conceptos básicos de las variables. Para recapitular brevemente: son lugares con nombre para almacenar datos, normalmente en forma de cadenas de caracteres, y sus valores pueden obtenerse precediendo sus nombres con signos de dólar (\$). Ciertas variables, llamadas variables de entorno, se nombran convencionalmente en mayúsculas, y sus valores se dan a conocer (con la sentencia export) a los subprocesos.
Esta sección presenta los conceptos básicos de las variables del shell. La discusión de ciertas características avanzadas se retrasa hasta más adelante en el capítulo, después de cubrir las expresiones regulares.
Si es programador, ya sabe que casi todos los lenguajes de programación importantes utilizan variables de alguna manera; de hecho, una forma importante de caracterizar las diferencias entre lenguajes es comparar sus facilidades para las variables.
La principal diferencia entre el esquema de variables del shell Korn y los de los lenguajes convencionales es que el esquema del shell Korn pone mucho énfasis en las cadenas de caracteres. (Por tanto, tiene más en común con un lenguaje de propósito especial como SNOBOL que con uno de propósito general como Pascal). Esto también es cierto para el shell Bourne y el shell C, pero el shell Korn va más allá de ellos al tener mecanismos adicionales para manejar enteros y números de coma flotante de doble precisión explícitamente, así como arrays simples.
La principal diferencia entre el esquema de variables del shell de Korn y los de los lenguajes convencionales es que el esquema del shell de Korn pone mucho énfasis en las cadenas de caracteres. (Por tanto, tiene más en común con un lenguaje de propósito especial como SNOBOL que con uno de propósito general como Pascal). Esto también es cierto para el shell de Bourne y el shell C, pero el shell de Korn va más allá de ellos al tener mecanismos adicionales para manejar enteros y números de coma flotante de doble precisión explícitamente, así como arrays simples.
\subsection{Parámetros de Posición}
Como ya hemos visto, puedes definir valores para variables con sentencias de la forma \texttt{varname = value}, por ejemplo:
@ -270,7 +270,7 @@ Obtendrás el mismo resultado si escribes \texttt{fred bob dave}.
Normalmente, se definen varias funciones de shell dentro de un único script de shell. Por lo tanto, cada función necesita manejar sus propios argumentos, lo que a su vez significa que cada función necesita hacer un seguimiento de los parámetros posicionales por separado. Por supuesto, cada función tiene sus propias copias de estas variables (aunque las funciones no se ejecuten en su propio subproceso, como los scripts); decimos que tales variables son locales a la función.
Otras variables definidas dentro de las funciones no son locales; son globales, lo que significa que sus valores son conocidos a través de todo el script de shell\footnote{Sin embargo, en la sección sobre composición tipográfica del \hyperref[sec:Chapter6]{Capítulo 6} se explica cómo hacer que las variables sean locales a las funciones.}. Por ejemplo, suponga que tiene un script de shell llamado ascript que contiene esto:
Otras variables definidas dentro de las funciones no son locales; son globales, lo que significa que sus valores son conocidos a través de todo el script de shell\footnote{Sin embargo, en la sección sobre composición tipográfica del \hyperref[sec:Chapter6]{Capítulo 6} se explica cómo hacer que las variables sean locales a las funciones.}. Por ejemplo, suponga que tiene un script de shell llamado \emph{ascript} que contiene esto:
\begin{lstlisting}[language=bash]
function afunc {
@ -338,7 +338,7 @@ $ countargs "$@"
\subsubsection{Modificación de los Parámetros de Posición}\label{sec:4.2.1.2}
En ocasiones, resulta útil modificar los parámetros de posición. Ya hemos mencionado que no se pueden establecer directamente, utilizando una asignación como \texttt{1="primero"}. Sin embargo, el conjunto de comandos incorporado puede utilizarse para este propósito.
El comando \emph{set} es quizás el comando más complicado y sobrecargado del shell. Toma un gran número de opciones, las cuales se discuten en el \hyperref[sec:Chapter9]{Capítulo 9}. Lo que nos importa por el momento es que los argumentos adicionales no opcionales para \emph{set} reemplazan a los parámetros posicionales. Supongamos que nuestro script fue invocado con los tres argumentos <<bob>>, <<fred>>, y <<dave>>. Entonces countargs \texttt{"\$@"} nos dice que tenemos tres argumentos. Al usar \emph{set} para cambiar los parámetros posicionales, \texttt{\$\#} se actualiza también.
El comando \emph{set} es quizás el comando más complicado y sobrecargado del shell. Toma un gran número de opciones, las cuales se discuten en el \hyperref[sec:Chapter9]{Capítulo 9}. Lo que nos importa por el momento es que los argumentos adicionales no opcionales para \emph{set} reemplazan a los parámetros posicionales. Supongamos que nuestro script fue invocado con los tres argumentos <<bob>>, <<fred>>, y <<dave>>. Entonces \texttt{countargs "\$@"} nos dice que tenemos tres argumentos. Al usar \emph{set} para cambiar los parámetros posicionales, \texttt{\$\#} se actualiza también.
\begin{lstlisting}[language=bash]
$ set one two three "four not five" # Modificar los parametros de posicion
@ -365,7 +365,7 @@ $ countargs "$@" # Sin cambios en los parametros del she
\subsection{Más Sobre Sintaxis de Variables}
Antes de mostrar las muchas cosas que puedes hacer con las variables del shell, tenemos que hacer una confesión: la sintaxis de \texttt{\$ varname} para tomar el valor de una variable no es del todo exacta. En realidad, es la forma simple de la sintaxis más general, que es \texttt{\${varname}}.
¿Por qué dos sintaxis? Por un lado, la sintaxis más general es necesaria si su código se refiere a más de nueve parámetros posicionales: debe usar \texttt{\${10}} para el décimo en lugar de \texttt{\$10}. (Esto asegura la compatibilidad con el shell Bourne, donde \texttt{\$10} significa \texttt{\${1}0}.) Aparte de eso, considere el ejemplo del \hyperref[sec:Chapter3]{Capítulo 3} de establecer su variable prompt primaria (PS1) a su nombre de usuario:
¿Por qué dos sintaxis? Por un lado, la sintaxis más general es necesaria si su código se refiere a más de nueve parámetros posicionales: debe usar \texttt{\${10}} para el décimo en lugar de \texttt{\$10}. (Esto asegura la compatibilidad con el shell de Bourne, donde \texttt{\$10} significa \texttt{\${1}0}.) Aparte de eso, considere el ejemplo del \hyperref[sec:Chapter3]{Capítulo 3} de establecer su variable prompt primaria (PS1) a su nombre de usuario:
\begin{lstlisting}[language=bash]
PS1="($LOGNAME)-> "
@ -377,7 +377,7 @@ Esto funciona porque el paréntesis derecho que sigue inmediatamente a \texttt{L
PS1="$LOGNAME_ "
\end{lstlisting}
entonces el shell intenta utilizar \texttt{''LOGNAME\_'' }como nombre de la variable, es decir, tomar el valor de \texttt{\$LOGNAME\_}. Como no existe tal variable, el valor por defecto es null (la cadena vacía, ''''), y PS1 se establece sólo con un espacio.
entonces el shell intenta utilizar \texttt{''LOGNAME\_'' }como nombre de la variable, es decir, tomar el valor de \texttt{\$LOGNAME\_}. Como no existe tal variable, el valor por defecto es \emph{null} (la cadena vacía, ''''), y PS1 se establece sólo con un espacio.
Por esta razón, la sintaxis completa para tomar el valor de una variable es \texttt{\${ varname }}. Así que si usamos:
@ -388,13 +388,13 @@ PS1="${LOGNAME}_ "
obtendríamos el deseado \texttt{tunombre\_}. Es seguro omitir las llaves (\{\}) si el nombre de la variable va seguido de un carácter que no sea una letra, un dígito o un guión bajo.
\subsection{Añadir una Variable}
Como se ha mencionado, las variables del shell Korn tienden a estar orientadas a cadenas. Una operación muy común es añadir un nuevo valor a una variable existente. (Por ejemplo, reunir un conjunto de opciones en una sola cadena.) Desde tiempos inmemoriales, esto se hacía aprovechando la sustitución de variables dentro de comillas dobles:
Como se ha mencionado, las variables del shell de Korn tienden a estar orientadas a cadenas. Una operación muy común es añadir un nuevo valor a una variable existente. (Por ejemplo, reunir un conjunto de opciones en una sola cadena.) Desde tiempos inmemoriales, esto se hacía aprovechando la sustitución de variables dentro de comillas dobles:
\begin{lstlisting}[language=bash]
myopts="$myopts $newopt"
\end{lstlisting}
Los valores de \texttt{myopts} y \texttt{newopt} se concatenan en una sola cadena, y el resultado se asigna de nuevo a \texttt{myopts}. A partir de \emph{ksh93j}, el shell Korn proporciona un mecanismo más eficiente e intuitivo para hacer esto:
Los valores de \texttt{myopts} y \texttt{newopt} se concatenan en una sola cadena, y el resultado se asigna de nuevo a \texttt{myopts}. A partir de \emph{ksh93j}, el shell de Korn proporciona un mecanismo más eficiente e intuitivo para hacer esto:
\begin{lstlisting}[language=bash]
myopts+=" $newopt"
@ -436,7 +436,7 @@ Afortunadamente, puedes utilizar una asignación compuesta para hacerlo todo de
person=(firstname=John initial=Q. lastname=Public
\end{lstlisting}
Puede recuperar el valor de toda la variable, o de un componente, utilizando print.
Puede recuperar el valor de toda la variable, o de un componente, utilizando \emph{print}.
\begin{lstlisting}[language=bash]
$ print $person # Impresion sencilla
@ -451,9 +451,9 @@ $ print ${person.initial} # Imprimir solo la inicial del segundo
Q.
\end{lstlisting}
El segundo comando \emph{print} preserva los espacios en blanco que el shell Korn proporciona cuando devuelve el valor de una variable compuesta. La opción \emph{-r} para imprimir se discute en el \hyperref[sec:Chapter7]{Capítulo 7}.
El segundo comando \emph{print} preserva los espacios en blanco que el shell de Korn proporciona cuando devuelve el valor de una variable compuesta. La opción \emph{-r} para imprimir se discute en el \hyperref[sec:Chapter7]{Capítulo 7}.
\textbf{NOTA:} El orden de los componentes es diferente del utilizado en la asignación inicial. Este orden depende de cómo el shell Korn gestiona internamente las variables compuestas y no puede ser controlado por el programador.
\textbf{NOTA:} El orden de los componentes es diferente del utilizado en la asignación inicial. Este orden depende de cómo el shell de Korn gestiona internamente las variables compuestas y no puede ser controlado por el programador.
Existe una segunda sintaxis de asignación, similar a la primera:
@ -472,9 +472,9 @@ person+= (typeset spouse=Jane)
Se permite un espacio después del = pero no antes. Esto se aplica a las asignaciones compuestas con = y +=.
El shell Korn tiene sintaxis adicionales para asignaciones compuestas que se aplican sólo a variables de array; también se discuten en el \hyperref[sec:Chapter6]{Capítulo 6}.
El shell de Korn tiene sintaxis adicionales para asignaciones compuestas que se aplican sólo a variables de array; también se discuten en el \hyperref[sec:Chapter6]{Capítulo 6}.
Finalmente, mencionaremos que el shell Korn tiene una variable compuesta especial llamada \texttt{.sh}. Los diversos componentes se relacionan casi todos con características que aún no hemos cubierto, excepto \texttt{\${.sh.version}}, que le indica la versión del shell Korn que tiene:
Finalmente, mencionaremos que el shell de Korn tiene una variable compuesta especial llamada \texttt{.sh}. Los diversos componentes se relacionan casi todos con características que aún no hemos cubierto, excepto \texttt{\${.sh.version}}, que le indica la versión del shell de Korn que tiene:
\begin{lstlisting}[language=bash]
$ print ${.sh.version}
@ -484,7 +484,7 @@ Version M 1993-12-28 m
Veremos otro componente de \texttt{.sh} más adelante en este capítulo, y los otros componentes se cubren a medida que introducimos las características con las que se relacionan.
\section{Referencias Indirectas a Variables (namerefs)}\label{sec:4.4}
La mayoría de las veces, como hemos visto hasta ahora, se manipulan variables directamente, por su nombre (x=1, por ejemplo). El shell Korn le permite manipular variables indirectamente, usando algo llamado \emph{nameref}. Puedes crear un \emph{nameref} usando \texttt{typeset -n}, o el más conveniente alias predefinido, nameref. He aquí un ejemplo sencillo:
La mayoría de las veces, como hemos visto hasta ahora, se manipulan variables directamente, por su nombre (x=1, por ejemplo). El shell de Korn le permite manipular variables indirectamente, usando algo llamado \emph{nameref}. Puedes crear un \emph{nameref} usando \texttt{typeset -n}, o el más conveniente alias predefinido, \emph{nameref}. He aquí un ejemplo sencillo:
\begin{lstlisting}[language=bash]
$ name="bill" # Establecer valor inicial
@ -496,7 +496,7 @@ $ print $name # Se cambia la variable original
arnold
\end{lstlisting}
Para averiguar el nombre de la variable real a la que hace referencia el nameref, utilice \texttt{\${! variable }}:
Para averiguar el nombre de la variable real a la que hace referencia el \emph{nameref}, utilice \texttt{\${! variable }}:
\begin{lstlisting}[language=bash]
$ print ${!firstname}
@ -525,9 +525,9 @@ $ date
Wed Nov 14 11:52:38 IST 2001
\end{lstlisting}
La función \emph{getday} utiliza \emph{awk} para imprimir el primer campo, que es el día de la semana. El resultado de esta operación, que se realiza dentro de la sustitución de comandos (descrita más adelante en este capítulo), se asigna a la variable local \texttt{day}. Pero \texttt{day} es una referencia de nombre; la asignación en realidad actualiza la variable global \texttt{today}. Sin la función nameref, tendrá que recurrir a trucos avanzados como el uso de \emph{eval} (véase el capítulo 7) para hacer que ocurra algo como esto.
La función \emph{getday} utiliza \emph{awk} para imprimir el primer campo, que es el día de la semana. El resultado de esta operación, que se realiza dentro de la sustitución de comandos (descrita más adelante en este capítulo), se asigna a la variable local \texttt{day}. Pero \texttt{day} es una referencia de nombre; la asignación en realidad actualiza la variable global \texttt{today}. Sin la función \emph{nameref}, tendrá que recurrir a trucos avanzados como el uso de \emph{eval} (véase el capítulo 7) para hacer que ocurra algo como esto.
Para eliminar un nameref, utilice \texttt{unset -n}, que elimina el propio nameref, en lugar de eliminar la variable a la que el nameref hace referencia. Por último, tenga en cuenta que las variables que son namerefs no pueden tener puntos en sus nombres (es decir, ser componentes de una variable compuesta). Sin embargo, pueden ser referencias a una variable compuesta.
Para eliminar un \emph{nameref}, utilice \texttt{unset -n}, que elimina el propio \emph{nameref}, en lugar de eliminar la variable a la que el \emph{nameref} hace referencia. Por último, tenga en cuenta que las variables que son \emph{namerefs} no pueden tener puntos en sus nombres (es decir, ser componentes de una variable compuesta). Sin embargo, pueden ser referencias a una variable compuesta.
\section{Operadores de Cadena}
La sintaxis de llaves permite utilizar los \emph{operadores de cadena} del shell. Los operadores de cadena le permiten manipular valores de variables de varias formas útiles sin tener que escribir programas completos o recurrir a utilidades externas de Unix. Puede hacer mucho con los operadores de manejo de cadenas incluso si todavía no domina las características de programación que veremos en capítulos posteriores.
@ -556,16 +556,16 @@ El primer grupo de operadores de cadena comprueba la existencia de variables y p
\textbf{Operador} & \textbf{Sustitución} \\ \hline
\texttt{\$\{varname:-word\}} & Si \emph{varname} existe y no es nulo, devuelve su valor; en caso contrario devuelve word. \\
\textbf{Propósito:} & Devolver un valor por defecto si la variable no está definida. \\
\textbf{Ejemplo:} & \texttt{\${count:-0}} se evalúa a 0 si count no está definido. \\ \hline
\textbf{Ejemplo:} & \texttt{\${count:-0}} se evalúa a 0 si \emph{count} no está definido. \\ \hline
\texttt{\$\{varname:=word\}} & Si \emph{varname} existe y no es nulo, devuelve su valor; en caso contrario, lo establece en word y luego devuelve su valor.\tablefootnote{Los programadores de Pascal, Modula y Ada pueden encontrar útil reconocer la similitud de esto con los operadores de asignación en esos lenguajes.} \\
\textbf{Propósito:} & Asignar a una variable un valor por defecto si no está definida. \\
\textbf{Ejemplo:} & \texttt{\${count:=0}} establece el recuento a 0 si no está definido. \\ \hline
\texttt{\$\{varname:?word\}} & Si \emph{varname} existe y no es null, devuelve su valor; de lo contrario imprime \texttt{varname : message}, y aborta el comando o script actual. Omitir mensaje produce el parámetro mensaje por defecto nulo o no establecido. Tenga en cuenta, sin embargo, que los shells interactivos no abortan. \\
\texttt{\$\{varname:?word\}} & Si \emph{varname} existe y no es \emph{null}, devuelve su valor; de lo contrario imprime \texttt{varname : message}, y aborta el comando o script actual. Omitir mensaje produce el parámetro mensaje por defecto nulo o no establecido. Tenga en cuenta, sin embargo, que los shells interactivos no abortan. \\
\textbf{Propósito:} & Atrapar errores que resultan de variables no definidas. \\
\textbf{Ejemplo:} & \texttt{\$\{count:? ''undefined!''\}} imprime \texttt{count: ¡undefined!} y sale si count es undefined. \\ \hline
\texttt{\$\{varname:+word\}} & Si \emph{varname} existe y no es null, devuelve word; en caso contrario devuelve null. \\
\texttt{\$\{varname:+word\}} & Si \emph{varname} existe y no es \emph{null}, devuelve word; en caso contrario devuelve null. \\
\textbf{Objetivo} & Comprobar la existencia de una variable. \\
\textbf{Ejemplo:} & \texttt{\$\{count:+1\}} devuelve 1 (que podría significar "verdadero") si count está definido. \\\hline
\textbf{Ejemplo:} & \texttt{\$\{count:+1\}} devuelve 1 (que podría significar "verdadero") si \emph{count} está definido. \\\hline
\end{tabular}
\end{table}
@ -599,7 +599,7 @@ La salida de \emph{sort} se envía a la utilidad \emph{head(1)}, que, cuando rec
Supongamos que el script que queremos escribir se llama \emph{highest}. Entonces si el usuario escribe \texttt{highest myfile}, la línea que realmente se ejecuta es:
\begin{lstlisting}[language=bash]
ort -nr myfile | head -10
sort -nr myfile | head -10
\end{lstlisting}
O si el usuario escribe highest \texttt{myfile 22}, la línea que se ejecuta es:
@ -629,7 +629,7 @@ sort -nr "$filename" | head -$howmany
Los corchetes alrededor de \texttt{howmany} en los comentarios se adhieren a la convención en la documentación Unix de que los corchetes denotan argumentos opcionales.
Los cambios que acabamos de hacer mejoran la legibilidad del código, pero no su ejecución. ¿Qué pasaría si el usuario invocara el script sin ningún argumento? Recuerde que los parámetros posicionales por defecto son null si no están definidos. Si no hay argumentos, entonces \texttt{\$1} y \texttt{\$2} son nulos. La variable howmany \texttt(\$2) está configurada por defecto a 10, pero no hay valor por defecto para \texttt{filename (\$1)}. El resultado sería que este comando se ejecuta:
Los cambios que acabamos de hacer mejoran la legibilidad del código, pero no su ejecución. ¿Qué pasaría si el usuario invocara el script sin ningún argumento? Recuerde que los parámetros posicionales por defecto son \emph{null} si no están definidos. Si no hay argumentos, entonces \texttt{\$1} y \texttt{\$2} son nulos. La variable howmany \texttt(\$2) está configurada por defecto a 10, pero no hay valor por defecto para \texttt{filename (\$1)}. El resultado sería que este comando se ejecuta:
\begin{lstlisting}[language=bash]
sort -nr | head -10
@ -721,7 +721,7 @@ Continuaremos refinando nuestra solución a la \hyperref[box:4-1]{Tarea 4-1} má
Los comodines han sido características estándar de todos los intérpretes de comandos Unix que se remontan (al menos) al intérprete de comandos Thompson de la versión 6.\footnote{El shell de la versión 6 fue escrito por Ken Thompson. Stephen Bourne escribió el intérprete de comandos Bourne para la versión 7.} Pero el intérprete de comandos Korn es el primero en añadir capacidades. Añade un conjunto de operadores, llamados \emph{operadores de expresión regular (o regexp para abreviar)}, que le dan mucho del poder de comparación de cadenas de utilidades Unix avanzadas como \emph{awk(1), egrep(1)} (\emph{grep(1)} extendido), y el editor Emacs, aunque con una sintaxis diferente. Estas capacidades van más allá de aquellas a las que puede estar acostumbrado en otras utilidades Unix como \emph{grep, sed(1)} y \emph{vi(1)}.
Los usuarios avanzados de Unix encontrarán útiles las capacidades de expresión regular del shell Korn para la escritura de scripts, aunque rozan la exageración. (Parte del problema es el inevitable choque sintáctico con la miríada de otros caracteres especiales del shell). Por lo tanto, no entraremos aquí en grandes detalles sobre las expresiones regulares. Para una información más completa, la ''última palabra>> sobre expresiones regulares prácticas en Unix es \emph{Mastering Regular Expressions}, por Jeffrey E. F. Friedl. Una introducción más suave puede encontrarse en la segunda edición de \emph{sed \& awk}, por Dale Dougherty y Arnold Robbins. Ambos están publicados por O'Reilly \& Associates. Si ya se siente cómodo con \emph{awk} o \emph{egrep}, puede saltarse la siguiente sección introductoria y pasar a la \hyperref[sec:4523]{Sección 4.5.2.3}, más adelante en este capítulo, donde explicamos el mecanismo de expresiones regulares del intérprete de órdenes comparándolo con la sintaxis utilizada en esas dos utilidades. De lo contrario, siga leyendo.
Los usuarios avanzados de Unix encontrarán útiles las capacidades de expresión regular del shell de Korn para la escritura de scripts, aunque rozan la exageración. (Parte del problema es el inevitable choque sintáctico con la miríada de otros caracteres especiales del shell). Por lo tanto, no entraremos aquí en grandes detalles sobre las expresiones regulares. Para una información más completa, la <<última palabra>> sobre expresiones regulares prácticas en Unix es \emph{Mastering Regular Expressions}, por Jeffrey E. F. Friedl. Una introducción más suave puede encontrarse en la segunda edición de \emph{sed \& awk}, por Dale Dougherty y Arnold Robbins. Ambos están publicados por O'Reilly \& Associates. Si ya se siente cómodo con \emph{awk} o \emph{egrep}, puede saltarse la siguiente sección introductoria y pasar a la \hyperref[sec:4523]{Sección 4.5.2.3}, más adelante en este capítulo, donde explicamos el mecanismo de expresiones regulares del intérprete de órdenes comparándolo con la sintaxis utilizada en esas dos utilidades. De lo contrario, siga leyendo.
\subsubsection{Conceptos Básicos de Expresiones Regulares}
Piense en las expresiones regulares como cadenas de caracteres que emparejan patrones de forma más potente que el esquema de comodines estándar del shell. Las expresiones regulares surgieron como una idea de la informática teórica, pero han llegado a muchos rincones de la informática práctica cotidiana. La sintaxis utilizada para representarlas puede variar, pero los conceptos son muy parecidos.
@ -744,15 +744,15 @@ Una expresión regular de shell puede contener caracteres regulares, caracteres
\end{tabular}
\end{table}
Como se muestra para el patrón \texttt{@( exp1 | exp2 |...)}, un \emph{exp} dentro de cualquiera de los operadores del shell Korn puede ser una serie de alternativas \emph{exp1|exp2|...}
Como se muestra para el patrón \texttt{@( exp1 | exp2 |...)}, un \emph{exp} dentro de cualquiera de los operadores del shell de Korn puede ser una serie de alternativas \emph{exp1|exp2|...}
Una notación alternativa poco conocida es separar cada exp con el carácter ampersand, \&. En este caso, todas las expresiones alternativas deben coincidir. Piense que | significa <<o>>, mientras que \& significa <<y>>. (De hecho, puede utilizar ambos en la misma lista de patrones. El \& tiene mayor precedencia, con el significado <<coincide con esto y aquello, O coincide con lo siguiente>>). La Tabla \ref{Tab: ejemplos} proporciona algunos ejemplos de uso de los operadores de expresiones regulares del shell.
Una notación alternativa poco conocida es separar cada \emph{exp} con el carácter ampersand, \&. En este caso, todas las expresiones alternativas deben coincidir. Piense que | significa <<o>>, mientras que \& significa <<y>>. (De hecho, puede utilizar ambos en la misma lista de patrones. El \& tiene mayor precedencia, con el significado <<coincide con esto y aquello, O coincide con lo siguiente>>). La Tabla \ref{Tab: ejemplos} proporciona algunos ejemplos de uso de los operadores de expresiones regulares del shell.
\begin{table}[h]
\center
\caption{Ejemplos de operadores de expresiones regulares}
\label{Tab: ejemplos}
\begin{tabular}{|p{2cm}|p{6cm}|} \hline
\begin{tabular}{|p{3cm}|p{6cm}|} \hline
\textbf{Expresión} & \textbf{Coincidencia} \\ \hline
\emph{x} & x \\\hline
\emph{+(x)} & Cadena nula, \texttt{x, xx, xxx, ...} \\\hline
@ -819,11 +819,11 @@ Las tres construcciones deben aparecer dentro de los corchetes de una expresión
\end{tabular}
\end{table}
El shell Korn soporta todas estas características dentro de sus facilidades de concordancia de patrones. Los nombres de clases de caracteres POSIX son los más útiles, porque funcionan en diferentes localizaciones.
El shell de Korn soporta todas estas características dentro de sus facilidades de concordancia de patrones. Los nombres de clases de caracteres POSIX son los más útiles, porque funcionan en diferentes localizaciones.
La siguiente sección compara las expresiones regulares del shell Korn con las características análogas de \emph{awk} y \emph{egrep}. Si no está familiarizado con ellas, vaya a la Sección 4.5.3.
La siguiente sección compara las expresiones regulares del shell de Korn con las características análogas de \emph{awk} y \emph{egrep}. Si no está familiarizado con ellas, vaya a la Sección 4.5.3.
\subsubsection{Korn Shell Versus Expresiones Eegulares awk/egrep}\label{sec:5423}
\subsubsection{Korn Shell Versus Expresiones Regulares awk/egrep}\label{sec:5423}
La Tabla \ref{Tab: operadores} es una expansión de la Tabla \ref{Tab: expresiones}: la columna del medio muestra los equivalentes en \emph{awk/egrep} de los operadores de expresiones regulares del shell.
\begin{table}[h]
@ -862,9 +862,9 @@ Por ejemplo:
\item{\texttt{!(dave|fred|bob)} coincide con cualquier cosa excepto \emph{dave, fred o bob}.}
\end{itemize}
Vale la pena recalcar que las expresiones regulares del shell pueden contener comodines estándar del shell. Así, el comodín del shell \texttt{?} (coincide con cualquier carácter) es equivalente a \texttt{.} en \emph{egrep} o \emph{awk}, y el operador de conjunto de caracteres del shell \texttt{[...]} es el mismo que en esas utilidades.\footnote{Y, para el caso, lo mismo que en grep, sed, ed, vi, etc. Una diferencia notable es que el shell utiliza ! dentro de [...] para la negación, mientras que las distintas utilidades utilizan todas \textasciicircum.} Por ejemplo, la expresión \texttt{+([[:dígito:]])} coincide con un número, es decir, uno o más dígitos. El carácter comodín del shell * es equivalente a la expresión regular del shell \texttt{*(?)}. Incluso puede anidar las expresiones regulares: \texttt{+([[:dígito:]]|!([[:mayúscula:]]))} coincide con uno o más dígitos o letras no mayúsculas.
Vale la pena recalcar que las expresiones regulares del shell pueden contener comodines estándar del shell. Así, el comodín del shell \texttt{?} (coincide con cualquier carácter) es equivalente a \texttt{.} en \emph{egrep} o \emph{awk}, y el operador de conjunto de caracteres del shell \texttt{[...]} es el mismo que en esas utilidades.\footnote{Y, para el caso, lo mismo que en \emph{grep, sed, ed, vi,} etc. Una diferencia notable es que el shell utiliza ! dentro de [...] para la negación, mientras que las distintas utilidades utilizan todas \textasciicircum.} Por ejemplo, la expresión \texttt{+([[:dígito:]])} coincide con un número, es decir, uno o más dígitos. El carácter comodín del shell * es equivalente a la expresión regular del shell \texttt{*(?)}. Incluso puede anidar las expresiones regulares: \texttt{+([[:dígito:]]|!([[:mayúscula:]]))} coincide con uno o más dígitos o letras no mayúsculas.
Dos operadores regexp de x\emph{egrep} y \emph{awk} no tienen equivalentes en el shell Korn:
Dos operadores regexp de x\emph{egrep} y \emph{awk} no tienen equivalentes en el shell de Korn:
\begin{itemize}
\item{Los operadores de principio y fin de línea \textasciicircum y \$.}
@ -874,7 +874,7 @@ Dos operadores regexp de x\emph{egrep} y \emph{awk} no tienen equivalentes en el
Apenas son necesarios, ya que el intérprete de comandos Korn no opera normalmente con archivos de texto y analiza las cadenas en palabras por sí mismo. (Esencialmente, \textasciicircum y \$ están implícitos como si siempre estuvieran ahí. Rodee un patrón con caracteres * para desactivar esto). Siga leyendo para conocer más características de la última versión de \emph{ksh}.
\subsubsection{Coincidencia de Patrones con Expresiones Regulares}
A partir de \emph{ksh93l}, el intérprete de órdenes proporciona una serie de funciones adicionales de expresiones regulares. Las discutimos aquí por separado, porque es muy probable que su versión de \emph{ksh93} no las tenga, a menos que descargue un binario de ksh93 o construya \emph{ksh93} desde el código fuente. Las facilidades se desglosan de la siguiente manera.
A partir de \emph{ksh93l}, el intérprete de órdenes proporciona una serie de funciones adicionales de expresiones regulares. Las discutimos aquí por separado, porque es muy probable que su versión de \emph{ksh93} no las tenga, a menos que descargue un binario de \emph{ksh93} o construya \emph{ksh93} desde el código fuente. Las facilidades se desglosan de la siguiente manera.
\begin{description}
\item[Nuevos operadores de coincidencia de patrones:] Hay varias funciones nuevas de coincidencia de patrones disponibles. Se describen brevemente en la Tabla \ref{Tab: ksh93l}. Más discusión sigue después de la mesa.
@ -885,7 +885,7 @@ A partir de \emph{ksh93l}, el intérprete de órdenes proporciona una serie de f
\begin{table}[h]
\center
\caption{Nuevos operadores de coincidencia de patrones en ksh93l y versiones posteriores}
\caption{Nuevos operadores de coincidencia de patrones en \emph{ksh93l} y versiones posteriores}
\label{Tab: ksh93l}
\begin{tabular}{|m{4cm}|m{10cm}|} \hline
\textbf{Operador} & \textbf{Significado} \\ \hline
@ -935,7 +935,7 @@ Dentro de las expresiones entre paréntesis, \emph{ksh} reconoce todas las secue
¡Uf! Todo esto es bastante embriagador. Si te sientes un poco abrumado, no te preocupes. A medida que aprendas más sobre expresiones regulares y programación en el shell y empieces a realizar tareas de procesamiento de texto cada vez más complejas, llegarás a apreciar el hecho de poder hacer todo esto dentro del propio shell, en lugar de tener que recurrir a programas externos como \texttt{sed, awk} o \emph{perl}.
\subsection{Operadores de Coincidencia de Patrones}
La Tabla \ref{Tab_Op} enumera los operadores de concordancia de patrones del shell Korn.
La Tabla \ref{Tab_Op} enumera los operadores de concordancia de patrones del shell de Korn.
\begin{table}[h]
\center
\caption{Operadores de concordancia de patrones}
@ -967,12 +967,12 @@ El uso clásico de los operadores de concordancia de patrones es la eliminación
Los dos patrones utilizados aquí son \texttt{/*/}, que coincide con cualquier cosa entre dos barras, y \emph{.*}, que coincide con un punto seguido de cualquier cosa.
A partir de ksh93l, estos operadores establecen automáticamente la variable de array \texttt{.sh.match.} Esto se discute en la Sección 4.5.7, más adelante en este capítulo.
A partir de \emph{ksh93l}, estos operadores establecen automáticamente la variable de array \texttt{.sh.match.} Esto se discute en la Sección 4.5.7, más adelante en este capítulo.
Incorporaremos uno de estos operadores en nuestra próxima tarea de programación, \hyperref[box:4-2]{Tarea 4-2}.
\begin{mybox}[Tarea 4-2]\label{box:4-2}
Estás escribiendo un compilador de C, y quieres usar el shell Korn para tu front-end.\footnote{No te rías: antaño, muchos compiladores de Unix tenían shell scripts como interfaz.}
Estás escribiendo un compilador de C, y quieres usar el shell de Korn para tu front-end.\footnote{No te rías: antaño, muchos compiladores de Unix tenían shell scripts como interfaz.}
\end{mybox}
Imagina un compilador de C como una cadena de componentes de procesamiento de datos. El código fuente C se introduce al principio de la tubería, y el código objeto sale al final; hay varios pasos intermedios. La tarea del script de shell, entre otras muchas cosas, es controlar el flujo de datos a través de los componentes y designar los archivos de salida.
@ -1005,7 +1005,7 @@ Esta solución es similar a la primera línea de los ejemplos mostrados anterior
Si usáramos \texttt{\#*/} en lugar de \texttt{\#\#*/}, la expresión tendría el valor incorrecto \texttt{dave/pete/fred/bob}, porque la instancia más corta de <<cualquier cosa seguida de una barra>> al principio de la cadena es sólo una barra (/).
La construcción \texttt{\$\{variable\#\#*/\}} es bastante similar a la utilidad de Unix \emph{basename(1)}. \emph{basename} es menos eficiente que \texttt{\$\{variable\#\#/*\}} porque puede ejecutarse en su propio proceso separado en lugar de dentro del shell.\footnote{basename puede estar incorporado en algunas versiones de ksh93. Por lo tanto, no se garantiza que se ejecute en un proceso separado.} Otra utilidad, \emph{dirname(1)}, hace esencialmente lo contrario que \emph{basename}: devuelve sólo el prefijo del directorio. Es equivalente a la expresión del shell Korn \texttt{\$\{variable\%/*\}} y es menos eficiente por la misma razón.
La construcción \texttt{\$\{variable\#\#*/\}} es bastante similar a la utilidad de Unix \emph{basename(1)}. \emph{basename} es menos eficiente que \texttt{\$\{variable\#\#/*\}} porque puede ejecutarse en su propio proceso separado en lugar de dentro del shell.\footnote{basename puede estar incorporado en algunas versiones de \emph{ksh93}. Por lo tanto, no se garantiza que se ejecute en un proceso separado.} Otra utilidad, \emph{dirname(1)}, hace esencialmente lo contrario que \emph{basename}: devuelve sólo el prefijo del directorio. Es equivalente a la expresión del shell de Korn \texttt{\$\{variable\%/*\}} y es menos eficiente por la misma razón.
\subsection{Operadores de Sustitución de Patrones}
Además de los operadores de concordancia de patrones que eliminan fragmentos de los valores de las variables del shell, puedes hacer sustituciones en esos valores, como en un editor de texto. (De hecho, usando estas facilidades, casi podría escribir un editor de texto en modo línea como un script del shell). Estos operadores están listados en la Tabla \ref{Tab_sust}.
@ -1053,7 +1053,7 @@ $ print $allobs
fred.o dave.o pete.o
\end{lstlisting}
Los patrones pueden ser cualquier expresión de patrón del shell Korn, como se ha comentado anteriormente, y el texto de sustitución puede incluir la notación \textbackslash{} N para obtener el texto que coincida con un sub-patrón.
Los patrones pueden ser cualquier expresión de patrón del shell de Korn, como se ha comentado anteriormente, y el texto de sustitución puede incluir la notación \textbackslash{} N para obtener el texto que coincida con un sub-patrón.
Finalmente, estas operaciones pueden aplicarse a los parámetros posicionales y a los arrays, en cuyo caso se realizan sobre todos los parámetros o elementos del array a la vez. (Las matrices se describen en el capítulo 6.)
@ -1137,7 +1137,7 @@ He aquí algunos ejemplos sencillos:
\item{El valor de \texttt{\$(ls)} son los nombres de todos los archivos del directorio actual, separados por nuevas líneas.}
\item{Para encontrar información detallada sobre un comando si no sabe dónde reside su archivo, escriba \texttt{ls -l \$(whence -p command} ). La opción -p fuerza a whence a hacer una búsqueda por ruta y no considerar palabras clave, built-ins, etc.}
\item{Para obtener el contenido de un archivo en una variable, puede utilizar \texttt{varname=\$(<filename)}. \texttt{\$(cat filename)} hará lo mismo, pero el intérprete de comandos utiliza el primero como una abreviatura incorporada y lo ejecuta de forma más eficiente.}
\item{Si quieres editar (con Emacs) todos los capítulos de tu libro en el shell Korn que tengan la frase <<sustitución de comandos>>, suponiendo que todos tus archivos de capítulos empiecen por ch, podrías escribir:
\item{Si quieres editar (con Emacs) todos los capítulos de tu libro en el shell de Korn que tengan la frase <<sustitución de comandos>>, suponiendo que todos tus archivos de capítulos empiecen por ch, podrías escribir:
\begin{lstlisting}[language=bash]
emacs $(grep -l 'command substitution' ch*.xml)
\end{lstlisting}
@ -1146,11 +1146,11 @@ emacs $(grep -l 'command substitution' ch*.xml)
La sustitución de órdenes, al igual que la expansión de variables, se realiza entre comillas dobles. (Las comillas dobles dentro de la sustitución de comandos no se ven afectadas por las comillas dobles que las encierran). Por lo tanto, nuestra regla en el \hyperref[sec:Chapter1]{Capítulo 1} y el \hyperref[sec:Chapter3]{Capítulo 3} sobre el uso de comillas simples para cadenas a menos que contengan variables se ampliará ahora: <<En caso de duda, use comillas simples, a menos que la cadena contenga variables o sustituciones de comandos, en cuyo caso use comillas dobles>>.
(Por compatibilidad con versiones anteriores, el shell Korn soporta la notación original de sustitución de comandos del shell Bourne (y del shell C) usando comillas inversas: \texttt{`...`}. Sin embargo, es considerablemente más difícil de usar que \texttt{\$(...)}, ya que las comillas y las sustituciones de órdenes anidadas requieren un cuidadoso escape. No utilizamos las comillas traseras en ninguno de los programas de este libro).
(Por compatibilidad con versiones anteriores, el shell de Korn soporta la notación original de sustitución de comandos del shell de Bourne (y del shell C) usando comillas inversas: \texttt{`...`}. Sin embargo, es considerablemente más difícil de usar que \texttt{\$(...)}, ya que las comillas y las sustituciones de órdenes anidadas requieren un cuidadoso escape. No utilizamos las comillas traseras en ninguno de los programas de este libro).
Sin duda se le ocurrirán muchas formas de usar la sustitución de comandos a medida que gane experiencia con el shell Korn. Una que es un poco más compleja que las mencionadas anteriormente se relaciona con una tarea de personalización que vimos en el \hyperref[sec:Chapter3]{Capítulo 3}: personalizar su prompt string.
Sin duda se le ocurrirán muchas formas de usar la sustitución de comandos a medida que gane experiencia con el shell de Korn. Una que es un poco más compleja que las mencionadas anteriormente se relaciona con una tarea de personalización que vimos en el \hyperref[sec:Chapter3]{Capítulo 3}: personalizar su cadena del prompt.
Recuerde que puede personalizar su prompt string asignando un valor a la variable \texttt{PS1}. Si estás en una red de ordenadores, y usas diferentes máquinas de vez en cuando, puede resultarte útil tener el nombre de la máquina en la que estás en tu prompt string. La mayoría de las versiones modernas de Unix tienen el comando \emph{hostname(1)}, que imprime el nombre de red de la máquina en la que se encuentra en la salida estándar. (Si usted no tiene este comando, puede tener uno similar como \emph{uname}.) Este comando le permite obtener el nombre de la máquina en su prompt string poniendo una línea como esta en su \emph{.profile} o archivo de entorno:
Recuerde que puede personalizar su cadena del prompt asignando un valor a la variable \texttt{PS1}. Si estás en una red de ordenadores, y usas diferentes máquinas de vez en cuando, puede resultarte útil tener el nombre de la máquina en la que estás en tu cadena del prompt. La mayoría de las versiones modernas de Unix tienen el comando \emph{hostname(1)}, que imprime el nombre de red de la máquina en la que se encuentra en la salida estándar. (Si usted no tiene este comando, puede tener uno similar como \emph{uname}.) Este comando le permite obtener el nombre de la máquina en su cadena del prompt poniendo una línea como esta en su \emph{.profile} o archivo de entorno:
\begin{lstlisting}[language=bash]
PS1="$(hostname) $ "
@ -1166,7 +1166,7 @@ El fichero utilizado en la \hyperref[box:4-1]{Tarea 4-1} es en realidad un infor
Supongamos que existe una función del shell llamada \emph{getfield} que toma el nombre del campo como argumento y escribe el número de campo correspondiente en la salida estándar. Utilice esta rutina para extraer una columna de la tabla de datos.
\end{mybox}
La utilidad \emph{cut(1)} es ideal para esta tarea. \emph{cut} es un filtro de datos: extrae columnas de datos tabulares.\footnote{Algunos sistemas muy antiguos derivados de BSD no tienen cut, pero puedes usar awk en su lugar. Siempre que veas un comando de la forma cut -f N -d C nombrearchivo, usa esto en su lugar: \texttt{awk -F C '\{print \$ N\}' filename}.} Si proporciona el número de columnas que desea extraer de la entrada, cut imprime sólo esas columnas en la salida estándar. Las columnas pueden ser posiciones de caracteres o - relevante en este ejemplo - campos que están separados por caracteres TAB u otros delimitadores.
La utilidad \emph{cut(1)} es ideal para esta tarea. \emph{cut} es un filtro de datos: extrae columnas de datos tabulares.\footnote{Algunos sistemas muy antiguos derivados de BSD no tienen \emph{cut}, pero puedes usar \emph{awk} en su lugar. Siempre que veas un comando de la forma texttt{cut -f N -d C nombrearchivo}, usa esto en su lugar: \texttt{awk -F C '\{print \$ N\}' filename}.} Si proporciona el número de columnas que desea extraer de la entrada, \emph{cut} imprime sólo esas columnas en la salida estándar. Las columnas pueden ser posiciones de caracteres o - relevante en este ejemplo - campos que están separados por caracteres TAB u otros delimitadores.
Supongamos que la tabla de datos de nuestra tarea es un fichero llamado \emph{albums} y que tiene el siguiente aspecto:
@ -1258,7 +1258,7 @@ function lsd {
Esta función depende de la disposición de las columnas del comando \emph{ls -l}. En particular, depende de que las fechas empiecen en la columna 42 y los nombres de fichero empiecen en la columna 55. Si este no es el caso en tu versión de Unix, necesitarás ajustar los números de columna \footnote{Por ejemplo, \texttt{ls -l} en GNU/Linux tiene fechas que comienzan en la columna 43 y nombres de archivo que comienzan en la columna 57.}.
Usamos la utilidad de búsqueda \emph{grep} para hacer coincidir la fecha dada como argumento (en la forma \emph{Mon DD}, por ejemplo, \texttt{Jan 15} u \texttt{Oct 6}, este último con dos espacios) con la salida de \texttt{ls -l}. (El argumento de expresión regular para grep se entrecomilla con comillas dobles, para realizar la sustitución de variables). Esto nos da un largo listado de sólo aquellos ficheros cuyas fechas coinciden con el argumento. La opción \emph{-i} de \emph{grep} le permite utilizar todas las letras minúsculas en el nombre del mes, mientras que el argumento bastante extravagante significa: <<Coincidir con cualquier línea que contenga 41 caracteres seguidos del argumento de la función>>. Por ejemplo, si se escribe \texttt{lsd 'jan 15'}, \emph{grep} buscará las líneas que contengan 41 caracteres seguidos de \texttt{jan 15} (o \texttt{Jan 15}).
Usamos la utilidad de búsqueda \emph{grep} para hacer coincidir la fecha dada como argumento (en la forma \emph{Mon DD}, por ejemplo, \texttt{Jan 15} u \texttt{Oct 6}, este último con dos espacios) con la salida de \texttt{ls -l}. (El argumento de expresión regular para \emph{grep} se entrecomilla con comillas dobles, para realizar la sustitución de variables). Esto nos da un largo listado de sólo aquellos ficheros cuyas fechas coinciden con el argumento. La opción \emph{-i} de \emph{grep} le permite utilizar todas las letras minúsculas en el nombre del mes, mientras que el argumento bastante extravagante significa: <<Coincidir con cualquier línea que contenga 41 caracteres seguidos del argumento de la función>>. Por ejemplo, si se escribe \texttt{lsd 'jan 15'}, \emph{grep} buscará las líneas que contengan 41 caracteres seguidos de \texttt{jan 15} (o \texttt{Jan 15}).
La salida de \emph{grep} se canaliza a través de nuestro omnipresente amigo \emph{cut} para recuperar sólo los nombres de archivo. El argumento para \emph{cut} le dice que extraiga los caracteres de la columna 55 hasta el final de la línea.
@ -1274,16 +1274,16 @@ La salida de \emph{lsd} está en múltiples líneas (una por cada nombre de fich
Concluimos este capítulo con un par de funciones que puedes encontrar útiles en tu uso diario de Unix. Resuelven el problema presentado por la \hyperref[box:4-7]{Tarea 4-7}.
\begin{mybox}[Tarea 4-7]\label{box:4-7}
En el shell C, los comandos pushd y popd implementan una pila de directorios que le permiten moverse a otro directorio temporalmente y que el shell recuerde dónde estaba. El comando dirs imprime la pila. El shell Korn no proporciona estos comandos. Impleméntelos como funciones del shell.
En el shell C, los comandos \emph{pushd} y \emph{popd} implementan una pila de directorios que le permiten moverse a otro directorio temporalmente y que el shell recuerde dónde estaba. El comando \emph{dirs} imprime la pila. El shell de Korn no proporciona estos comandos. Impleméntelos como funciones del shell.
\end{mybox}
Comenzamos implementando un subconjunto significativo de sus capacidades y terminamos la implementación en el \hyperref[sec:Chapter6]{Capítulo 6}. (Para facilitar el desarrollo y la explicación, nuestra implementación ignora algunas cosas que una versión más a prueba de balas debería manejar. Por ejemplo, los espacios en los nombres de archivo harán que las cosas se rompan).
Si no sabe lo que es una pila, piense en un receptáculo de platos accionado por un muelle en una cafetería. Al colocar los platos en el recipiente, el muelle se comprime para que la parte superior se mantenga más o menos al mismo nivel. El plato colocado más recientemente en la pila es el primero que se coge cuando alguien quiere comida; por eso, la pila se conoce como una estructura de ''último en entrar, primero en salir>> o \emph{LIFO}. (Las víctimas de una recesión o de adquisiciones de empresas también reconocerán este mecanismo en el contexto de las políticas de despido de las empresas). Poner algo en una pila se conoce en informática como \emph{pushing}, y quitar algo de la parte superior se llama \emph{popping}.
Si no sabe lo que es una pila, piense en un receptáculo de platos accionado por un muelle en una cafetería. Al colocar los platos en el recipiente, el muelle se comprime para que la parte superior se mantenga más o menos al mismo nivel. El plato colocado más recientemente en la pila es el primero que se coge cuando alguien quiere comida; por eso, la pila se conoce como una estructura de <<último en entrar, primero en salir>> o \emph{LIFO}. (Las víctimas de una recesión o de adquisiciones de empresas también reconocerán este mecanismo en el contexto de las políticas de despido de las empresas). Poner algo en una pila se conoce en informática como \emph{pushing}, y quitar algo de la parte superior se llama \emph{popping}.
Una pila es muy útil para recordar directorios, como veremos; puede <<mantener su lugar>> hasta un número arbitrario de veces. La forma \texttt{cd -} del comando \emph{cd} hace esto, pero sólo a un nivel. Por ejemplo: si estás en \emph{firstdir} y luego cambias a \emph{seconddir}, puedes escribir \texttt{cd -} para volver. Pero si empiezas en \emph{firstdir}, luego cambias a \emph{seconddir}, y luego vas a \emph{thirddir}, puedes usar \texttt{cd -} sólo para volver a \emph{seconddir}. Si escribes \texttt{cd -} de nuevo, volverás a \emph{thirddir}, porque es el directorio anterior\footnote{Piense en \texttt{cd -} como sinónimo de \texttt{cd \$OLDPWD}; véase el capítulo anterior.}.
Si quieres la funcionalidad <<anidada>> de recordar-y-cambiar que te llevará de vuelta a \emph{firstdir}, necesitas una pila de directorios junto con los comandos \emph{dirs, pushd} y \emph{popd}. Así es como funcionan:\footnote{Aquí lo hemos hecho de forma diferente al shell C. El shell C pushd empuja primero el directorio inicial a la pila, seguido del argumento del comando. El shell C popd elimina el directorio superior de la pila, revelando un nuevo directorio superior. A continuación, cds al nuevo directorio superior. Creemos que este comportamiento es menos intuitivo que nuestro diseño aquí.}
Si quieres la funcionalidad <<anidada>> de recordar-y-cambiar que te llevará de vuelta a \emph{firstdir}, necesitas una pila de directorios junto con los comandos \emph{dirs, pushd} y \emph{popd}. Así es como funcionan:\footnote{Aquí lo hemos hecho de forma diferente al shell C. El shell C \emph{pushd} empuja primero el directorio inicial a la pila, seguido del argumento del comando. El shell C \emph{popd} elimina el directorio superior de la pila, revelando un nuevo directorio superior. A continuación, \emph{cds} al nuevo directorio superior. Creemos que este comportamiento es menos intuitivo que nuestro diseño aquí.}
\begin{itemize}
\item{\texttt{pushd dir} hace un \texttt{cd} a \texttt{dir} y luego empuja \emph{dir} a la pila.}
@ -1347,9 +1347,9 @@ La tercera línea de la función introduce el nuevo directorio en la pila. La ex
La última línea simplemente imprime el contenido de la pila, con la implicación de que el directorio situado más a la izquierda es el directorio actual y el primero de la pila. (Esta es la razón por la que elegimos espacios para separar los directorios, en lugar de los más habituales dos puntos como en \texttt{PATH} y \texttt{MAILPATH}).
La función \emph{popd} hace otro uso de los operadores de coincidencia de patrones del shell. La primera línea utiliza el operador \%\%, que elimina la coincidencia más larga de '' *'' (un espacio seguido de cualquier cosa). Esto elimina todo menos la parte superior de la pila. El resultado se guarda en la variable \texttt{top}, de nuevo por razones de legibilidad.
La función \emph{popd} hace otro uso de los operadores de coincidencia de patrones del shell. La primera línea utiliza el operador \%\%, que elimina la coincidencia más larga de << *>> (un espacio seguido de cualquier cosa). Esto elimina todo menos la parte superior de la pila. El resultado se guarda en la variable \texttt{top}, de nuevo por razones de legibilidad.
La segunda línea es similar, pero va en la otra dirección. Utiliza el operador \#, que intenta borrar la coincidencia más corta del patrón ''* '' (cualquier cosa seguida de un espacio) del valor de \texttt{DIRSTACK}. El resultado es que el directorio superior (y el espacio que le sigue) se borra de la pila.
La segunda línea es similar, pero va en la otra dirección. Utiliza el operador \#, que intenta borrar la coincidencia más corta del patrón <<* >> (cualquier cosa seguida de un espacio) del valor de \texttt{DIRSTACK}. El resultado es que el directorio superior (y el espacio que le sigue) se borra de la pila.
La tercera línea en realidad cambia el directorio a la parte superior anterior de la pila. (Tenga en cuenta que a \emph{popd} no le importa dónde se encuentre cuando lo ejecute; si su directorio actual es el que está en la parte superior de la pila, no irá a ninguna parte). La línea final sólo imprime un mensaje de confirmación.

View File

@ -1,12 +1,12 @@
Si es programador, puede que haya leído el último capítulo -- con su afirmación al principio de que el shell Korn tiene un conjunto avanzado de capacidades de programación -- y se haya preguntado dónde están muchas características de los lenguajes convencionales. Tal vez el <<agujero>> más obvio en nuestra cobertura hasta ahora se refiere a las construcciones de \emph{control de flujo} como \texttt{if, for, while,} etcétera.
Si es programador, puede que haya leído el último capítulo -- con su afirmación al principio de que el shell de Korn tiene un conjunto avanzado de capacidades de programación -- y se haya preguntado dónde están muchas características de los lenguajes convencionales. Tal vez el <<agujero>> más obvio en nuestra cobertura hasta ahora se refiere a las construcciones de \emph{control de flujo} como \texttt{if, for, while,} etcétera.
El control de flujo da a un programador el poder de especificar que sólo se ejecuten ciertas partes de un programa, o que ciertas partes se ejecuten repetidamente, según condiciones como los valores de las variables, si los comandos se ejecutan correctamente o no, y otras. Llamamos a esto la capacidad de controlar el flujo de ejecución de un programa.
Casi todos los scripts o funciones de shell mostrados hasta ahora no han tenido control de flujo -- ¡sólo han sido listas de comandos a ejecutar! Sin embargo, el shell Korn, como los shells C y Bourne, tiene todas las capacidades de control de flujo que cabría esperar y más; las examinaremos en este capítulo. Las usaremos para mejorar las soluciones a algunas de las tareas de programación que vimos en el último capítulo y para resolver tareas que introducimos aquí.
Casi todos los scripts o funciones de shell mostrados hasta ahora no han tenido control de flujo -- ¡sólo han sido listas de comandos a ejecutar! Sin embargo, el shell de Korn, como los shells C y Bourne, tiene todas las capacidades de control de flujo que cabría esperar y más; las examinaremos en este capítulo. Las usaremos para mejorar las soluciones a algunas de las tareas de programación que vimos en el último capítulo y para resolver tareas que introducimos aquí.
Aunque hemos intentado explicar el control de flujo para que los no programadores puedan entenderlo, también simpatizamos con los programadores que temen tener que pasar por otra explicación tabula rasa. Por esta razón, algunas de nuestras discusiones relacionan los mecanismos de control de flujo del shell Korn con aquellos que los programadores ya deberían conocer. Por lo tanto, estará en una mejor posición para entender este capítulo si ya tiene un conocimiento básico de los conceptos de control de flujo.
Aunque hemos intentado explicar el control de flujo para que los no programadores puedan entenderlo, también simpatizamos con los programadores que temen tener que pasar por otra explicación tabula rasa. Por esta razón, algunas de nuestras discusiones relacionan los mecanismos de control de flujo del shell de Korn con aquellos que los programadores ya deberían conocer. Por lo tanto, estará en una mejor posición para entender este capítulo si ya tiene un conocimiento básico de los conceptos de control de flujo.
El shell Korn soporta las siguientes construcciones de control de flujo:
El shell de Korn soporta las siguientes construcciones de control de flujo:
\begin{itemize}
\item{\texttt{if/else} Ejecuta una lista de sentencias si una determinada condición es/no es verdadera.}
@ -16,7 +16,7 @@ El shell Korn soporta las siguientes construcciones de control de flujo:
\item{\texttt{case} Ejecuta una de varias listas de sentencias en función del valor de una variable.}
\end{itemize}
Además, el shell Korn proporciona un nuevo tipo de construcción de control de flujo:
Además, el shell de Korn proporciona un nuevo tipo de construcción de control de flujo:
\begin{itemize}
\item{\texttt{select} Permitir al usuario seleccionar una de una lista de posibilidades de un menú.}
\end{itemize}
@ -24,9 +24,9 @@ Además, el shell Korn proporciona un nuevo tipo de construcción de control de
Cubriremos cada uno de ellos, pero le advertimos: la sintaxis es inusual.
\section{if/else}
El tipo más simple de construcción de control de flujo es el condicional, encarnado en la sentencia if del shell Korn. Se usa un condicional cuando se quiere elegir si hacer o no hacer algo, o elegir entre un pequeño número de cosas a hacer, de acuerdo con la verdad o falsedad de las condiciones. Las condiciones comprueban los valores de las variables del shell, las características de los archivos, si los comandos se ejecutan correctamente o no, y otros factores. El shell tiene un gran conjunto de pruebas incorporadas que son relevantes para la tarea de programación del shell.
El tipo más simple de construcción de control de flujo es el condicional, encarnado en la sentencia \emph{if} del shell de Korn. Se usa un condicional cuando se quiere elegir si hacer o no hacer algo, o elegir entre un pequeño número de cosas a hacer, de acuerdo con la verdad o falsedad de las condiciones. Las condiciones comprueban los valores de las variables del shell, las características de los archivos, si los comandos se ejecutan correctamente o no, y otros factores. El shell tiene un gran conjunto de pruebas incorporadas que son relevantes para la tarea de programación del shell.
La construcción if tiene la siguiente sintaxis:
La construcción \emph{if} tiene la siguiente sintaxis:
\begin{lstlisting}[language=bash]
if <condicion>
then
@ -38,7 +38,7 @@ then
fi
\end{lstlisting}
La forma más sencilla (sin las partes \texttt{elif} y \texttt{else}, también conocidas como cláusulas) ejecuta las \emph{sentencias} sólo si la \emph{condición} es verdadera. Si añade una cláusula \texttt{else}, podrá ejecutar un conjunto de sentencias si la condición es verdadera u otro conjunto de sentencias si la condición es falsa. Puede utilizar tantas cláusulas \texttt{elif} (contracción de <<else if>>) como desee; introducen más condiciones y, por lo tanto, más opciones para el conjunto de sentencias a ejecutar. Si utiliza una o más cláusulas \texttt{elif}, puede considerar la cláusula \texttt{else} como la parte <<si todo lo demás falla>>.
La forma más sencilla (sin las partes \texttt{elif} y \texttt{else}, también conocidas como cláusulas) ejecuta las \emph{sentencias} sólo si la \emph{condición} es verdadera. Si añade una cláusula \texttt{else}, podrá ejecutar un conjunto de sentencias si la condición es verdadera u otro conjunto de sentencias si la condición es falsa. Puede utilizar tantas cláusulas \texttt{elif} (contracción de \emph{else if}) como desee; introducen más condiciones y, por lo tanto, más opciones para el conjunto de sentencias a ejecutar. Si utiliza una o más cláusulas \texttt{elif}, puede considerar la cláusula \texttt{else} como la parte <<si todo lo demás falla>>.
\subsection{Estado de salida y retorno}
Quizá el único aspecto de esta sintaxis que difiere de la de lenguajes convencionales como C y Pascal es que la <<condición>> es en realidad una lista de sentencias en lugar de la expresión booleana (verdadero o falso) más habitual. ¿Cómo se determina la veracidad o falsedad de la condición? Tiene que ver con un concepto general de Unix que aún no hemos tratado: el \emph{estado de salida} de los comandos.
@ -73,7 +73,7 @@ function pushd { # empuja el directorio actual a la pila
Esta función ahora verifica si el argumento es un nombre de directorio válido antes de intentar cambiar al directorio y agregarlo a la pila. Si el nombre de directorio no es válido, imprime un mensaje de error.
Sin embargo, la función reacciona de manera engañosa cuando se proporciona un argumento que no es un directorio válido. En caso de que no lo hayas entendido al leer el último capítulo, aquí está lo que sucede: el comando `cd` falla, dejándote en el mismo directorio en el que estabas. Esto también es apropiado. Pero luego, la tercera línea de código empuja el directorio incorrecto a la pila de todos modos, y la última línea imprime un mensaje que te hace creer que la operación fue exitosa.
Sin embargo, la función reacciona de manera engañosa cuando se proporciona un argumento que no es un directorio válido. En caso de que no lo hayas entendido al leer el último capítulo, aquí está lo que sucede: el comando \emph{cd} falla, dejándote en el mismo directorio en el que estabas. Esto también es apropiado. Pero luego, la tercera línea de código empuja el directorio incorrecto a la pila de todos modos, y la última línea imprime un mensaje que te hace creer que la operación fue exitosa.
Necesitamos evitar que el directorio incorrecto se agregue a la pila e imprimir un mensaje de error. Aquí tienes cómo podemos hacer esto:
@ -164,7 +164,7 @@ function cd {
Esta función se basa en el orden de búsqueda de los comandos enumerados en el último capítulo. \emph{cd} es un comando incorporado no especial, lo que significa que se encuentra \emph{después} de las funciones. Por lo tanto, podemos nombrar nuestra función \emph{cd}, y el shell la encontrará primero.
¿Pero cómo llegamos al <<verdadero>> comando \emph{cd}? Lo necesitamos para cambiar de directorio. La respuesta es el comando incorporado llamado, curiosamente, \emph{command}. Su trabajo es hacer exactamente lo que necesitamos: omitir cualquier función nombrada por el primer argumento, en su lugar encontrar el comando incorporado o externo y ejecutarlo con los argumentos suministrados. En el shell Korn, el uso de \emph{command} seguido de uno de los comandos incorporados especiales evita que los errores en ese comando aborten el script. (Esto resulta ser un mandato de POSIX).
¿Pero cómo llegamos al <<verdadero>> comando \emph{cd}? Lo necesitamos para cambiar de directorio. La respuesta es el comando incorporado llamado, curiosamente, \emph{command}. Su trabajo es hacer exactamente lo que necesitamos: omitir cualquier función nombrada por el primer argumento, en su lugar encontrar el comando incorporado o externo y ejecutarlo con los argumentos suministrados. En el shell de Korn, el uso de \emph{command} seguido de uno de los comandos incorporados especiales evita que los errores en ese comando aborten el script. (Esto resulta ser un mandato de POSIX).
\textbf{ADVERTENCIA:} El comando incorporado \emph{command} no es especial. Si defines una función llamada \emph{command}, ya no hay forma de llegar al real (excepto eliminando la función, por supuesto).
@ -195,7 +195,7 @@ Para \emph{ksh93}, los valores de estado de salida para los comandos incorporado
Las señales son una función más avanzada; se describen en el \hyperref[sec:Chapter8]{Capítulo 8}.
\subsection{Combinaciones de estado de salida}\label{sec:5.1.2}
Una de las partes más oscuras de la sintaxis del shell Korn le permite combinar estados de salida de forma lógica, de modo que pueda probar más de una cosa a la vez.
Una de las partes más oscuras de la sintaxis del shell de Korn le permite combinar estados de salida de forma lógica, de modo que pueda probar más de una cosa a la vez.
La sintaxis \emph{statement1 \&\& statement2} significa, <<ejecuta statement1, y si su estado de salida es 0, ejecuta statement2>>. La sintaxis \emph{statement1 || statement2} es la inversa: significa <<ejecuta la sentencia1, y si su estado de salida no es 0, ejecuta la sentencia2>>.
@ -248,7 +248,7 @@ then
fi
\end{lstlisting}
Una nota menor: cuando se usan con comandos, \&\& y || tienen la misma precedencia. Sin embargo, cuando se usan dentro de [[...]] (de lo que hablaremos en breve), \&\& tiene mayor precedencia que ||.
Una nota menor: cuando se usan con comandos, \texttt{\&\&} y \texttt{||} tienen la misma precedencia. Sin embargo, cuando se usan dentro de \texttt{[[...]]} (de lo que hablaremos en breve), \texttt{\&\&} tiene mayor precedencia que \texttt{||}.
Veremos más ejemplos de estos operadores lógicos más adelante en este capítulo y en el código para el depurador \emph{kshdb} en el \hyperref[sec:Chapter9]{Capítulo 9}.
@ -264,7 +264,7 @@ else
fi
\end{lstlisting}
El comando \emph{:} no hace nada. El significado, entonces, es <<si palabra1 o palabra2 están presentes en nombre de fichero, no hagas nada; si no, imprime un mensaje>>. El shell Korn le permite hacer esto de forma más elegante utilizando la palabra clave ! (introducida en POSIX): t
El comando \emph{:} no hace nada. El significado, entonces, es <<si palabra1 o palabra2 están presentes en nombre de fichero, no hagas nada; si no, imprime un mensaje>>. El shell de Korn le permite hacer esto de forma más elegante utilizando la palabra clave ! (introducida en POSIX): t
\begin{lstlisting}[language=bash]
filename=$1
@ -279,11 +279,11 @@ fi
\subsection{Pruebas de estado}
Los estados de salida son las únicas cosas que una construcción \texttt{if} puede comprobar. Pero eso no significa que sólo pueda comprobar si los comandos se ejecutaron correctamente o no. El shell proporciona una forma de probar una variedad de condiciones con la construcción \texttt{[[...]]}.
\footnote{El shell Korn también acepta los comandos \texttt{[...]} y \emph{test}. (Hay comandos incorporados en todas las versiones de \emph{ksh}; se comportan como las versiones externas originales). La construcción \texttt{[[...]]} tiene muchas más opciones y está mejor integrada en el lenguaje del shell Korn: específicamente, la división de palabras y la expansión de comodines no se hacen dentro de \texttt{[[} y \texttt{]]}, haciendo las citas menos necesarias. Además, siempre puede distinguir los operadores de los operandos, ya que los operadores no pueden ser el resultado de la expansión.}
\footnote{El shell de Korn también acepta los comandos \texttt{[...]} y \emph{test}. (Hay comandos incorporados en todas las versiones de \emph{ksh}; se comportan como las versiones externas originales). La construcción \texttt{[[...]]} tiene muchas más opciones y está mejor integrada en el lenguaje del shell de Korn: específicamente, la división de palabras y la expansión de comodines no se hacen dentro de \texttt{[[} y \texttt{]]}, haciendo las citas menos necesarias. Además, siempre puede distinguir los operadores de los operandos, ya que los operadores no pueden ser el resultado de la expansión.}
Puede utilizar la construcción para comprobar muchos atributos diferentes de un archivo (si existe, qué tipo de archivo es, cuáles son sus permisos y propiedad, etc.), comparar dos archivos para ver cuál es más nuevo, hacer comparaciones y coincidencias de patrones en cadenas, y mucho más.
\texttt{[[ condición ]]} es en realidad una sentencia como cualquier otra, salvo que lo único que hace es devolver un estado de salida que indica si la condición es verdadera. Por lo tanto, encaja dentro de la sintaxis de las sentencias if de la construcción if.
\texttt{[[ condición ]]} es en realidad una sentencia como cualquier otra, salvo que lo único que hace es devolver un estado de salida que indica si la condición es verdadera. Por lo tanto, encaja dentro de la sintaxis de las sentencias \emph{if} de la construcción \emph{if}.
\subsubsection{Comparación de cadenas}
Los corchetes dobles (\texttt{[[...]]}) rodean expresiones que incluyen varios tipos de \emph{operadores}. Empezaremos con los operadores de comparación de cadenas, que se enumeran en la Tabla \ref{Tab: 5.2}. (Observe que no hay operadores para <<mayor o igual>> o <<menor o igual>>. (Observe que no hay operadores para <<mayor que o igual>> o <<menor que o igual>>). En la tabla, \emph{str} se refiere a una expresión con un valor de cadena, y \emph{pat} se refiere a un patrón que puede contener comodines (igual que los patrones en los operadores de manejo de cadenas que vimos en el capítulo anterior). Tenga en cuenta que estos operadores comparan los valores lexicográficos de las cadenas, por lo que ``10'' < ``2''.
@ -349,9 +349,9 @@ if [[ $DIRSTACK == "" ]]; then
\textbf{[[...]] vs el comando \emph{test} y [...]} \\
Escribimos nuestra prueba \texttt{[[ \$DIRSTACK == '''' ]]}. Este no es el uso correcto para la sintaxis más antigua \texttt{[...]} o \emph{test}.
En esta sintaxis, que el shell Korn todavía soporta, y que es todo lo que tiene en el shell Bourne, si \texttt{\$DIRSTACK} se evalúa como una cadena nula, el shell se quejará de que falta un argumento. Esto lleva al requisito de encerrar ambas cadenas entre comillas dobles (\texttt{[ ''\$DIRSTACK>> = '''' ]}), que es la forma más legible de hacerlo, o al truco común de añadir un carácter extra delante de las cadenas, como así: \texttt{[ x\$DIRSTACK = x ]}. Esto último funciona, ya que si \texttt{\$DIRSTACK} es nulo, el comando \texttt{[...]} sólo ve los dos caracteres \texttt{x}, pero no es muy obvio lo que está pasando, especialmente para el novato.
En esta sintaxis, que el shell de Korn todavía soporta, y que es todo lo que tiene en el shell de Bourne, si \texttt{\$DIRSTACK} se evalúa como una cadena nula, el shell se quejará de que falta un argumento. Esto lleva al requisito de encerrar ambas cadenas entre comillas dobles (\texttt{[ ''\$DIRSTACK>> = '''' ]}), que es la forma más legible de hacerlo, o al truco común de añadir un carácter extra delante de las cadenas, como así: \texttt{[ x\$DIRSTACK = x ]}. Esto último funciona, ya que si \texttt{\$DIRSTACK} es nulo, el comando \texttt{[...]} sólo ve los dos caracteres \texttt{x}, pero no es muy obvio lo que está pasando, especialmente para el novato.
Tenga en cuenta también que el operador preferido del shell Korn es \texttt{==}, mientras que test requiere un único carácter \texttt{=}.
Tenga en cuenta también que el operador preferido del shell de Korn es \texttt{==}, mientras que test requiere un único carácter \texttt{=}.
\end{mybox}
Mientras limpiamos el código que escribimos en el último capítulo, corrijamos el manejo de errores en el script principal (\hyperref[box:4-1]{Tarea 4-1}). El código de ese script es:
@ -401,7 +401,7 @@ Aunque mucha gente considera que el lenguaje ensamblador es algo pintorescamente
La otra tarea de la que nos ocuparemos se llama enlazado. La mayoría de los programas del mundo real, a diferencia de los asignados a una clase de programación de primer curso, constan de varios archivos de código fuente, posiblemente escritos por varios programadores diferentes. Estos archivos se compilan en código objeto; después, el código objeto debe combinarse para formar el programa final ejecutable. La tarea de combinar suele denominarse <<enlazar>>: cada componente del código objeto suele contener referencias a otros componentes, y estas referencias deben resolverse o <<enlazarse>> entre sí.
Los sistemas de compilación C son capaces de ensamblar archivos de lenguaje ensamblador en código objeto y enlazar archivos de código objeto en ejecutables. En concreto, un compilador llama a un ensamblador independiente para que se ocupe del código ensamblador y a un enlazador (también conocido como <<cargador>>, <<cargador de enlace>> o <<editor de enlace>>) para que se ocupe de los archivos de código objeto. Estas herramientas separadas se conocen en el mundo Unix como \emph{as} y \emph{ld}, respectivamente. El compilador de C propiamente dicho se invoca con el comando cc.
Los sistemas de compilación C son capaces de ensamblar archivos de lenguaje ensamblador en código objeto y enlazar archivos de código objeto en ejecutables. En concreto, un compilador llama a un ensamblador independiente para que se ocupe del código ensamblador y a un enlazador (también conocido como <<cargador>>, <<cargador de enlace>> o <<editor de enlace>>) para que se ocupe de los archivos de código objeto. Estas herramientas separadas se conocen en el mundo Unix como \emph{as} y \emph{ld}, respectivamente. El compilador de C propiamente dicho se invoca con el comando \emph{cc}.
Podemos expresar todos estos pasos en términos de los sufijos de los archivos pasados como argumentos al compilador de C. Básicamente, el compilador hace lo siguiente:
@ -457,7 +457,7 @@ El otro tipo de operador que puede utilizarse en expresiones condicionales compr
\texttt{-d \emph{file}} & \emph{file} es un directorio \\
\texttt{-f \emph{file}} & \emph{file} es un archivo regular (por ejemplo, no un directorio u otro tipo especial de archivo) \\
\texttt{-L \emph{file}} & \emph{file} es un enlace simbólico \\
\texttt{-r \emph{file}} & Tienepermisos de lectura en \emph{file} \\
\texttt{-r \emph{file}} & Tiene permisos de lectura en \emph{file} \\
\texttt{-s \emph{file}} & \emph{file} existe y no está vacío \\
\texttt{-w \emph{file}} & Tiene permisos de escritura en \emph{file} \\
\texttt{-x \emph{file}} & Tienes permiso de ejecución sobre \emph{file} o permiso de búsqueda de directorio si es un directorio \\
@ -544,7 +544,7 @@ Llamaremos a este script \emph{fileinfo}. Así es como funciona:
\item{La primera condicional comprueba si el archivo dado como argumento no existe (el signo de exclamación es el operador <<not>>; los espacios que lo rodean son obligatorios). Si el fichero no existe, el script imprime un mensaje de error y sale con el estado de error.}
\item{La segunda condicional comprueba si el fichero es un directorio. Si es así, la primera imprime parte de un mensaje; recuerde que la opción \emph{-n} indica a \emph{print} que no imprima una nueva línea al final. La condicional interna comprueba si no tienes permiso de búsqueda en el directorio. Si no tiene permiso de búsqueda, se añade la palabra <<not>> al mensaje parcial. A continuación, el mensaje se completa con <<search>> y una nueva línea. }
\item{La cláusula \texttt{elif} comprueba si el fichero es un fichero normal; en caso afirmativo, imprime un mensaje.}
\item{La cláusula else tiene en cuenta los distintos tipos de ficheros especiales de los sistemas Unix recientes, como sockets, dispositivos, ficheros FIFO, etc. Asumimos que el usuario ocasional no está interesado en sus detalles.}
\item{La cláusula \emph{else} tiene en cuenta los distintos tipos de ficheros especiales de los sistemas Unix recientes, como sockets, dispositivos, ficheros FIFO, etc. Asumimos que el usuario ocasional no está interesado en sus detalles.}
\item{La siguiente condicional comprueba si eres el propietario del fichero (es decir, si su ID de propietario es el mismo que tu ID de usuario efectivo). Si es así, imprime un mensaje diciendo que usted es el propietario. (Los ID reales y efectivos de Usuario y Grupo se explican en el Capítulo 10.) }
\item{Las dos condiciones siguientes comprueban sus permisos de lectura y escritura sobre el fichero.}
\item{La última condicional comprueba si puedes ejecutar el fichero. Comprueba si tiene permiso de ejecución y si el fichero no es un directorio. (Si el archivo fuera un directorio, el permiso de ejecución significaría realmente el permiso de búsqueda de directorio).}
@ -569,7 +569,7 @@ you have write permission on the file.
you have execute permission on the file.
\end{lstlisting}
Al escribir fileinfo \texttt{custom.tbl} se obtiene lo siguiente:
Al escribir \emph{fileinfo} \texttt{custom.tbl} se obtiene lo siguiente:
\begin{lstlisting}[language=bash]
custom.tbl is a regular file.
@ -621,11 +621,11 @@ De hecho, parte de la documentación de \emph{ksh93} considera obsoletas estas c
\section{for}
La mejora más obvia que podríamos hacer al script anterior es la capacidad de informar sobre varios archivos en lugar de sólo uno. Pruebas como \emph{-e} y \emph{-d} sólo toman argumentos individuales, por lo que necesitamos una manera de llamar al código una vez para cada archivo dado en la línea de comandos.
La forma de hacer esto -- de hecho, la forma de hacer muchas cosas con el shell Korn -- es con una construcción de bucle. La más simple y ampliamente aplicable de las construcciones de bucle del shell es el bucle \texttt{for}. Usaremos \texttt{for} para mejorar \emph{fileinfo} pronto.
La forma de hacer esto -- de hecho, la forma de hacer muchas cosas con el shell de Korn -- es con una construcción de bucle. La más simple y ampliamente aplicable de las construcciones de bucle del shell es el bucle \texttt{for}. Usaremos \texttt{for} para mejorar \emph{fileinfo} pronto.
El bucle for le permite repetir una sección de código un número fijo de veces. Durante cada vez que se repite el código (conocido como iteración), una variable especial llamada \emph{variable de bucle} se establece a un valor diferente; de esta forma cada iteración puede hacer algo ligeramente diferente.
El bucle for es algo, pero no totalmente, similar a sus homólogos en lenguajes convencionales como C y Pascal. La principal diferencia es que el bucle for del shell no le permite especificar un número de veces para iterar o un rango de valores sobre los que iterar; en su lugar, sólo le permite dar una lista fija de valores. En otras palabras, con el bucle for normal, no puedes hacer nada como este código tipo Pascal, que ejecuta las sentencias 10 veces:
El bucle \emph{fo}r es algo, pero no totalmente, similar a sus homólogos en lenguajes convencionales como C y Pascal. La principal diferencia es que el bucle \emph{for} del shell no le permite especificar un número de veces para iterar o un rango de valores sobre los que iterar; en su lugar, sólo le permite dar una lista fija de valores. En otras palabras, con el bucle \emph{for} normal, no puedes hacer nada como este código tipo Pascal, que ejecuta las sentencias 10 veces:
\begin{lstlisting}[language=bash]
for x := 1 to 10 do
@ -634,9 +634,9 @@ begin
end
\end{lstlisting}
(Para ello necesitas el bucle aritmético for, que veremos en el \hyperref[sec:Chapter6]{Capítulo 6}).
(Para ello necesitas el bucle aritmético \emph{for}, que veremos en el \hyperref[sec:Chapter6]{Capítulo 6}).
Sin embargo, el bucle for es ideal para trabajar con argumentos en la línea de órdenes y con conjuntos de ficheros (por ejemplo, todos los ficheros de un directorio determinado). Veremos un ejemplo de cada uno de ellos. Pero primero, aquí está la sintaxis para la construcción for:
Sin embargo, el bucle \emph{for} es ideal para trabajar con argumentos en la línea de órdenes y con conjuntos de ficheros (por ejemplo, todos los ficheros de un directorio determinado). Veremos un ejemplo de cada uno de ellos. Pero primero, aquí está la sintaxis para la construcción \emph{for}:
\begin{lstlisting}[language=bash]
for name [in list]
@ -647,7 +647,7 @@ done
\emph{list} es una lista de nombres. (Si se omite en \emph{list}, la lista por defecto es "\$@", es decir, la lista entrecomillada de argumentos de la línea de comandos, pero siempre proporcionamos en \emph{list} en aras de la claridad). En nuestras soluciones a la siguiente tarea, mostramos dos formas sencillas de especificar listas.
En \emph{ksh93} hay una interesante interacción entre el bucle for y las variables nameref (ver Capítulo 4). Si la variable de control es un nameref, entonces cada elemento de la lista de nombres puede ser una variable shell diferente, y el shell asigna el nameref a cada variable sucesivamente. Por ejemplo:
En \emph{ksh93} hay una interesante interacción entre el bucle \emph{for} y las variables \emph{nameref} (ver \hyperref[sec:Chapter4]{Capítulo 4}). Si la variable de control es un \emph{nameref}, entonces cada elemento de la lista de nombres puede ser una variable shell diferente, y el shell asigna el \emph{nameref} a cada variable sucesivamente. Por ejemplo:
\begin{lstlisting}[language=bash]
$ first="I am first" # Initialize test variables
@ -664,7 +664,7 @@ $ print ${!refvar}, $refvar # Show final state
third, I am last
\end{lstlisting}
El bucle for es fundamental para resolver la \hyperref[box:5-2]{Tarea 5-2}.
El bucle \emph{for} es fundamental para resolver la \hyperref[box:5-2]{Tarea 5-2}.
\begin{mybox}[Tarea 5-2]\label{box:5-2}
Usted trabaja en un entorno con varios ordenadores en una red local. Escribe un script de shell que te diga quién ha iniciado sesión en cada máquina de la red.
@ -697,9 +697,9 @@ done
Esto funciona independientemente del sistema en el que esté conectado. Imprime una salida para cada máquina similar a la anterior, con líneas en blanco entre ellas.
Una solución ligeramente mejor sería almacenar los nombres de los sistemas en una variable de entorno. De esta forma, si se añaden sistemas a su red y necesita una lista de sus nombres en más de un script, sólo tendrá que cambiarlos en un lugar. Si el valor de una variable son varias palabras separadas por espacios (o TABS), for lo tratará como una lista de palabras.
Una solución ligeramente mejor sería almacenar los nombres de los sistemas en una variable de entorno. De esta forma, si se añaden sistemas a su red y necesita una lista de sus nombres en más de un script, sólo tendrá que cambiarlos en un lugar. Si el valor de una variable son varias palabras separadas por espacios (o TABS), \emph{for} lo tratará como una lista de palabras.
Aquí está la solución mejorada. Primero, ponga líneas en su archivo \emph{.profile} o de entorno que definan la variable SYSNAMES y conviértala en una variable de entorno:
Aquí está la solución mejorada. Primero, ponga líneas en su archivo \emph{.profile} o de entorno que definan la variable \texttt{SYSNAMES} y conviértala en una variable de entorno:
\begin{lstlisting}[language=bash]
SYSNAMES="fred bob dave pete"
@ -716,7 +716,7 @@ do
done
\end{lstlisting}
Lo anterior ilustra un uso simple de for, pero es mucho más común usar for para iterar a través de una lista de argumentos de línea de comandos. Para mostrar esto, podemos mejorar el script \emph{fileinfo} anterior para que acepte múltiples argumentos. Primero, escribimos un poco de código <<envolvente>> que hace la iteración:
Lo anterior ilustra un uso simple de \emph{for}, pero es mucho más común usar \emph{for} para iterar a través de una lista de argumentos de línea de comandos. Para mostrar esto, podemos mejorar el script \emph{fileinfo} anterior para que acepte múltiples argumentos. Primero, escribimos un poco de código <<envolvente>> que hace la iteración:
\begin{lstlisting}[language=bash]
for filename in "$@" ; do
@ -725,7 +725,7 @@ for filename in "$@" ; do
done
\end{lstlisting}
A continuación, convertimos el script original en una función llamada finfo\footnote{Una función puede tener el mismo nombre que un script; sin embargo, esto no es una buena práctica de programación.}:
A continuación, convertimos el script original en una función llamada \emph{finfo}\footnote{Una función puede tener el mismo nombre que un script; sin embargo, esto no es una buena práctica de programación.}:
\begin{lstlisting}[language=bash]
function finfo {
@ -737,9 +737,9 @@ function finfo {
}
\end{lstlisting}
El script completo consiste en el código del bucle for y la función anterior. Debido a que la función debe ser definida antes de que pueda ser usada, la definición de la función debe ir primero, o bien debe estar en un directorio listado tanto en \texttt{PATH} como en \texttt{FPATH}.
El script completo consiste en el código del bucle \emph{for} y la función anterior. Debido a que la función debe ser definida antes de que pueda ser usada, la definición de la función debe ir primero, o bien debe estar en un directorio listado tanto en \texttt{PATH} como en \texttt{FPATH}.
El script \emph{fileinfo} funciona de la siguiente manera: en la sentencia for, <<\$@>> es una lista de todos los parámetros posicionales. Para cada argumento, el cuerpo del bucle se ejecuta con \texttt{filename} fijado a ese argumento. En otras palabras, la función \emph{fileinfo} es llamada una vez por cada valor de \texttt{\$filename} como su primer argumento (\$1). La llamada a \emph{print} después de la llamada a \emph{fileinfo} simplemente imprime una línea en blanco entre los conjuntos de información sobre cada fichero.
El script \emph{fileinfo} funciona de la siguiente manera: en la sentencia \emph{for}, <<\$@>> es una lista de todos los parámetros posicionales. Para cada argumento, el cuerpo del bucle se ejecuta con \texttt{filename} fijado a ese argumento. En otras palabras, la función \emph{fileinfo} es llamada una vez por cada valor de \texttt{\$filename} como su primer argumento (\$1). La llamada a \emph{print} después de la llamada a \emph{fileinfo} simplemente imprime una línea en blanco entre los conjuntos de información sobre cada fichero.
Dado un directorio con los mismos ficheros que en el ejemplo anterior, al teclear \texttt{fileinfo *} se obtendría la siguiente salida:
@ -764,7 +764,7 @@ you do not own the file.
you have read permission on the file.
\end{lstlisting}
La \hyperref[box:5-3]{Tarea 5-3} es una tarea de programación que explota el otro uso principal de for.
La \hyperref[box:5-3]{Tarea 5-3} es una tarea de programación que explota el otro uso principal de \emph{for}.
\begin{mybox}[Tarea 5-3]\label{box:5-3}
Su sistema Unix tiene la capacidad de transferir archivos desde un sistema MS-DOS, pero deja intactos los nombres de archivo MS-DOS. Escribe una secuencia de comandos que traduzca los nombres de archivo de un directorio determinado del formato MS-DOS a un formato más compatible con Unix.
@ -778,10 +778,10 @@ Los nombres de archivo en el antiguo sistema MS-DOS de Microsoft tienen el forma
\end{enumerate}
La primera herramienta que necesitaremos para este trabajo es la utilidad Unix \emph{tr(1)}, que traduce caracteres de uno en uno
\footnote{Como veremos en el \hyperref[sec:Chapter6]{Capítulo 6}, es posible hacer la traducción de mayúsculas y minúsculas dentro del shell, sin usar un programa externo. Sin embargo, ignoraremos ese hecho por ahora.}. Dados los argumentos \emph{charset1} y \emph{charset2}, traduce los caracteres de la entrada estándar que son miembros de \emph{charset1} a los caracteres correspondientes de \emph{charset2}. Los dos conjuntos son rangos de caracteres encerrados entre corchetes ([...] en forma de expresión regular estándar a la manera de \emph{grep, awk, ed,} etc.). Más concretamente, \texttt{tr [A-Z] [a-z]} toma su entrada estándar, convierte las mayúsculas en minúsculas y escribe el texto convertido en la salida estándar
\footnote{Los sistemas modernos compatibles con POSIX soportan locales, que son formas de utilizar conjuntos de caracteres no ASCII de forma portable. En un sistema así, la invocación correcta de tr es tr '[:upper:]' '[:lower:]'. Sin embargo, la mayoría de los usuarios veteranos de Unix tienden a olvidar esto.}.
\footnote{Como veremos en el \hyperref[sec:Chapter6]{Capítulo 6}, es posible hacer la traducción de mayúsculas y minúsculas dentro del shell, sin usar un programa externo. Sin embargo, ignoraremos ese hecho por ahora.}. Dados los argumentos \emph{charset1} y \emph{charset2}, traduce los caracteres de la entrada estándar que son miembros de \emph{charset1} a los caracteres correspondientes de \emph{charset2}. Los dos conjuntos son rangos de caracteres encerrados entre corchetes (\texttt{[...]} en forma de expresión regular estándar a la manera de \emph{grep, awk, ed,} etc.). Más concretamente, \texttt{tr [A-Z] [a-z]} toma su entrada estándar, convierte las mayúsculas en minúsculas y escribe el texto convertido en la salida estándar
\footnote{Los sistemas modernos compatibles con POSIX soportan locales, que son formas de utilizar conjuntos de caracteres no ASCII de forma portable. En un sistema así, la invocación correcta de \emph{tr} es \texttt{tr [:upper:] [:lower:]}. Sin embargo, la mayoría de los usuarios veteranos de Unix tienden a olvidar esto.}.
Esto se encarga del primer paso en el proceso de traducción. Podemos usar un operador de cadena del shell Korn para manejar el segundo. Aquí está el código para un script que llamaremos \emph{dosmv}:
Esto se encarga del primer paso en el proceso de traducción. Podemos usar un operador de cadena del shell de Korn para manejar el segundo. Aquí está el código para un script que llamaremos \emph{dosmv}:
\begin{lstlisting}[language=bash]
for filename in ${1:+$1/}* ; do
@ -792,16 +792,16 @@ for filename in ${1:+$1/}* ; do
done
\end{lstlisting}
El * en la construcción for \emph{no} es lo mismo que \texttt{\$*}. Es un comodín, es decir, todos los archivos de un directorio.
El * en la construcción \emph{for} \emph{no} es lo mismo que \texttt{\$*}. Es un comodín, es decir, todos los archivos de un directorio.
Este script acepta un nombre de directorio como argumento, siendo por defecto el directorio actual. La expresión \texttt{\$\{1:+\$1/\}} se evalúa como el argumento (\$1) con una barra añadida si se proporciona el argumento, o la cadena nula si no se proporciona. Por lo tanto, la expresión \texttt{\$\{1:+\$1/\}*} completa equivale a todos los archivos del directorio indicado, o a todos los archivos del directorio actual si no se proporciona ningún argumento.
Por lo tanto, \texttt{filename} toma el valor de cada filename de la lista. \texttt{filename} se convierte en \texttt{newfilename} en dos pasos. (Podríamos haberlo hecho en uno, pero la legibilidad se habría resentido.) El primer paso utiliza \emph{tr} en un canal dentro de una construcción de sustitución de comandos. Nuestro viejo amigo \emph{print} convierte el valor de \texttt{filename} en la entrada estándar de \emph{tr}. La salida de \emph{tr} se convierte en el valor de la expresión de sustitución de comandos, que se asigna a \texttt{newfilename}. Así, si \texttt{\$filename} fuera \texttt{DOSFILE.TXT}, \texttt{filename} se convertiría en \texttt{dosfile.txt}.
Por lo tanto, \texttt{filename} toma el valor de cada \emph{filename} de la lista. \texttt{filename} se convierte en \texttt{newfilename} en dos pasos. (Podríamos haberlo hecho en uno, pero la legibilidad se habría resentido.) El primer paso utiliza \emph{tr} en un canal dentro de una construcción de sustitución de comandos. Nuestro viejo amigo \emph{print} convierte el valor de \texttt{filename} en la entrada estándar de \emph{tr}. La salida de \emph{tr} se convierte en el valor de la expresión de sustitución de comandos, que se asigna a \texttt{newfilename}. Así, si \texttt{\$filename} fuera \texttt{DOSFILE.TXT}, \texttt{filename} se convertiría en \texttt{dosfile.txt}.
El segundo paso utiliza uno de los operadores de coincidencia de patrones del intérprete de comandos, el que elimina la coincidencia más corta que encuentra al final de la cadena. El patrón aquí es ., que significa un punto al final de la cadena
El segundo paso utiliza uno de los operadores de coincidencia de patrones del intérprete de comandos, el que elimina la coincidencia más corta que encuentra al final de la cadena. El patrón aquí es \texttt{.}, que significa un punto al final de la cadena
\footnote{Los expertos en expresiones regulares de Unix deben recordar que se trata de la sintaxis de comodines del shell, en la que los puntos no son operadores y, por lo tanto, no es necesario ocultarlos.}. Esto significa que la expresión \texttt{\$\{newfilename\%.\}} eliminará un punto de \texttt{\$newfilename} sólo si está al final de la cadena; de lo contrario, la expresión dejará \texttt{\$newfilename} intacto. Por ejemplo, si \texttt{\$newfilename} es \texttt{dosfile.txt}, no se modificará, pero si es \texttt{dosfile.}, la expresión lo cambiará a \texttt{dosfile} sin el punto final. En cualquier caso, el nuevo valor se asigna de nuevo a \texttt{newfilename}.
La última sentencia en el cuerpo del bucle for realiza el renombrado de ficheros con el comando estándar de Unix \emph{mv(1)}. Antes de eso, un comando \emph{print} simplemente informa al usuario de lo que está ocurriendo.
La última sentencia en el cuerpo del bucle \emph{for} realiza el renombrado de ficheros con el comando estándar de Unix \emph{mv(1)}. Antes de eso, un comando \emph{print} simplemente informa al usuario de lo que está ocurriendo.
Hay un pequeño problema con esta solución: si hay ficheros en el directorio dado que no son ficheros MS-DOS (en particular, si hay ficheros cuyos nombres no contienen letras mayúsculas o no contienen un punto), entonces la conversión no hará nada con esos nombres de fichero y \emph{mv} será llamado con dos argumentos idénticos. \emph{mv} se quejará con el mensaje: \texttt{mv: \emph{filename} and \emph{filename} are identical}. La solución es muy sencilla: compruebe si los nombres de archivo son idénticos:
@ -833,17 +833,17 @@ La primera de ellas es una modificación relativamente sencilla de dosmv. La nú
\begin{itemize}
\item{Desarrolle una expresión regular que coincida con los nombres de archivo OpenVMS (de todos modos, la necesitará para el número 1).}
\item{Obtenga una lista de los nombres base (sin los números de versión) de los archivos del directorio indicado pasando \emph{ls} por \emph{grep} (con la expresión regular anterior), \emph{cut} y \emph{sort -u}. Utilice \emph{cut} con punto y coma como <<separador de campos>>. Utilice cut con un punto y coma como "separador de campos"; asegúrese de entrecomillar el punto y coma para que el shell no lo trate como un separador de sentencias. \emph{sort -u} elimina los duplicados tras la ordenación. Utilice la sustitución de comandos para guardar la lista resultante en una variable.}
\item{Utiliza un bucle for en la lista de nombres base. Para cada nombre, obtenga el número de versión más alto del archivo (sólo el número, no el nombre completo). Haga esto con otra tubería: pipe \emph{ls} a través de \emph{cut}, \emph{sort -n}, y \emph{tail -1}. \emph{sort -n} ordena en orden numérico (no lexicográfico); \emph{tail -N} muestra las últimas \emph{N} líneas de su entrada. De nuevo, utilice la sustitución de comandos para capturar la salida de este proceso en una variable. }
\item{Utiliza un bucle \emph{for} en la lista de nombres base. Para cada nombre, obtenga el número de versión más alto del archivo (sólo el número, no el nombre completo). Haga esto con otra tubería: pipe \emph{ls} a través de \emph{cut}, \emph{sort -n}, y \emph{tail -1}. \emph{sort -n} ordena en orden numérico (no lexicográfico); \emph{tail -N} muestra las últimas \emph{N} líneas de su entrada. De nuevo, utilice la sustitución de comandos para capturar la salida de este proceso en una variable. }
\item{Añada el número de versión más alto al nombre base; éste es el archivo que hay que renombrar en formato Unix. }
\end{itemize}
Una vez que hayas completado el número 2, puedes hacer el número 3 añadiendo una sola línea de código a tu script; a ver si averiguas cómo.
Finalmente, \emph{ksh93} proporciona el bucle for aritmético, que es mucho más cercano en sintaxis y estilo al bucle for de C. Lo presentamos en el próximo capítulo, después de discutir las capacidades aritméticas generales del shell. Lo presentamos en el próximo capítulo, después de discutir las capacidades aritméticas generales del shell.
Finalmente, \emph{ksh93} proporciona el bucle \emph{for} aritmético, que es mucho más cercano en sintaxis y estilo al bucle \emph{for} de C. Lo presentamos en el próximo capítulo, después de discutir las capacidades aritméticas generales del shell. Lo presentamos en el próximo capítulo, después de discutir las capacidades aritméticas generales del shell.
\section{case}
La siguiente construcción de control de flujo a cubrir es \texttt{case}. Mientras que la sentencia \texttt{case} en Pascal y la sentencia \texttt{witch} similar en C pueden usarse para probar valores simples como enteros y caracteres, la construcción \texttt{case} del shell Korn le permite probar cadenas contra patrones que pueden contener caracteres comodín. Al igual que sus equivalentes en lenguajes convencionales, \texttt{case} permite expresar una serie de sentencias del tipo \texttt{if-then-else} de forma concisa.
La siguiente construcción de control de flujo a cubrir es \texttt{case}. Mientras que la sentencia \texttt{case} en Pascal y la sentencia \texttt{witch} similar en C pueden usarse para probar valores simples como enteros y caracteres, la construcción \texttt{case} del shell de Korn le permite probar cadenas contra patrones que pueden contener caracteres comodín. Al igual que sus equivalentes en lenguajes convencionales, \texttt{case} permite expresar una serie de sentencias del tipo \texttt{if-then-else} de forma concisa.
La sintaxis de \texttt{case} es la siguiente
@ -861,7 +861,7 @@ Cualquiera de los \emph{patrones} puede ser en realidad varios patrones separado
Esta sintaxis bastante desgarbada debería quedar más clara con un ejemplo. Una opción obvia es revisar nuestra solución a la \hyperref[box:4-2]{Tarea 4-2}, el front-end para el compilador C. Anteriormente en este capítulo, escribimos algo de código que procesaba archivos de entrada según sus sufijos (.c, .s, o .o para C, ensamblador, o código objeto, respectivamente).
Podemos mejorar esta solución de dos maneras. En primer lugar, podemos utilizar for para permitir que se procesen varios archivos a la vez; en segundo lugar, podemos utilizar case para agilizar el código:
Podemos mejorar esta solución de dos maneras. En primer lugar, podemos utilizar \emph{for} para permitir que se procesen varios archivos a la vez; en segundo lugar, podemos utilizar case para agilizar el código:
\begin{lstlisting}[language=bash]
for filename in "$@"; do
@ -885,8 +885,8 @@ Después, el código es un poco diferente. Recordemos que si el nombre del fiche
Si el nombre del archivo no termina en \texttt{.o}, se produce un error. Esto se trata en el último caso, que es \texttt{*}. Esto captura cualquier cosa que no coincida con los otros casos. (De hecho, un caso \texttt{*} es análogo a un \emph{case} por defecto en C y un caso de lo contrario en algunos lenguajes derivados de Pascal).
El bucle for que lo rodea procesa correctamente todos los argumentos de la línea de comandos. Esto nos lleva a otra mejora: ahora que sabemos cómo procesar todos los argumentos, deberíamos ser capaces de escribir el código que pasa todos los ficheros objeto al enlazador (el programa
\emph{ld}) al final. Podemos hacerlo construyendo una cadena de nombres de ficheros objeto, separados por espacios, y pasársela al enlazador cuando hayamos procesado todos los ficheros de entrada. Inicializamos la cadena a null y añadimos un nombre de fichero objeto cada vez que se crea uno, es decir, durante cada iteración del bucle for. El código para esto es simple, requiriendo sólo adiciones menores:
El bucle \emph{for} que lo rodea procesa correctamente todos los argumentos de la línea de comandos. Esto nos lleva a otra mejora: ahora que sabemos cómo procesar todos los argumentos, deberíamos ser capaces de escribir el código que pasa todos los ficheros objeto al enlazador (el programa
\emph{ld}) al final. Podemos hacerlo construyendo una cadena de nombres de ficheros objeto, separados por espacios, y pasársela al enlazador cuando hayamos procesado todos los ficheros de entrada. Inicializamos la cadena a \emph{null} y añadimos un nombre de fichero objeto cada vez que se crea uno, es decir, durante cada iteración del bucle \emph{for}. El código para esto es simple, requiriendo sólo adiciones menores:
\begin{lstlisting}[language=bash]
objfiles=""
@ -909,11 +909,11 @@ done
ld $objfiles
\end{lstlisting}
La primera línea en esta versión del script inicializa la variable \texttt{objfiles} a null
\footnote{Esto no es estrictamente necesario, porque se asume que todas las variables son nulas si no se inicializan explícitamente (a menos que la opción nounset esté activada). Sólo hace que el código sea más fácil de leer.}.
La primera línea en esta versión del script inicializa la variable \texttt{objfiles} a \emph{null}
\footnote{Esto no es estrictamente necesario, porque se asume que todas las variables son nulas si no se inicializan explícitamente (a menos que la opción \emph{nounset} esté activada). Sólo hace que el código sea más fácil de leer.}.
Añadimos una línea de código en el caso \texttt{*.o} para establecer \texttt{objname} igual a \texttt{\$filename}, porque ya sabemos que es un archivo objeto. Así, el valor de \texttt{objname} se establece en todos los casos -- excepto en el caso de error, en el que la rutina imprime un mensaje y se retira.
La última línea de código en el cuerpo del bucle for añade un espacio y el último \texttt{\$objname} a \texttt{objfiles}. Llamando a este script con los mismos argumentos que en la Figura \ref{fig:05} resultaría en \texttt{\$objfiles} igual a \texttt{" a.o b.o c.o d.o"} cuando el bucle for termina (el espacio inicial no importa). Esta lista de nombres de archivos de objetos se le da a ld como un único argumento, pero el shell lo divide en múltiples nombres de archivo correctamente.
La última línea de código en el cuerpo del bucle \emph{for} añade un espacio y el último \texttt{\$objname} a \texttt{objfiles}. Llamando a este script con los mismos argumentos que en la Figura \ref{fig:05} resultaría en \texttt{\$objfiles} igual a \texttt{" a.o b.o c.o d.o"} cuando el bucle for termina (el espacio inicial no importa). Esta lista de nombres de archivos de objetos se le da a \emph{ld} como un único argumento, pero el shell lo divide en múltiples nombres de archivo correctamente.
La \hyperref[box:5-4]{Tarea 5-4} es una nueva tarea cuya solución inicial utiliza case.
@ -976,7 +976,7 @@ result=$(case $input in
\emph{ksh93} todavía acepta esta sintaxis, pero ya no la requiere.
\subsection{Fusionando <<cases>>}
A veces, al escribir una construcción de tipo case, hay instancias en las que un caso es un subconjunto de lo que debería hacerse para otro. El lenguaje C maneja esto permitiendo que un caso en un switch <<continue>> en el código de otro. Un hecho poco conocido es que el shell Korn (pero no el shell Bourne) tiene una funcionalidad similar.
A veces, al escribir una construcción de tipo case, hay instancias en las que un caso es un subconjunto de lo que debería hacerse para otro. El lenguaje C maneja esto permitiendo que un caso en un switch <<continue>> en el código de otro. Un hecho poco conocido es que el shell de Korn (pero no el shell de Bourne) tiene una funcionalidad similar.
Por ejemplo, supongamos que nuestro compilador de C sólo genera código ensamblador, y que depende de nuestro script front-end convertir el código ensamblador en código objeto. En este caso, queremos pasar del caso \texttt{*.c} al caso \texttt{*.s}. Esto se hace usando \texttt{;\&} para terminar el cuerpo del caso que hace la caída:
@ -1002,10 +1002,10 @@ done
ld $objfiles
\end{lstlisting}
Antes de caer, el caso \texttt{*c} tiene que restablecer el valor de \texttt{filename} para que el caso \texttt{*.s} funcione correctamente. Suele ser una muy buena idea añadir un comentario indicando que la <<continuación de ejecución>> es intencional, aunque es más obvio en shell que en C. Volveremos a este ejemplo una vez más en el \hyperref[sec:Chapter6]{Capítulo 6} cuando discutamos cómo manejar las opciones dash en la línea de comandos.
Antes de caer, el caso \texttt{*c} tiene que restablecer el valor de \texttt{filename} para que el caso \texttt{*.s} funcione correctamente. Suele ser una muy buena idea añadir un comentario indicando que la <<continuación de ejecución>> es intencional, aunque es más obvio en shell que en C. Volveremos a este ejemplo una vez más en el \hyperref[sec:Chapter6]{Capítulo 6} cuando discutamos cómo manejar las opciones \emph{dash} en la línea de comandos.
\section{select}
Casi todas las construcciones de control de flujo que hemos visto hasta ahora también están disponibles en el shell Bourne, y el shell C tiene equivalentes con diferente sintaxis. Nuestra siguiente construcción, \texttt{select}, es exclusiva del shell Korn; además, no tiene análogos en los lenguajes de programación convencionales.
Casi todas las construcciones de control de flujo que hemos visto hasta ahora también están disponibles en el shell de Bourne, y el shell C tiene equivalentes con diferente sintaxis. Nuestra siguiente construcción, \texttt{select}, es exclusiva del shell de Korn; además, no tiene análogos en los lenguajes de programación convencionales.
\texttt{select} le permite generar menús sencillos fácilmente. Tiene una sintaxis concisa, pero hace bastante trabajo. La sintaxis es:
@ -1016,7 +1016,7 @@ do
done
\end{lstlisting}
Es la misma sintaxis que el bucle for normal, excepto por la palabra clave \texttt{select}. Y al igual que \texttt{for}, puede omitir en \texttt{list}, y por defecto será <<\$@>>, es decir, la lista de argumentos de línea de comandos entrecomillados.
Es la misma sintaxis que el bucle \emph{for} normal, excepto por la palabra clave \texttt{select}. Y al igual que \texttt{for}, puede omitir en \texttt{list}, y por defecto será <<\$@>>, es decir, la lista de argumentos de línea de comandos entrecomillados.
Esto es lo que hace \texttt{select}:
@ -1059,13 +1059,13 @@ terminal?
La variable de shell incorporada \texttt{PS3} contiene la cadena de consulta que utiliza \texttt{select}; su valor por defecto es el poco útil <<\#? >>. Así que la primera línea del código anterior la establece en un valor más relevante
\footnote{En cuanto a \texttt{PS1}, \emph{ksh} realiza la sustitución de parámetros, comandos y aritmética en el valor antes de imprimirlo.}.
La sentencia \texttt{select} construye el menú a partir de la lista de opciones. Si el usuario introduce un número válido (de 1 a 4), la variable term se establece en el valor correspondiente; de lo contrario, es nula. (Si el usuario sólo pulsa INTRO, el shell vuelve a imprimir el menú).
La sentencia \texttt{select} construye el menú a partir de la lista de opciones. Si el usuario introduce un número válido (de 1 a 4), la variable \emph{term} se establece en el valor correspondiente; de lo contrario, es nula. (Si el usuario sólo pulsa INTRO, el shell vuelve a imprimir el menú).
El código en el cuerpo del bucle comprueba si \texttt{term} no es nulo. Si lo es, asigna \texttt{\$term} a la variable de entorno \texttt{TERM}, exporta \texttt{TERM}, e imprime un mensaje de confirmación; entonces la sentencia \emph{break} sale del bucle \texttt{select}. Si \texttt{term} es nulo, el código imprime un mensaje de error y repite el prompt (pero no el menú).
La sentencia \texttt{break} es la forma habitual de salir de un bucle \texttt{select}. En realidad (al igual que su análogo en C), se puede utilizar para salir de cualquier estructura de control circundante que hayamos visto hasta ahora (excepto \texttt{case}, donde el doble punto y coma actúa como \emph{break}), así como de los \texttt{while} y \texttt{until} que veremos próximamente. No hemos introducido \emph{break} hasta ahora porque algunas personas consideran que es un mal estilo de codificación utilizarlo para salir de un bucle. Sin embargo, es necesario para salir de \texttt{select} cuando el usuario hace una elección válida. \footnote{Un usuario también puede teclear CTRL-D -- para fin de entrada -- para salir de un bucle de \texttt{selección}. Esto le da al usuario una forma uniforme de salir, pero no ayuda mucho al programador del shell.}
Perfeccionemos nuestra solución haciendo que el menú sea más fácil de usar, para que el usuario no tenga que conocer el nombre \emph{terminfo} de su terminal. Para ello, utilizaremos cadenas de caracteres entre comillas como elementos del menú y, a continuación, utilizaremos mayúsculas y minúsculas para determinar el nombre terminfo:
Perfeccionemos nuestra solución haciendo que el menú sea más fácil de usar, para que el usuario no tenga que conocer el nombre \emph{terminfo} de su terminal. Para ello, utilizaremos cadenas de caracteres entre comillas como elementos del menú y, a continuación, utilizaremos mayúsculas y minúsculas para determinar el nombre \emph{terminfo}:
\begin{lstlisting}[language=bash]
print 'Select your terminal type:'
@ -1114,7 +1114,7 @@ Dentro de un bucle \texttt{select}, si \texttt{REPLY} se establece en una cadena
La variable \texttt{TMOUT} (tiempo de espera) puede afectar la instrucción \texttt{select}. Antes del bucle \texttt{select}, configúrala en algún número de segundos \emph{N} y, si no se ingresa nada en ese lapso de tiempo, el \texttt{select} se cerrará. Como se explicará más adelante, \texttt{TMOUT} también afecta al comando \texttt{read} y al mecanismo interactivo de solicitud de entrada del shell.
\section{while y until}
Las dos estructuras de control de flujo restantes que proporciona el shell Korn son \texttt{while} y \texttt{until}. Estas son similares; ambas permiten que se ejecute repetidamente una sección de código mientras (o hasta que) se cumpla cierta condición. También se asemejan a construcciones análogas en Pascal (\texttt{while}/\texttt{do} y \texttt{repeat}/\texttt{until}) y en C (\texttt{while} y \texttt{do}/\texttt{until}).
Las dos estructuras de control de flujo restantes que proporciona el shell de Korn son \texttt{while} y \texttt{until}. Estas son similares; ambas permiten que se ejecute repetidamente una sección de código mientras (o hasta que) se cumpla cierta condición. También se asemejan a construcciones análogas en Pascal (\texttt{while}/\texttt{do} y \texttt{repeat}/\texttt{until}) y en C (\texttt{while} y \texttt{do}/\texttt{until}).
\texttt{while} y \texttt{until} son más útiles cuando se combinan con características que veremos en el próximo capítulo, como aritmética entera, entrada/salida de variables y procesamiento de línea de comandos. Aún así, podemos mostrar un ejemplo útil incluso con las herramientas que hemos cubierto hasta ahora.
@ -1239,7 +1239,7 @@ while [[ -n $path ]]; do
con resultados idénticos.
Veremos ejemplos adicionales de `while` en el próximo capítulo.
Veremos ejemplos adicionales de \emph{while} en el próximo capítulo.
\subsection{break y continue}

View File

@ -2,7 +2,7 @@ Deberías tener un sólido conocimiento de las técnicas de programación de she
Sin embargo, es posible que hayas notado algunas lagunas restantes en el conocimiento que necesitas para escribir código de shell que se comporte como los comandos UNIX a los que estás acostumbrado. En particular, si eres un usuario experimentado de UNIX, puede que hayas notado que ninguno de los scripts de ejemplo mostrados hasta ahora tiene la capacidad de manejar \emph{opciones} (precedidas por un guion ( - )) en la línea de comandos. Y si programas en un lenguaje convencional como C o Pascal, habrás notado que el único tipo de datos que hemos visto en las variables de shell son cadenas de caracteres; no hemos visto cómo hacer operaciones aritméticas, por ejemplo.
Estas capacidades son ciertamente cruciales para la capacidad del shell de funcionar como un lenguaje de programación UNIX útil. En este capítulo, mostraremos cómo el shell Korn admite estas y otras características relacionadas.
Estas capacidades son ciertamente cruciales para la capacidad del shell de funcionar como un lenguaje de programación UNIX útil. En este capítulo, mostraremos cómo el shell de Korn admite estas y otras características relacionadas.
\section{Opciones de línea de comandos}
Ya hemos visto muchos ejemplos de los \emph{parámetros posicionales} (variables llamadas \textbf{1, 2, 3,} etc.) que el shell utiliza para almacenar los argumentos de línea de comandos de un script o función de shell cuando se ejecuta. También hemos visto variables relacionadas como * (para la cadena de todos los argumentos) y \# (para el número de argumentos).
@ -78,7 +78,7 @@ else
sort -nr $filename | head $howmany
\end{lstlisting}
En este código, se considera que la opción se ha proporcionado si \texttt{\$1} coincide con el patrón \texttt{-+([0-9])}. Esto utiliza uno de los operadores de expresiones regulares del shell Korn, que vimos en el \hyperref[sec:Chapter4]{Capítulo 4}. Observa que no rodeamos el patrón con comillas (ni siquiera comillas dobles); si lo hiciéramos, el shell lo interpretaría literalmente, no como un patrón. Este patrón significa <<un guion seguido por uno o más dígitos>>. Si \texttt{\$1} coincide, entonces lo asignamos a la variable \textbf{howmany}.
En este código, se considera que la opción se ha proporcionado si \texttt{\$1} coincide con el patrón \texttt{-+([0-9])}. Esto utiliza uno de los operadores de expresiones regulares del shell de Korn, que vimos en el \hyperref[sec:Chapter4]{Capítulo 4}. Observa que no rodeamos el patrón con comillas (ni siquiera comillas dobles); si lo hiciéramos, el shell lo interpretaría literalmente, no como un patrón. Este patrón significa <<un guion seguido por uno o más dígitos>>. Si \texttt{\$1} coincide, entonces lo asignamos a la variable \textbf{howmany}.
Si \texttt{\$1} no coincide, comprobamos si es una opción en absoluto, es decir, si coincide con el patrón \texttt{-*}. Si es así, entonces es inválido; imprimimos un mensaje de error y salimos con un estado de error. Si llegamos al caso final (\texttt{else}), asumimos que \texttt{\$1} es un nombre de archivo y lo tratamos como tal en el código siguiente. El resto del script procesa los datos como antes.
@ -138,7 +138,7 @@ se puede utilizar como condición del \texttt{while} en un bucle de procesamient
La función \texttt{getopts} toma al menos dos argumentos. El primero es una cadena que puede contener letras y dos puntos. Cada letra es una opción válida; si una letra va seguida de dos puntos, la opción requiere un argumento. Si la letra va seguida de un numeral (\texttt{\#}), la opción requiere un argumento numérico. Los dos puntos (\texttt{:}) o el numeral (\texttt{\#})pueden ir seguidos de \texttt{[descripción]}, es decir, una cadena descriptiva encerrada entre corchetes que se utiliza al generar mensajes de error de uso. Si añades un espacio con texto más descriptivo a la lista de caracteres de opción, ese texto también se imprime en los mensajes de error.
\texttt{getopts} selecciona opciones de la línea de comandos y asigna cada una (sin el guion inicial) a una variable cuyo nombre es el segundo argumento de \texttt{getopts}. Mientras haya opciones por procesar, \texttt{getopts} devuelve un estado de salida 0; cuando las opciones se agotan, devuelve un estado de salida 1, lo que hace que el bucle while salga.
\texttt{getopts} selecciona opciones de la línea de comandos y asigna cada una (sin el guion inicial) a una variable cuyo nombre es el segundo argumento de \texttt{getopts}. Mientras haya opciones por procesar, \texttt{getopts} devuelve un estado de salida 0; cuando las opciones se agotan, devuelve un estado de salida 1, lo que hace que el bucle \emph{while} salga.
De forma predeterminada, \texttt{getopts} recorre \texttt{"\$@"}, la lista entre comillas de los argumentos de la línea de comandos. Sin embargo, puedes proporcionar argumentos adicionales a \texttt{getopts}, en cuyo caso los utiliza en su lugar.
@ -162,7 +162,7 @@ shift $(($OPTIND - 1))
procesamiento normal de argumentos...
\end{lstlisting}
La llamada a \texttt{getopts} en la condición del bucle \texttt{while} configura el bucle para aceptar las opciones \texttt{-a, -b} y \texttt{-c}, yespecifica que \texttt{-b} toma un argumento. (Explicaremos el \textbf{``:''} que inicia la cadena de opciones en un momento.) Cada vez que se ejecuta el cuerpo del bucle, tiene la opción más reciente disponible, sin un guion (-), en la variable \texttt{opt}.
La llamada a \texttt{getopts} en la condición del bucle \texttt{while} configura el bucle para aceptar las opciones \texttt{-a, -b} y \texttt{-c}, y especifica que \texttt{-b} toma un argumento. (Explicaremos el \textbf{``:''} que inicia la cadena de opciones en un momento.) Cada vez que se ejecuta el cuerpo del bucle, tiene la opción más reciente disponible, sin un guion (-), en la variable \texttt{opt}.
Si el usuario escribe una opción no válida, \texttt{getopts} normalmente imprime un mensaje de error (de la forma \texttt{cmd: -o: unknown option}) y establece \texttt{opt} en \texttt{?}. \texttt{getopts} termina de procesar todas sus opciones y, si se encontró un error, el shell sale. Sin embargo, ahora aquí hay un truco oscuro: si comienzas la cadena de letras de opción con dos puntos, \texttt{getopts} no imprimirá el mensaje y el shell no saldrá. Esto te permite manejar los mensajes de error por tu cuenta.
@ -253,14 +253,14 @@ La Tabla \ref{Tab:6.1} resume las opciones que incorporaremos en nuestro front-e
También debes tener en cuenta esta información sobre las opciones:
\begin{itemize}
\item Las opciones \textbf{-o} y \textbf{-l} lib se pasan simplemente al enlazador \emph{(ld)}, que las procesa por sí mismo.
\item Las opciones \textbf{-o} y \textbf{-l lib} se pasan simplemente al enlazador \emph{(ld)}, que las procesa por sí mismo.
\item En la mayoría de los sistemas, \texttt{ld} requiere que las opciones de biblioteca vayan después de los ficheros objeto en la línea de órdenes. (Además, el orden de las bibliotecas en la línea de órdenes es importante. Si una rutina en \texttt{libA.a} hace referencia a otra rutina de \texttt{libB.a}, entonces \texttt{libA.a} debe aparecer primero en la línea de comandos (\texttt{-lA -lB}). Esto implica que la biblioteca C (\texttt{libc.a}) debe cargarse en último lugar, ya que las rutinas de otras bibliotecas casi siempre dependen de las rutinas estándar de la biblioteca C.
\item La opción \textbf{-l} \emph{lib} se puede usar varias veces para vincular varias bibliotecas.
\item La opción \textbf{-g} se pasa al comando \texttt{ccom} (el programa que realiza la compilación real de C).
\item Supondremos que el optimizador es un programa independiente llamado \emph{optimize} que acepta un archivo de código objeto como argumento y lo optimiza <<en su lugar>>, es decir, sin producir un archivo de salida separado.
\end{itemize}
Para nuestro front-end, hemos elegido dejar que el shell se encargue de imprimir el mensaje de uso. Aquí está el código para el script occ que incluye el procesamiento de opciones:
Para nuestro front-end, hemos elegido dejar que el shell se encargue de imprimir el mensaje de uso. Aquí está el código para el script \emph{occ} que incluye el procesamiento de opciones:
\begin{lstlisting}[language=bash]
# inicializar variables relacionadas con las opciones
@ -353,11 +353,11 @@ print "Solo quedan $(( (365-$(date +%j)) / 7 )) semanas hasta el Año Nuevo!"
Mostraremos dónde encaja esto en el esquema general del procesamiento de la línea de comandos en el \hyperref[sec:Chapter7]{Capítulo 7}.
La función de expresiones aritméticas está integrada en la sintaxis del shell Korn y estaba disponible en el shell Bourne (en la mayoría de las versiones) solo a través del comando externo \emph{expr(1)}. Así que es otro ejemplo de una característica deseable proporcionada por un comando externo (es decir, un truco sintáctico) que se integra mejor en el shell. \texttt{[[...]]} y getopts son también ejemplos de esta tendencia de diseño.
La función de expresiones aritméticas está integrada en la sintaxis del shell de Korn y estaba disponible en el shell de Bourne (en la mayoría de las versiones) solo a través del comando externo \emph{expr(1)}. Así que es otro ejemplo de una característica deseable proporcionada por un comando externo (es decir, un truco sintáctico) que se integra mejor en el shell. \texttt{[[...]]} y \emph{getopts} son también ejemplos de esta tendencia de diseño.
Mientras que \texttt{expr} y \emph{ksh88} estaban limitados a la aritmética entera, \emph{ksh93} admite la aritmética de punto flotante. Como veremos en breve, puedes realizar prácticamente cualquier cálculo en el shell Korn que podrías hacer en C o en la mayoría de los otros lenguajes de programación.
Mientras que \texttt{expr} y \emph{ksh88} estaban limitados a la aritmética entera, \emph{ksh93} admite la aritmética de punto flotante. Como veremos en breve, puedes realizar prácticamente cualquier cálculo en el shell de Korn que podrías hacer en C o en la mayoría de los otros lenguajes de programación.
Los operadores aritméticos del shell Korn son equivalentes a sus contrapartes en el lenguaje C. La precedencia y la asociatividad son las mismas que en C. (Más detalles sobre la compatibilidad del shell Korn con el lenguaje C se pueden encontrar en el \hyperref[sec:ApendiceB]{Apéndice B}; dichos detalles son de interés principalmente para personas que ya están familiarizadas con C.) La Tabla \ref{Tab:6-2} muestra los operadores aritméticos que se admiten, en orden de mayor a menor precedencia. Aunque algunos de ellos son (o contienen) caracteres especiales, no es necesario escaparlos con barra invertida, porque están dentro de la sintaxis \texttt{\$((...))}.
Los operadores aritméticos del shell de Korn son equivalentes a sus contrapartes en el lenguaje C. La precedencia y la asociatividad son las mismas que en C. (Más detalles sobre la compatibilidad del shell de Korn con el lenguaje C se pueden encontrar en el \hyperref[sec:ApendiceB]{Apéndice B}; dichos detalles son de interés principalmente para personas que ya están familiarizadas con C.) La Tabla \ref{Tab:6-2} muestra los operadores aritméticos que se admiten, en orden de mayor a menor precedencia. Aunque algunos de ellos son (o contienen) caracteres especiales, no es necesario escaparlos con barra invertida, porque están dentro de la sintaxis \texttt{\$((...))}.
\begin{table}[h]
\small
@ -367,7 +367,7 @@ Los operadores aritméticos del shell Korn son equivalentes a sus contrapartes e
\begin{tabular}{|m{5cm}|m{6cm}|m{4cm}|} \hline
\textbf{Operador} & \textbf{Significado} & \textbf{Asociatividad} \\\hline
\texttt{++ --} & Incremento y decremento, prefijo y postfijo & De izquierda a derecha \\\hline
\texttt{+ - ! \~{}} & Más y menos unario; megación lógica y bit a bit & De derecha a izquierda \\\hline
\texttt{+ - ! \~{}} & Más y menos unario; negación lógica y bit a bit & De derecha a izquierda \\\hline
\texttt{**} & Exponenciación \tablefootnote{\emph{ksh93m} y más reciente. El operador ** no está en lenguaje C.} & De derecha a izquierda \\\hline
\texttt{* / \%} & Multiplicación, división y resta & De izquierda a derecha \\\hline
\texttt{+ -} & Adición y sustracción & De izquierda a derecha \\\hline
@ -698,7 +698,7 @@ Antes de dejar este tema, aquí tienes algunos ejercicios que deberían poner a
\end{enumerate}
\section{for aritmétrico}
El bucle \texttt{for} descrito en el \hyperref[sec:Chapter5]{Capítulo 5} ha estado en los shells Unix desde la versión 7 del Bourne Shell. Como se ha mencionado, no puede hacer bucles al estilo Pascal o C para un número fijo de iteraciones con ese bucle \texttt{for}. \emph{ksh93} introdujo el bucle aritmético for para remediar esta situación y para acercar el shell a un lenguaje de programación tradicional (algunos dirían <<real>>).
El bucle \texttt{for} descrito en el \hyperref[sec:Chapter5]{Capítulo 5} ha estado en los shells Unix desde la versión 7 del Bourne Shell. Como se ha mencionado, no puede hacer bucles al estilo Pascal o C para un número fijo de iteraciones con ese bucle \texttt{for}. \emph{ksh93} introdujo el bucle aritmético \emph{for} para remediar esta situación y para acercar el shell a un lenguaje de programación tradicional (algunos dirían <<real>>).
La sintaxis se parece a las facilidades aritméticas del shell que acabamos de ver. Es casi idéntica a la sintaxis del bucle \texttt{for} de C, excepto por el conjunto extra de paréntesis:
@ -711,7 +711,7 @@ done
Aquí, \emph{init} representa algo que debe hacerse una vez, al comienzo del bucle. La \emph{condición} se comprueba, y mientras sea verdadera, el shell ejecuta las \emph{sentencias}. Antes de volver al principio del bucle para comprobar la condición de nuevo, el shell ejecuta \emph{increment}.
Cualquier \emph{init, condition} e \emph{increment} puede ser omitida. Una condición \emph{omitida} se trata como \emph{verdadera}; es decir, el cuerpo del bucle siempre se ejecuta. (El llamado <<bucle infinito>> requiere que utilice algún otro método para salir del bucle). Utilizaremos el bucle aritmético for para la \hyperref[box:6-2]{Tarea 6-2}, que es nuestra siguiente tarea, bastante simple.
Cualquier \emph{init, condition} e \emph{increment} puede ser omitida. Una condición \emph{omitida} se trata como \emph{verdadera}; es decir, el cuerpo del bucle siempre se ejecuta. (El llamado <<bucle infinito>> requiere que utilice algún otro método para salir del bucle). Utilizaremos el bucle aritmético \emph{for} para la \hyperref[box:6-2]{Tarea 6-2}, que es nuestra siguiente tarea, bastante simple.
\begin{mybox}[Tarea 6-2]\label{box:6-2}
Escribe un script simple que tome una lista de números en la línea de comandos y los sume, imprimiendo el resultado.
@ -730,17 +730,17 @@ done
print $sum
\end{lstlisting}
La primera línea inicializa la variable \texttt{sum} a 0. \texttt{sum} acumula la suma de los argumentos. La segunda línea es más que nada para facilitar la lectura; \texttt{count} indica cuántos argumentos hay. La tercera línea inicia el bucle propiamente dicho. La variable \texttt{i} es la variable de control del bucle. La cláusula \emph{init} la pone a 1, la cláusula \emph{condition} la comprueba con el límite de \texttt{count}, y la cláusula \texttt{increment} le añade 1 cada vez que se pasa por el bucle. Una cosa que notará de inmediato es que dentro del encabezado del bucle \texttt{for}, no hay necesidad del \$ delante del nombre de una variable para obtener el valor de esa variable. Esto es cierto para cualquier expresión aritmética en el shell Korn.
La primera línea inicializa la variable \texttt{sum} a 0. \texttt{sum} acumula la suma de los argumentos. La segunda línea es más que nada para facilitar la lectura; \texttt{count} indica cuántos argumentos hay. La tercera línea inicia el bucle propiamente dicho. La variable \texttt{i} es la variable de control del bucle. La cláusula \emph{init} la pone a 1, la cláusula \emph{condition} la comprueba con el límite de \texttt{count}, y la cláusula \texttt{increment} le añade 1 cada vez que se pasa por el bucle. Una cosa que notará de inmediato es que dentro del encabezado del bucle \texttt{for}, no hay necesidad del \$ delante del nombre de una variable para obtener el valor de esa variable. Esto es cierto para cualquier expresión aritmética en el shell de Korn.
El cuerpo del bucle hace la suma. Simplemente deja que haga las cuentas: la suma se consigue añadiendo \texttt{\$1} al valor de \texttt{sum}. El comando \emph{shift} mueve el siguiente argumento a \texttt{\$1} para usarlo en la siguiente vuelta del bucle. Finalmente, cuando el bucle termina, el script imprime el resultado.
El bucle for aritmético es particularmente útil para trabajar con todos los elementos de un array indexado, que veremos en la siguiente sección.
El bucle \emph{for} aritmético es particularmente útil para trabajar con todos los elementos de un array indexado, que veremos en la siguiente sección.
\section{Arrays (matrices)}
Hasta ahora, hemos visto tres tipos de variables: cadenas de caracteres, enteros y números de punto flotante. El cuarto tipo de variable que admite el shell de Korn es un \texttt{array}. Como probablemente sepas, un array es como una lista de cosas; puedes referirte a elementos específicos en un array con \emph{índices}, de modo que \texttt{a[i]} se refiere al \emph{i-ésimo} elemento del array a. El shell Korn proporciona dos tipos de \emph{arrays}: \emph{arrays} indexados y \emph{arrays} asociativos.
Hasta ahora, hemos visto tres tipos de variables: cadenas de caracteres, enteros y números de punto flotante. El cuarto tipo de variable que admite el shell de Korn es un \texttt{array}. Como probablemente sepas, un array es como una lista de cosas; puedes referirte a elementos específicos en un array con \emph{índices}, de modo que \texttt{a[i]} se refiere al \emph{i-ésimo} elemento del array a. El shell de Korn proporciona dos tipos de \emph{arrays}: \emph{arrays} indexados y \emph{arrays} asociativos.
\subsection{Matrices indexadas}
El shell Korn proporciona una funcionalidad de arrays indexados que, aunque útil, es mucho más limitada que las características análogas en lenguajes de programación convencionales. En particular, los arrays indexados solo pueden ser unidimensionales (es decir, no hay arrays de arrays) y están limitados a 4096 elementos.\footnote{4096 es un valor mínimo en \emph{ksh93}. Las versiones recientes permiten hasta 64K elementos.}
El shell de Korn proporciona una funcionalidad de arrays indexados que, aunque útil, es mucho más limitada que las características análogas en lenguajes de programación convencionales. En particular, los arrays indexados solo pueden ser unidimensionales (es decir, no hay arrays de arrays) y están limitados a 4096 elementos.\footnote{4096 es un valor mínimo en \emph{ksh93}. Las versiones recientes permiten hasta 64K elementos.}
Los índices comienzan en 0. Esto implica que el valor máximo del índice es 4095. Además, los índices pueden ser cualquier expresión aritmética: \emph{ksh} evalúa automáticamente la expresión para obtener el índice real.
Hay tres formas de asignar valores a elementos de un array. La primera es la más intuitiva: puedes usar la sintaxis estándar de asignación de variables del shell con el índice del array entre corchetes ([]). Por ejemplo:
@ -750,7 +750,7 @@ nicknames[2]=bob
nicknames[3]=ed
\end{lstlisting}
Estas asignaciones colocan los valores \texttt{bob} y \texttt{ed} en los elementos del array \texttt{nicknames} con índices 2 y 3, respectivamente. Al igual que con las variables regulares del shell, los valores asignados a elementos del array se tratan como cadenas de caracteres a menos que la asignación esté precedida por \texttt{let}, o el array se haya declarado numérico con una de las opciones \texttt{typeset -i, -ui, -E} o \texttt{-F}. (Estrictamente hablando, el valor asignado con let sigue siendo una cadena; es solo que con \emph{let}, el shell evalúa la expresión aritmética que se asigna para producir esa cadena).
Estas asignaciones colocan los valores \texttt{bob} y \texttt{ed} en los elementos del array \texttt{nicknames} con índices 2 y 3, respectivamente. Al igual que con las variables regulares del shell, los valores asignados a elementos del array se tratan como cadenas de caracteres a menos que la asignación esté precedida por \texttt{let}, o el array se haya declarado numérico con una de las opciones \texttt{typeset -i, -ui, -E} o \texttt{-F}. (Estrictamente hablando, el valor asignado con \emph{let} sigue siendo una cadena; es solo que con \emph{let}, el shell evalúa la expresión aritmética que se asigna para producir esa cadena).
La segunda forma de asignar valores a un array es con una variante de la declaración set, que vimos en el \hyperref[sec:Chapter3]{Capítulo 3}. La declaración:
@ -1094,7 +1094,7 @@ fi
La primera línea configura el array \texttt{filenames} para contener todos los archivos en el directorio dado por el primer argumento (el directorio actual por defecto). La declaración \texttt{typeset} configura la variable \texttt{fname} para tener un ancho fijo de 14 caracteres. La siguiente línea inicializa \texttt{numcols} con el número de columnas por línea.
El bucle for aritmético itera una vez por cada elemento en \texttt{filenames}. En el cuerpo del bucle, la primera línea asigna el próximo elemento del array a la variable de ancho fijo. La declaración \texttt{print} imprime este último seguido de dos espacios; la opción \texttt{-n} suprime la última nueva línea de \texttt{print}.
El bucle \emph{for} aritmético itera una vez por cada elemento en \texttt{filenames}. En el cuerpo del bucle, la primera línea asigna el próximo elemento del array a la variable de ancho fijo. La declaración \texttt{print} imprime este último seguido de dos espacios; la opción \texttt{-n} suprime la última nueva línea de \texttt{print}.
Luego está la declaración \texttt{if}, que determina cuándo comenzar la próxima línea. Verifica el resto de \texttt{(count + 1) \% numcols} - recuerda que los signos de dólar no son necesarios dentro de la construcción \texttt{\$((...))} - y si el resultado es 0, es hora de emitir una nueva línea a través de una declaración \texttt{print} sin argumentos. Observa que aunque \texttt{\$count} aumenta en 1 con cada iteración del bucle, el resto pasa por un ciclo de 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, ...
@ -1149,11 +1149,11 @@ Las otras opciones de \texttt{typeset} son más útiles para programadores avanz
-Fn & Representa la variable internamente como un número de punto flotante de doble precisión; mejora la eficiencia de la aritmética de punto flotante. Si se da \emph{n}, es el número de decimales a utilizar en la salida. Todos los valores se imprimen en notación regular: \texttt{[-]ddd.ddd}. \\\hline
-H & En sistemas que no son Unix, los nombres de archivo de estilo Unix se convierten al formato apropiado para el sistema local. \\\hline
-in & Representa la variable internamente como un entero; mejora la eficiencia de la aritmética de enteros. Si se da \emph{n}, es la base utilizada para la salida. La base por defecto es 10. \\\hline
-n & Crea una variable nameref (ver \hyperref[sec:Chapter4]{Capítulo 4}). \\\hline
-n & Crea una variable \emph{nameref} (ver \hyperref[sec:Chapter4]{Capítulo 4}). \\\hline
-p & Cuando se utiliza por sí mismo, imprime declaraciones compuestas (\texttt{typeset}) que describen los atributos de cada una de las variables del shell que tienen atributos establecidos. Con opciones adicionales, solo imprime aquellas variables que tienen el atributo correspondiente establecido. Destinado para volcar el estado del shell en un archivo que luego puede ser utilizado por un shell diferente para recrear el estado original del shell. \\\hline
-r & Hace que la variable sea de solo lectura: prohíbe la asignación a la misma y no permite que sea \emph{desestablecida}. El comando integrado \texttt{readonly} hace lo mismo, pero \texttt{readonly} no puede ser usado para variables locales. \\\hline
-t & <<Etiqueta>> la variable. La lista de variables etiquetadas está disponible mediante \texttt{typeset +t}. Esta opción está obsoleta. \\\hline
-uin & Representa la variable internamente como un entero \emph{sin signo}. Esto se discute más adelante en el \hyperref[sec:ApendiceB]{Apéndice B}. Si se proporciona \emph{n}, es la base utilizada para la salida. La base predeterminada es 10.\tablefootnote{Esta función sólo está disponible en ksh93m y posteriores.} \\\hline
-uin & Representa la variable internamente como un entero \emph{sin signo}. Esto se discute más adelante en el \hyperref[sec:ApendiceB]{Apéndice B}. Si se proporciona \emph{n}, es la base utilizada para la salida. La base predeterminada es 10.\tablefootnote{Esta función sólo está disponible en \emph{ksh93m} y posteriores.} \\\hline
-x & Esto hace lo mismo que el comando \texttt{export}, pero \texttt{export} no puede ser utilizado para variables locales. \\\hline
-f & Hace referencia solo a nombres de funciones; consulte la \hyperref[sec:6.5.4]{Sección 6.5.4}, más adelante en este capítulo. \\\hline
\end{longtable}

View File

@ -5,7 +5,7 @@ En segundo lugar, nos centraremos en la E/S a nivel de línea y palabra. Este es
Nuestra discusión sobre la E/S de línea y palabra nos llevará a una explicación más detallada de cómo el shell procesa las líneas de comandos. Esta información es necesaria para que puedas entender exactamente cómo el shell maneja las \emph{citas} y para que puedas apreciar el poder de un comando avanzado llamado \texttt{eval}, que cubriremos al final del capítulo.
\section{Redireccionadores de E/S}
En el \hyperref[sec:Chapter1]{Capítulo 1} aprendiste sobre los redireccionadores básicos de E/S del shell, \texttt{<}, \texttt{>}, y \texttt{|}. Aunque estos son suficientes para cubrir el 95\% de tu vida en Unix, debes saber que el shell Korn admite un total de 20 redireccionadores de E/S. La Tabla \ref{Tab:7-1} los enumera, incluyendo los tres que ya hemos visto. Aunque algunos de los demás son útiles, otros son principalmente para programadores de sistemas. Esperaremos hasta el próximo capítulo para discutir los últimos tres, que, junto con \texttt{>|} y \texttt{<<<}, no están presentes en la mayoría de las versiones del shell Bourne.
En el \hyperref[sec:Chapter1]{Capítulo 1} aprendiste sobre los redireccionadores básicos de E/S del shell, \texttt{<}, \texttt{>}, y \texttt{|}. Aunque estos son suficientes para cubrir el 95\% de tu vida en Unix, debes saber que el shell de Korn admite un total de 20 redireccionadores de E/S. La Tabla \ref{Tab:7-1} los enumera, incluyendo los tres que ya hemos visto. Aunque algunos de los demás son útiles, otros son principalmente para programadores de sistemas. Esperaremos hasta el próximo capítulo para discutir los últimos tres, que, junto con \texttt{>|} y \texttt{<<<}, no están presentes en la mayoría de las versiones del shell de Bourne.
\begin{table}[h]
\center
@ -17,7 +17,7 @@ En el \hyperref[sec:Chapter1]{Capítulo 1} aprendiste sobre los redireccionadore
< file & Tomar entrada estándar del archivo \\\hline
cmd1 | cmd2 & Tubería; tomar salida estándar de cmd1 como entrada estándar a cmd2 \\\hline
$>>$ file & Dirigir la salida estándar al archivo; añadir al archivo si ya existe \\\hline
>| file & Fuerza la salida estándar a fichero incluso si noclobber está activado \\\hline
>| file & Fuerza la salida estándar a fichero incluso si \emph{noclobber} está activado \\\hline
<> file & Abrir archivo tanto para lectura como para escritura en la entrada estándar\tablefootnote{Normalmente, los archivos abiertos con \texttt{<} se abren en modo de solo lectura.} \\\hline
$<<$ label & \emph{here-document}; ver texto \\\hline
$<<-$ label & \emph{here-document} variante; ver texto \\\hline
@ -142,7 +142,7 @@ EOF
\end{lstlisting}
A partir de \emph{ksh93n}, \footnote{Gracias a David Korn por proporcionarme acceso previo a la versión con esta característica. ADR.}
el shell Korn proporciona una nueva forma de here-document, usando tres signos de menor que:
el shell de Korn proporciona una nueva forma de here-document, usando tres signos de menor que:
\begin{lstlisting}[language=bash]
program <<< WORD
@ -155,14 +155,14 @@ En esta forma, el texto de WORD (seguido de un salto de línea final) se convier
interrogate -i mild <<< "$name, $rank, $serial_num"
\end{lstlisting}
Esta notación se originó por primera vez en la versión de Unix del shell \texttt{rc}, donde se llama <<here string>>. Luego fue adoptada por el shell Z, \emph{zsh} (ver \hyperref[sec:ApendiceA]{Apéndice A}), del cual el shell Korn lo tomó prestado. Esta notación es simple, fácil de usar, eficiente y visualmente distinguible de los \emph{here-documents} regulares.
Esta notación se originó por primera vez en la versión de Unix del shell \texttt{rc}, donde se llama <<here string>>. Luego fue adoptada por el shell Z, \emph{zsh} (ver \hyperref[sec:ApendiceA]{Apéndice A}), del cual el shell de Korn lo tomó prestado. Esta notación es simple, fácil de usar, eficiente y visualmente distinguible de los \emph{here-documents} regulares.
\subsection{Descriptores de ficheros}
Los siguientes redireccionadores en la Tabla \ref{Tab:7-1} dependen de la noción de un \emph{descriptor de archivo}. Este es un concepto de E/S (Entrada/Salida) de bajo nivel en Unix que es vital entender al programar en C o C++. Aparece a nivel del shell cuando quieres hacer algo que no involucra la entrada estándar, la salida estándar y el error estándar. Puedes manejarte con algunos hechos básicos sobre ellos; para toda la información, consulta las entradas \emph{open(2), creat(2), read(2), write(2), dup(2), dup2(2), fcntl(2)} y \emph{close(2)} en el manual de Unix. (Como las entradas del manual están dirigidas al programador en C, su relación con los conceptos del shell no será necesariamente obvia).
Los descriptores de archivo son enteros que comienzan en 0 que indexan un array de información de archivos dentro de un proceso. Cuando un proceso se inicia, tiene tres descriptores de archivo abiertos. Estos corresponden a los tres estándares: entrada estándar (descriptor de archivo 0), salida estándar (1) y error estándar (2). Si un proceso abre archivos Unix para entrada o salida, se les asignan los siguientes descriptores de archivo disponibles, comenzando por 3.
De lejos, el uso más común de los descriptores de archivo con el shell Korn es guardar el error estándar en un archivo. Por ejemplo, si deseas guardar los mensajes de error de un trabajo largo en un archivo para que no desplacen la pantalla, agrega \texttt{2> archivo} a tu comando. Si también deseas guardar la salida estándar, agrega \texttt{> archivo1 2> archivo2}.
De lejos, el uso más común de los descriptores de archivo con el shell de Korn es guardar el error estándar en un archivo. Por ejemplo, si deseas guardar los mensajes de error de un trabajo largo en un archivo para que no desplacen la pantalla, agrega \texttt{2> archivo} a tu comando. Si también deseas guardar la salida estándar, agrega \texttt{> archivo1 2> archivo2}.
Esto nos lleva a la \hyperref[box:7-3]{Tarea 7-3}.
@ -322,7 +322,7 @@ La secuencia \texttt{\textbackslash{}0n} es aún más dependiente del dispositi
\begin{tabular}{|m{2cm}|m{13cm}|} \hline
\textbf{Opción} & \textbf{Función} \\ \hline
-e & Procesar secuencias de escape en los argumentos (este es el valor por defecto). \\\hline
-f \emph{format} & Imprime como si fuera mediante printf con el formato dado (véase la sección siguiente). \\\hline
-f \emph{format} & Imprime como si fuera mediante \emph{printf} con el formato dado (véase la sección siguiente). \\\hline
-n & Omite la nueva línea final (igual que la secuencia de escape \textbackslash{}c). \\\hline
-p & Imprime en la tubería a la coroutine; ver \hyperref[sec:Chapter8]{Capítulo 8}. \\\hline
-r & Raw; ignora las secuencias de escape listadas arriba. \\\hline
@ -484,8 +484,8 @@ Si \emph{printf} no puede realizar una conversión de formato, devuelve un estad
Similar a \emph{print}, el comando \emph{printf} incorporado interpreta secuencias de escape dentro de la cadena de formato. Sin embargo, \emph{printf} acepta un rango más amplio de secuencias de escape; son las mismas que para la cadena \texttt{\$'...'}. Estas secuencias se enumeran más adelante en la Tabla \ref{Tab:7-9}.
\subsection{Especificadores adicionales de printf en el shell Korn}
Además de los especificadores estándar recién descritos, el shell Korn acepta varios especificadores adicionales. Estos proporcionan funciones útiles a expensas de la no portabilidad a otras versiones del comando \emph{printf}.
\subsection{Especificadores adicionales de printf en el shell de Korn}
Además de los especificadores estándar recién descritos, el shell de Korn acepta varios especificadores adicionales. Estos proporcionan funciones útiles a expensas de la no portabilidad a otras versiones del comando \emph{printf}.
\begin{description}
\item[\$b] Cuando se utiliza en lugar de \%s, expande las secuencias de escape de estilo de impresión en la cadena del argumento. Por ejemplo:
@ -515,7 +515,7 @@ hola, mundo
$ print $msglen
13
\end{lstlisting}
\item[\%P] Cuando se utiliza en lugar de \%s, traduce la expresión regular extendida de estilo \emph{egrep} a un patrón de shell Korn equivalente. Por ejemplo:
\item[\%P] Cuando se utiliza en lugar de \%s, traduce la expresión regular extendida de estilo \emph{egrep} a un patrón de shell de Korn equivalente. Por ejemplo:
\begin{lstlisting}[language=bash]
$ printf "%P\n" '(.*\.o|.*\.obj|core)+'
@ -544,7 +544,7 @@ $ printf "%(Ahora es %m/%d/%Y %H:%M:%S)T\n" "$(date)"
Ahora es 30/01/2002 15:46:07
\end{lstlisting}
Los sistemas Unix mantienen el tiempo en <<segundos desde Epoch>>. Epoch es la medianoche del 1 de enero de 1970, UTC. Si dispone de un valor de tiempo en este formato, puede utilizarlo con el especificador de conversión \%T precediéndolo de un carácter \#, así:
Los sistemas Unix mantienen el tiempo en <<segundos desde Epoch>>. \emph{Epoch} es la medianoche del 1 de enero de 1970, UTC. Si dispone de un valor de tiempo en este formato, puede utilizarlo con el especificador de conversión \%T precediéndolo de un carácter \#, así:
\begin{lstlisting}[language=bash]
$ printf "%(It is now %m/%d/%Y %H:%M:%S)T\n" '#1012398411'
@ -601,7 +601,7 @@ Sin embargo, los scripts de shell con \emph{read} son útiles para ciertos tipos
Una tarea que ya hemos visto se ajusta a esta descripción: la \hyperref[box:5-4]{Tarea 5-4}, el script que un administrador del sistema podría usar para establecer la variable de entorno TERM de un usuario según la línea de terminal que esté utilizando. El código en el \hyperref[sec:Chapter5]{Capítulo 5} utilizó una declaración \texttt{case} para seleccionar el valor correcto para \texttt{TERM}.
Este código presumiblemente residiría en \texttt{/etc/profile}, el archivo de inicialización del sistema que el shell Korn ejecuta antes de ejecutar el \emph{.profile} de un usuario. Si las terminales en el sistema cambian con el tiempo, como seguramente lo harán, entonces el código tendría que cambiarse. Sería mejor almacenar la información en un archivo y cambiar solo el archivo en su lugar.
Este código presumiblemente residiría en \texttt{/etc/profile}, el archivo de inicialización del sistema que el shell de Korn ejecuta antes de ejecutar el \emph{.profile} de un usuario. Si las terminales en el sistema cambian con el tiempo, como seguramente lo harán, entonces el código tendría que cambiarse. Sería mejor almacenar la información en un archivo y cambiar solo el archivo en su lugar.
Supongamos que colocamos la información en un archivo cuyo formato es típico de los archivos de <<configuración del sistema>> de Unix: cada línea contiene un nombre de dispositivo, un TAB y un valor de TERM. Si el archivo, que llamaremos \texttt{/etc/terms}, contenía los mismos datos que la declaración \texttt{case} en el \hyperref[sec:Chapter5]{Capítulo 5}, se vería así:
@ -634,7 +634,7 @@ El bucle \texttt{while} lee cada línea de la entrada en las variables \texttt{d
Aún no hemos terminado: ¡este código lee desde la entrada estándar, no desde \texttt{/etc/terms}! Necesitamos saber cómo redirigir la entrada a múltiples comandos. Hay varias maneras de hacer esto.
\subsubsection{Redirección de E/S y comandos múltiples}
Una forma de resolver el problema es con un subproceso, como veremos en el próximo capítulo. Esto implica crear un proceso separado para realizar la lectura. Sin embargo, generalmente es más eficiente hacerlo en el mismo proceso; el shell Korn nos ofrece tres formas de hacer esto.
Una forma de resolver el problema es con un subproceso, como veremos en el próximo capítulo. Esto implica crear un proceso separado para realizar la lectura. Sin embargo, generalmente es más eficiente hacerlo en el mismo proceso; el shell de Korn nos ofrece tres formas de hacer esto.
La primera, que ya hemos visto, es con una función:
@ -760,7 +760,7 @@ ls "$@" | {
Este código parece un ejercicio de una clase de programación del primer semestre. El bucle \texttt{while} recorre la entrada en busca de archivos con nombres más largos que el más largo encontrado hasta ahora; si se encuentra uno más largo, su longitud se guarda como la nueva longitud más larga.
Después de que el bucle termina, agregamos 2 al ancho para permitir espacio entre columnas. Luego dividimos el ancho del terminal por el ancho de la columna para obtener el número de columnas. Como el shell realiza la división en punto flotante, el resultado se pasa a la función int para producir un resultado final entero. Recuerda del \hyperref[sec:Chapter3]{Capítulo 3} que la variable integrada COLUMNS a menudo contiene el ancho de visualización; la construcción \texttt{\$\{COLUMNS:-80\}} da un valor predeterminado de 80 si esta variable no está configurada.
Después de que el bucle termina, agregamos 2 al ancho para permitir espacio entre columnas. Luego dividimos el ancho del terminal por el ancho de la columna para obtener el número de columnas. Como el shell realiza la división en punto flotante, el resultado se pasa a la función \emph{int} para producir un resultado final entero. Recuerda del \hyperref[sec:Chapter3]{Capítulo 3} que la variable integrada \texttt{COLUMNS} a menudo contiene el ancho de visualización; la construcción \texttt{\$\{COLUMNS:-80\}} da un valor predeterminado de 80 si esta variable no está configurada.
Los resultados del bloque son las variables \texttt{width} y \texttt{numcols}. Estas son variables globales, por lo que son accesibles por el resto del código dentro de nuestro script (eventual). En particular, las necesitamos en nuestra segunda pasada por los nombres de archivo. El código para esto se asemeja al código de nuestra solución original; todo lo que necesitamos hacer es reemplazar el ancho de columna fijo y el número de columnas con las variables:
@ -1248,7 +1248,7 @@ function cd {
cd $PWD # establecer el prompt
\end{lstlisting}
Como vimos en el \hyperref[sec:Chapter5]{Capítulo 5}, escribir una función con el mismo nombre que un comando incorporado parece bastante extraño a primera vista. Pero, siguiendo el estándar POSIX, el shell Korn distingue entre comandos incorporados <<especiales>> y comandos incorporados regulares. Cuando el shell busca comandos para ejecutar, encuentra funciones antes de encontrar comandos incorporados regulares. \emph{cd} es un comando incorporado regular, así que esto funciona. Dentro de la función, usamos el comando ingeniosamente llamado \emph{command} para acceder realmente al comando \emph{cd} real.\footnote{Como se mencionó anteriormente, \texttt{command} no es un comando incorporado especial. ¡Ay del programador del shell que escriba una función llamada \texttt{command!}}
Como vimos en el \hyperref[sec:Chapter5]{Capítulo 5}, escribir una función con el mismo nombre que un comando incorporado parece bastante extraño a primera vista. Pero, siguiendo el estándar POSIX, el shell de Korn distingue entre comandos incorporados <<especiales>> y comandos incorporados regulares. Cuando el shell busca comandos para ejecutar, encuentra funciones antes de encontrar comandos incorporados regulares. \emph{cd} es un comando incorporado regular, así que esto funciona. Dentro de la función, usamos el comando ingeniosamente llamado \emph{command} para acceder realmente al comando \emph{cd} real.\footnote{Como se mencionó anteriormente, \texttt{command} no es un comando incorporado especial. ¡Ay del programador del shell que escriba una función llamada \texttt{command!}}
La declaración \texttt{command cd "\$@"} pasa los argumentos de la función al \emph{cd} real para cambiar el directorio. (Como nota al margen, el shell define un alias \texttt{command='command '}, lo que te permite usar \texttt{command} con alias).
Cuando inicias sesión, este código establece \texttt{PS1} en el directorio actual inicial (presumiblemente tu directorio principal). Luego, cada vez que ingresas un comando \emph{cd}, la función se ejecuta para cambiar el directorio y restablecer el prompt.
@ -1256,7 +1256,7 @@ Cuando inicias sesión, este código establece \texttt{PS1} en el directorio act
Por supuesto, la función \texttt{tildize} puede ser cualquier código que formatee la cadena del directorio. Consulta los ejercicios al final de este capítulo para obtener algunas sugerencias.
\subsubsection{Cita ampliada}\label{sec:7.3.3.1}
Las comillas simples y dobles han estado presentes en el shell de Bourne y sus derivados desde el principio (aunque el shell de Bourne original no realiza aritmética ni sustitución de \texttt{\$(...)}). El shell Korn ofrece versiones variantes de cadenas tanto con comillas simples como dobles, de la siguiente manera.
Las comillas simples y dobles han estado presentes en el shell de Bourne y sus derivados desde el principio (aunque el shell de Bourne original no realiza aritmética ni sustitución de \texttt{\$(...)}). El shell de Korn ofrece versiones variantes de cadenas tanto con comillas simples como dobles, de la siguiente manera.
\begin{description}
\item[\texttt{\$"..."}] Esta versión es la más simple. Es similar a una cadena de comillas dobles regular. Sin embargo, estas cadenas están sujetas a la \emph{traducción de localización} en tiempo de ejecución. Esto se describe más adelante, a continuación.
@ -1315,7 +1315,7 @@ listpage="ls | more"
$listpage
\end{lstlisting}
En lugar de producir una lista de archivos paginada, el shell trata | y \texttt{more} como argumentos de \emph{ls}, y \emph{ls} se queja de que no existen archivos con esos nombres. ¿Por qué? Porque el carácter de tubería <<aparece>> en el paso 5 cuando el shell evalúa la variable, \emph{después} de que realmente ha buscado los caracteres de tubería (en el paso 2). La expansión de la variable ni siquiera se analiza hasta el paso 10. Como resultado, el shell trata | y \emph{more} como argumentos de \emph{ls}, de modo que ls intenta encontrar archivos llamados | y \emph{more} en el directorio actual.
En lugar de producir una lista de archivos paginada, el shell trata | y \texttt{more} como argumentos de \emph{ls}, y \emph{ls} se queja de que no existen archivos con esos nombres. ¿Por qué? Porque el carácter de tubería <<aparece>> en el paso 5 cuando el shell evalúa la variable, \emph{después} de que realmente ha buscado los caracteres de tubería (en el paso 2). La expansión de la variable ni siquiera se analiza hasta el paso 10. Como resultado, el shell trata | y \emph{more} como argumentos de \emph{ls}, de modo que \emph{ls} intenta encontrar archivos llamados | y \emph{more} en el directorio actual.
Ahora considera \texttt{eval \$listpage} en lugar de simplemente \texttt{\$listpage}. Cuando el shell llega al último paso, ejecuta el comando \emph{eval} con los argumentos \emph{ls}, | y \emph{more}. Esto hace que el shell vuelva al Paso 1 con una línea que consiste en estos argumentos. Encuentra | en el Paso 2 y divide la línea en dos comandos, \emph{ls} y \emph{more}. Cada comando se procesa de la manera normal (y en ambos casos de manera trivial). El resultado es una lista paginada de los archivos en tu directorio actual.
@ -1346,7 +1346,7 @@ En otras palabras, decidimos qué canalización ejecutar según si \texttt{\$2}
eval sort -nr \$1 ${2:+"| head -\$2"}
\end{lstlisting}
La última expresión en esta línea evalúa a la cadena \texttt{| head -\textbackslash{}\$2} si \texttt{\$2} existe (no es nulo); si \texttt{\$2} es nulo, entonces la expresión también es nula. Escapamos los signos de dólar (\texttt{\textbackslash{}\$}) antes de los nombres de las variables para evitar resultados impredecibles si los valores de las variables contienen caracteres especiales como > o |. El backslash efectivamente pospone la evaluación de las variables hasta que se ejecuta el comando eval en sí. Entonces, toda la línea es ya sea:
La última expresión en esta línea evalúa a la cadena \texttt{| head -\textbackslash{}\$2} si \texttt{\$2} existe (no es nulo); si \texttt{\$2} es nulo, entonces la expresión también es nula. Escapamos los signos de dólar (\texttt{\textbackslash{}\$}) antes de los nombres de las variables para evitar resultados impredecibles si los valores de las variables contienen caracteres especiales como > o |. El backslash efectivamente pospone la evaluación de las variables hasta que se ejecuta el comando \emph{eval} en sí. Entonces, toda la línea es ya sea:
\begin{lstlisting}[language=bash]
eval sort -nr \$1 | head -\$2
@ -1417,7 +1417,7 @@ function makecmd {
}
\end{lstlisting}
Esta función lee la línea con el objetivo y las fuentes; la variable \texttt{colon} es solo un marcador de posición para el \texttt{:}. Luego verifica cada fuente para ver si es más nueva que el objetivo, utilizando el operador de prueba de atributo de archivo \texttt{-nt} que vimos en el \hyperref[sec:Chapter5]{Capítulo 5}. Si la fuente es más nueva, lee, imprime y ejecuta los comandos hasta que encuentra una línea que no comienza con un TAB o llega al final del archivo. (El `make` real hace más que esto; consulta los ejercicios al final de este capítulo). Después de ejecutar los comandos, sale del bucle \texttt{for}, para que no ejecute los comandos más de una vez. (No es necesario quitar el TAB inicial del comando. El shell descarta automáticamente los espacios en blanco iniciales).
Esta función lee la línea con el objetivo y las fuentes; la variable \texttt{colon} es solo un marcador de posición para el \texttt{:}. Luego verifica cada fuente para ver si es más nueva que el objetivo, utilizando el operador de prueba de atributo de archivo \texttt{-nt} que vimos en el \hyperref[sec:Chapter5]{Capítulo 5}. Si la fuente es más nueva, lee, imprime y ejecuta los comandos hasta que encuentra una línea que no comienza con un TAB o llega al final del archivo. (El \emph{make} real hace más que esto; consulta los ejercicios al final de este capítulo). Después de ejecutar los comandos, sale del bucle \texttt{for}, para que no ejecute los comandos más de una vez. (No es necesario quitar el TAB inicial del comando. El shell descarta automáticamente los espacios en blanco iniciales).
\subsubsection{El compilador C como tuberia (pipeline)}
Como ejemplo final de \emph{eval}, revisaremos nuestro viejo amigo \emph{occ}, el front-end del compilador C de los tres capítulos anteriores. Recuerda que el front-end del compilador realiza su trabajo llamando a programas separados para realizar la compilación real de C a código objeto (el programa \emph{ccom}), la optimización del código objeto (\texttt{optimize}), el ensamblaje de archivos de código ensamblador (\emph{as}), y la vinculación final de archivos de código objeto en un programa ejecutable (\emph{ld}). Estos programas separados utilizan archivos temporales para almacenar sus salidas.

View File

@ -7,7 +7,7 @@ Pero si has llegado tan lejos en este libro, probablemente no pienses que la mul
En este capítulo, cubrimos la mayoría de las características del shell Korn que se relacionan con la multitarea y el manejo de procesos en general. Decimos <<la mayoría>> porque algunas de estas características son, al igual que los descriptores de archivos que vimos en el \hyperref[sec:Chapter7]{Capítulo 7}, de interés solo para programadores de sistemas de bajo nivel.
Comenzamos mirando ciertos primitivos importantes para identificar procesos y controlarlos durante las sesiones de inicio y dentro de los scripts de shell. Luego nos movemos a una perspectiva de nivel superior, examinando formas de hacer que los procesos se comuniquen entre sí. La facilidad de las corutinas del shell Korn es el esquema de comunicación interprocesos más sofisticado que examinaremos; también analizamos en más detalle conceptos que ya hemos visto, como las tuberías y los subprocesos de shell.
Comenzamos mirando ciertos primitivos importantes para identificar procesos y controlarlos durante las sesiones de inicio y dentro de los scripts de shell. Luego nos movemos a una perspectiva de nivel superior, examinando formas de hacer que los procesos se comuniquen entre sí. La facilidad de las corrutinas del shell Korn es el esquema de comunicación interprocesos más sofisticado que examinaremos; también analizamos en más detalle conceptos que ya hemos visto, como las tuberías y los subprocesos de shell.
No te preocupes por atascarte en detalles técnicos de bajo nivel sobre Unix. Proporcionamos solo la información técnica necesaria para explicar las características de nivel superior, además de algunos otros detalles diseñados para despertar tu curiosidad. Si estás interesado en obtener más información sobre estas áreas, consulta tu Manual del programador de Unix o un libro sobre internos de Unix que sea relevante para tu versión de Unix.
@ -87,11 +87,11 @@ $ jobs -p
2382
\end{lstlisting}
Esto podría ser útil con la sustitución de comandos; consulta la \hyperref[box:8-1]{Tarea 8-1} más adelante en este capítulo. Finalmente, la opción \texttt{-n} lista solo aquellos trabajos cuyo estado ha cambiado desde la última vez que el shell lo informó, ya sea con un comando jobs o de otra manera.
Esto podría ser útil con la sustitución de comandos; consulta la \hyperref[box:8-1]{Tarea 8-1} más adelante en este capítulo. Finalmente, la opción \texttt{-n} lista solo aquellos trabajos cuyo estado ha cambiado desde la última vez que el shell lo informó, ya sea con un comando \emph{jobs} o de otra manera.
Si escribes \emph{fg} sin un argumento, el shell coloca a \texttt{dave | george} en primer plano, porque fue colocado en segundo plano más recientemente. Pero si escribes \texttt{fg \%bob} (o \texttt{fg \%2}), bob irá al primer plano.
También puedes referirte al trabajo colocado más recientemente en segundo plano con \texttt{\%+}. De manera similar, \texttt{\%-} se refiere al trabajo en segundo plano invocado a continuación más recientemente (\emph{bob} en este caso). Eso explica los signos más y menos en lo anterior: el signo más muestra el trabajo invocado más recientemente; el signo menos muestra el trabajo invocado a continuación más recientemente. \footnote{Esto es análogo a \~{}+ y \~{}- como referencias al directorio actual y anterior; consulta la nota al pie en el C\hyperref[sec:Chapter7]{apítulo 7}. Además: \%\% es un sinónimo de \%+.}
También puedes referirte al trabajo colocado más recientemente en segundo plano con \texttt{\%+}. De manera similar, \texttt{\%-} se refiere al trabajo en segundo plano invocado a continuación más recientemente (\emph{bob} en este caso). Eso explica los signos más y menos en lo anterior: el signo más muestra el trabajo invocado más recientemente; el signo menos muestra el trabajo invocado a continuación más recientemente. \footnote{Esto es análogo a \~{}+ y \~{}- como referencias al directorio actual y anterior; consulta la nota al pie en el C\hyperref[sec:Chapter7]{Capítulo 7}. Además: \%\% es un sinónimo de \%+.}
Si más de un trabajo en segundo plano tiene el mismo comando, entonces \texttt{\%command} desambiguará eligiendo el trabajo invocado más recientemente (como cabría esperar). Si esto no es lo que deseas, debes usar el número del trabajo en lugar del nombre del comando. Sin embargo, si los comandos tienen argumentos diferentes, puedes usar \texttt{\%?string} en lugar de \texttt{\%command. \%?string} se refiere al trabajo cuyo comando contiene la cadena. Por ejemplo, supongamos que iniciaste estos trabajos en segundo plano:
@ -167,7 +167,7 @@ Los programadores a menudo utilizan la misma técnica al depurar código fuente.
También es probable que encuentres útil suspender un trabajo y luego reanudarlo en segundo plano en lugar de en primer plano. Puedes iniciar un comando en primer plano (es decir, normalmente) y descubrir que tarda mucho más de lo esperado, por ejemplo, una búsqueda con \emph{grep}, \emph{sort} o una consulta a una base de datos. Necesitas que el comando finalice, pero también te gustaría recuperar el control de tu terminal para poder hacer otras tareas. Si escribes CTRL-Z seguido de \emph{bg}, mueves el trabajo al segundo plano. \footnote{Sin embargo, ten cuidado, ya que no todos los comandos se comportan de manera <<adecuada>> cuando haces esto. Ten especial precaución con los comandos que se ejecutan sobre una red en una máquina remota; podrías <<confundir>> al programa remoto.}
\subsection{Desvinculando un trabajo}
Normalmente, cuando cierras la sesión, el shell envía la señal HUP (consulta la siguiente sección) a cualquier trabajo en segundo plano. Si has iniciado un trabajo de larga duración en segundo plano y deseas que se complete sin importar qué, debes indicárselo al shell mediante el comando \emph{disown} con uno o más números de identificación de trabajo como argumentos. Sin argumentos, se desvinculan \emph{todos} los trabajos en segundo plano.
Normalmente, cuando cierras la sesión, el shell envía la señal \emph{HUP} (consulta la siguiente sección) a cualquier trabajo en segundo plano. Si has iniciado un trabajo de larga duración en segundo plano y deseas que se complete sin importar qué, debes indicárselo al shell mediante el comando \emph{disown} con uno o más números de identificación de trabajo como argumentos. Sin argumentos, se desvinculan \emph{todos} los trabajos en segundo plano.
\section{Señales}
Dijimos anteriormente que escribir CTRL-Z para suspender un trabajo es similar a escribir CTRL-C para detener un trabajo, excepto que puedes reanudar el trabajo más tarde. De hecho, son similares de una manera más profunda: ambos son casos particulares del acto de enviar una \emph{señal} a un proceso.
@ -244,7 +244,7 @@ En sistemas de control de trabajos, hay una señal adicional e inatrapable: STOP
La \hyperref[box:8-1]{Tarea 8-1} es otro ejemplo de cómo usar el comando \emph{kill}.
\begin{mybox}[Tarea 8-1]\label{box:8-1}
Escribe una función llamada `killalljobs` que mate todos los trabajos en segundo plano.\footnote{Para probar tu comprensión de cómo funciona el shell, responde a esta pregunta: ¿por qué esto no se puede hacer como un script separado?}
Escribe una función llamada \emph{killalljobs} que mate todos los trabajos en segundo plano.\footnote{Para probar tu comprensión de cómo funciona el shell, responde a esta pregunta: ¿por qué esto no se puede hacer como un script separado?}
\end{mybox}
La solución para esta tarea es simple, utilizando \texttt{jobs -p}:
@ -341,7 +341,7 @@ Estas opciones indican a \emph{ps} que liste procesos que no se iniciaron desde
De hecho, la salida de \texttt{ps -e} o \texttt{ps -ax} es una excelente fuente de educación sobre los entresijos internos del sistema Unix, si tienes curiosidad por conocerlos. Ejecuta el comando en tu sistema y, para cada línea de la lista que parezca interesante, invoca `man` en el nombre del proceso o búscalo en el Manual del Programador de Unix para tu sistema.
Las shells de usuario y los procesos se enumeran en la parte inferior de la salida de \texttt{ps -e} o \texttt{ps -ax}; aquí es donde debes buscar procesos fuera de control. Observa que muchos procesos en la lista tienen un ? en lugar de un terminal. Estos bien no deberían tener uno (como los daemons básicos) o son procesos fuera de control. Por lo tanto, es probable que si \texttt{ps -a} no encuentra un proceso que estás intentando eliminar, \texttt{ps -e} (o \texttt{ps -ax}) lo mostrará con ? en la columna TTY (o TT). Puedes determinar qué proceso deseas observando la columna COMD (o COMMAND).
Las shells de usuario y los procesos se enumeran en la parte inferior de la salida de \texttt{ps -e} o \texttt{ps -ax}; aquí es donde debes buscar procesos fuera de control. Observa que muchos procesos en la lista tienen un ? en lugar de un terminal. Estos bien no deberían tener uno (como los \emph{daemons} básicos) o son procesos fuera de control. Por lo tanto, es probable que si \texttt{ps -a} no encuentra un proceso que estás intentando eliminar, \texttt{ps -e} (o \texttt{ps -ax}) lo mostrará con ? en la columna TTY (o TT). Puedes determinar qué proceso deseas observando la columna COMD (o COMMAND).
\subsection{kill: La historia completa}
El comando \emph{kill} tiene un nombre bastante equívoco. Debería haberse llamado \emph{sendsignal} o algo similar, ya que envía señales a los procesos. (De hecho, el nombre se deriva de la llamada al sistema \emph{kill(2)}, que el comando \emph{kill} utiliza para enviar señales, y que está igualmente mal nombrada).
@ -357,7 +357,7 @@ Como vimos anteriormente, \texttt{kill -l} te proporciona la lista completa de n
kill \emph{job}... & Envía la señal TERM a cada \emph{trabajo} nombrado. Este es el uso normal. \\\hline
kill -l & Enumera los nombres de todas las señales compatibles. \\\hline
kill -l \emph{signal}... & Si \emph{signal} es un número, imprime su nombre. Si es un nombre, imprime su número. Si \emph{signal} es un número mayor que 256, se trata como un estado de salida. El shell resta 256 e imprime la señal correspondiente. \\\hline
kill -s \emph{signal-name job}... & Envía la señal nombrada por signal-name a cada trabajo dado. \\\hline
kill -s \emph{signal-name job}... & Envía la señal nombrada por \emph{signal-name} a cada trabajo dado. \\\hline
kill -n \emph{signal-number job}... & Envía la señal numérica dada por \emph{signal-number} a cada trabajo dado. \\\hline
kill \emph{-signal job}... & Envía la señal especificada por \emph{signal} a cada \emph{trabajo} dado. \emph{signal} puede ser un número o un nombre de señal. Esta forma se considera obsoleta; se proporciona por compatibilidad con \emph{ksh88} y la orden externa \emph{kill(1)}. \\\hline
\end{tabular}
@ -414,7 +414,7 @@ trap 'print "¡Presionaste control-C!"' INT TERM
Ahora repite el proceso: ejecútalo en segundo plano y escribe \texttt{kill \%loop}. Como antes, verás el mensaje y el proceso seguirá ejecutándose. Escribe \texttt{kill -KILL \%loop} para detenerlo.
Observa que el mensaje no es realmente apropiado cuando usas kill. Cambiaremos el script para que imprima un mensaje mejor en el caso de \emph{kill}:
Observa que el mensaje no es realmente apropiado cuando usas \emph{kill}. Cambiaremos el script para que imprima un mensaje mejor en el caso de \emph{kill}:
\begin{lstlisting}[language=bash]
trap 'print "¡Presionaste control-C!"' INT
@ -427,7 +427,7 @@ done
Ahora pruébalo de ambas maneras: en primer plano con CTRL-C y en segundo plano con \emph{kill}. Verás mensajes diferentes.
\subsection{Trampasy funciones}
La relación entre las trampas y las funciones del shell es directa, pero tiene ciertos matices que vale la pena discutir. Lo más importante que debes entender es que las funciones del shell Korn (aquellas creadas con la palabra clave \texttt{function}; consulta el C\hyperref[sec:Chapter4]{apítulo 4}) tienen sus propias trampas locales; estas no son conocidas fuera de la función. Las funciones de estilo antiguo de POSIX (aquellas creadas con la sintaxis \texttt{nombre()}) comparten trampas con el script principal.
La relación entre las trampas y las funciones del shell es directa, pero tiene ciertos matices que vale la pena discutir. Lo más importante que debes entender es que las funciones del shell Korn (aquellas creadas con la palabra clave \texttt{function}; consulta el C\hyperref[sec:Chapter4]{Capítulo 4}) tienen sus propias trampas locales; estas no son conocidas fuera de la función. Las funciones de estilo antiguo de POSIX (aquellas creadas con la sintaxis \texttt{nombre()}) comparten trampas con el script principal.
Comencemos con las funciones de estilo \texttt{function}, donde las trampas son locales. En particular, el script circundante no las conoce. Considera este código:
@ -581,9 +581,9 @@ rm $msgfile
\end{lstlisting}
\subsection{Ignorando señales}
A veces, llega una señal que no deseas manejar. Si proporcionas la cadena nula (\texttt{""} o \texttt{''}) como argumento de comando para \emph{trap}, el shell efectivamente ignora esa señal. El ejemplo clásico de una señal que es posible que desees ignorar es HUP (hangup), la señal que reciben todos tus procesos en segundo plano cuando cierras sesión. (Si tu conexión realmente se cae, Unix envía la señal HUP al shell. El shell reenvía la señal a todos tus procesos en segundo plano o la envía por iniciativa propia si cierras sesión de forma normal).
A veces, llega una señal que no deseas manejar. Si proporcionas la cadena nula (\texttt{""} o \texttt{''}) como argumento de comando para \emph{trap}, el shell efectivamente ignora esa señal. El ejemplo clásico de una señal que es posible que desees ignorar es \emph{HUP} (hangup), la señal que reciben todos tus procesos en segundo plano cuando cierras sesión. (Si tu conexión realmente se cae, Unix envía la señal \emph{HUP} al shell. El shell reenvía la señal a todos tus procesos en segundo plano o la envía por iniciativa propia si cierras sesión de forma normal).
HUP tiene el comportamiento predeterminado habitual: mata al proceso que la recibe. Pero seguramente habrá momentos en los que no querrás que un trabajo en segundo plano finalice cuando cierras sesión. Por ejemplo, podrías iniciar una compilación larga o un trabajo de formato de texto; quieres cerrar sesión y volver más tarde cuando esperas que el trabajo esté terminado. En circunstancias normales, tu trabajo en segundo plano terminaría cuando cierras sesión. Pero si lo ejecutas en un entorno de shell donde la señal HUP se ignora, el trabajo se completa.
\emph{HUP} tiene el comportamiento predeterminado habitual: mata al proceso que la recibe. Pero seguramente habrá momentos en los que no querrás que un trabajo en segundo plano finalice cuando cierras sesión. Por ejemplo, podrías iniciar una compilación larga o un trabajo de formato de texto; quieres cerrar sesión y volver más tarde cuando esperas que el trabajo esté terminado. En circunstancias normales, tu trabajo en segundo plano terminaría cuando cierras sesión. Pero si lo ejecutas en un entorno de shell donde la señal \emph{HUP} se ignora, el trabajo se completa.
Para hacer esto, podrías escribir una función simple que se ve así:
@ -596,7 +596,7 @@ function ignorehup {
Escribimos esto como una función en lugar de un script por razones que se harán más claras cuando examinemos detenidamente los subprocesos al final de este capítulo.
En realidad, hay un comando Unix llamado \emph{nohup} que hace precisamente esto. La función `start` del último capítulo podría incluir \emph{nohup}:
En realidad, hay un comando Unix llamado \emph{nohup} que hace precisamente esto. La función \emph{start} del último capítulo podría incluir \emph{nohup}:
\begin{lstlisting}[language=bash]
function start {
@ -604,7 +604,7 @@ function start {
}
\end{lstlisting}
Esto evita que HUP termine tu comando y guarda su salida estándar y de error en un archivo. De hecho, lo siguiente es igualmente bueno:
Esto evita que \emph{HUP} termine tu comando y guarda su salida estándar y de error en un archivo. De hecho, lo siguiente es igualmente bueno:
\begin{lstlisting}[language=bash]
function start {
@ -636,16 +636,16 @@ En este punto, es posible que estés pensando que uno podría involucrarse seria
Sin embargo, es probable que nunca escribas un script de shell lo suficientemente complejo y que necesite ser lo suficientemente robusto como para justificar mucho manejo de señales. Puedes escribir un prototipo para un programa tan grande como el correo en código de shell, pero los prototipos, por definición, no necesitan ser a prueba de balas.
Por lo tanto, no deberías preocuparte por poner código de manejo de señales en cada script de shell de 20 líneas que escribas. Nuestro consejo es determinar si hay situaciones en las que una señal podría hacer que tu programa haga algo seriamente malo y agregar código para manejar esas contingencias. ¿Qué es <<seriamente malo>>? Bueno, con respecto a los ejemplos anteriores, diríamos que el caso en el que HUP hace que tu trabajo termine al cerrar la sesión es seriamente malo, mientras que la situación del archivo temporal en nuestro programa de correo no lo es.
Por lo tanto, no deberías preocuparte por poner código de manejo de señales en cada script de shell de 20 líneas que escribas. Nuestro consejo es determinar si hay situaciones en las que una señal podría hacer que tu programa haga algo seriamente malo y agregar código para manejar esas contingencias. ¿Qué es <<seriamente malo>>? Bueno, con respecto a los ejemplos anteriores, diríamos que el caso en el que \emph{HUP} hace que tu trabajo termine al cerrar la sesión es seriamente malo, mientras que la situación del archivo temporal en nuestro programa de correo no lo es.
El shell Korn tiene varias opciones nuevas para \emph{trap} (con respecto al mismo comando en la mayoría de las conchas Bourne) que lo hacen útil como ayuda para depurar scripts de shell. Las cubrimos en el \hyperref[sec:Chapter9]{Capítulo 9}.
El shell Korn tiene varias opciones nuevas para \emph{trap} (con respecto al mismo comando en la mayoría de los shell de Bourne) que lo hacen útil como ayuda para depurar scripts de shell. Las cubrimos en el \hyperref[sec:Chapter9]{Capítulo 9}.
\section{Corrutinas}
Hemos dedicado las últimas páginas a detalles casi microscópicos del comportamiento de los procesos. En lugar de continuar nuestra inmersión en las profundidades turbias, volveremos a una vista de más alto nivel de los procesos.
Anteriormente en este capítulo, cubrimos formas de controlar múltiples trabajos simultáneos dentro de una sesión interactiva de inicio de sesión; ahora consideramos el control de múltiples procesos dentro de programas de shell. Cuando dos (o más) procesos están programados explícitamente para ejecutarse simultáneamente y posiblemente comunicarse entre sí, los llamamos corotinas.
Anteriormente en este capítulo, cubrimos formas de controlar múltiples trabajos simultáneos dentro de una sesión interactiva de inicio de sesión; ahora consideramos el control de múltiples procesos dentro de programas de shell. Cuando dos (o más) procesos están programados explícitamente para ejecutarse simultáneamente y posiblemente comunicarse entre sí, los llamamos corrutinas.
Esto no es realmente nuevo: una \emph{tubería} es un ejemplo de corotinas. El constructo de una tubería del shell encapsula un conjunto bastante sofisticado de reglas sobre cómo interactúan los procesos entre sí. Si observamos más de cerca estas reglas, podremos entender mejor otras formas de manejar corotinas, la mayoría de las cuales resultan ser más simples que las tuberías.
Esto no es realmente nuevo: una \emph{tubería} es un ejemplo de corrutinas. El constructo de una tubería del shell encapsula un conjunto bastante sofisticado de reglas sobre cómo interactúan los procesos entre sí. Si observamos más de cerca estas reglas, podremos entender mejor otras formas de manejar corrutinas, la mayoría de las cuales resultan ser más simples que las tuberías.
Cuando invocas una tubería simple, por ejemplo, \texttt{ls | more}, el shell invoca una serie de operaciones primitivas de Unix, también conocidas como \emph{llamadas al sistema}. En efecto, el shell le indica a Unix que haga lo siguiente; en caso de que estés interesado, incluimos entre paréntesis la llamada al sistema real utilizada en cada paso:
@ -660,7 +660,7 @@ Cuando invocas una tubería simple, por ejemplo, \texttt{ls | more}, el shell in
Probablemente puedas imaginar cómo cambian los pasos anteriores cuando la tubería involucra más de dos procesos.
Ahora simplifiquemos las cosas. Veremos cómo hacer que varios procesos se ejecuten al mismo tiempo si los procesos no necesitan comunicarse. Por ejemplo, queremos que los procesos \emph{dave} y \emph{bob} se ejecuten como corotinas, sin comunicación, en un script de shell. Ambos deben ejecutarse por completo antes de que el script finalice. Nuestra solución inicial sería esta:
Ahora simplifiquemos las cosas. Veremos cómo hacer que varios procesos se ejecuten al mismo tiempo si los procesos no necesitan comunicarse. Por ejemplo, queremos que los procesos \emph{dave} y \emph{bob} se ejecuten como corrutinas, sin comunicación, en un script de shell. Ambos deben ejecutarse por completo antes de que el script finalice. Nuestra solución inicial sería esta:
\begin{lstlisting}[language=bash]
dave &
@ -682,10 +682,10 @@ Aquí, si \emph{bob} termina primero, el shell principal espera a que \emph{dave
Si tu script tiene más de un trabajo en segundo plano y necesitas esperar a que terminen trabajos específicos, puedes darle a \emph{wait} el mismo tipo de argumento de trabajo (con un signo de porcentaje) que usarías con \emph{kill, fg} o \emph{bg}.
Sin embargo, es probable que encuentres que \emph{wait} sin argumentos es suficiente para todas las corotinas que programarás. Las situaciones en las que necesitarías esperar trabajos en segundo plano específicos son bastante complejas y están fuera del alcance de este libro.
Sin embargo, es probable que encuentres que \emph{wait} sin argumentos es suficiente para todas las corrutinas que programarás. Las situaciones en las que necesitarías esperar trabajos en segundo plano específicos son bastante complejas y están fuera del alcance de este libro.
\subsection{Ventajas y desventajas de las corrutinas}
De hecho, puede que te preguntes por qué necesitarías programar corotinas que no se comunican entre sí. Por ejemplo, ¿por qué no simplemente ejecutar \emph{bob} después de \emph{dave} de la manera habitual? ¿Qué ventaja hay en ejecutar los dos trabajos simultáneamente?
De hecho, puede que te preguntes por qué necesitarías programar corrutinas que no se comunican entre sí. Por ejemplo, ¿por qué no simplemente ejecutar \emph{bob} después de \emph{dave} de la manera habitual? ¿Qué ventaja hay en ejecutar los dos trabajos simultáneamente?
Si estás ejecutando un equipo con un solo procesador (CPU), hay una ventaja de rendimiento, pero solo si tienes desactivada la opción \emph{bgnice} (ver \hyperref[sec:Chapter3]{Capítulo 3}), y aún así solo en ciertas situaciones.
@ -699,11 +699,11 @@ Por ejemplo, si ambos procesos consumen muchos recursos del disco, el sistema op
\subsection{Paralelización}
Pero si tienes una computadora con múltiples CPUs \footnote{Los sistemas multiprocesador solían encontrarse solo en servidores a gran escala ubicados en salas de máquinas especiales con control climático. Hoy en día, los sistemas multiprocesador de escritorio están disponibles y se están volviendo cada vez más comunes, aunque los sistemas con más de alrededor de 4 CPUs aún tienden a estar principalmente en salas de máquinas.},
deberías preocuparte menos por el thrashing. Además, las corotinas pueden proporcionar aumentos dramáticos de velocidad en este tipo de máquina, que a menudo se llama una computadora \emph{paralela}; de manera análoga, descomponer un proceso en corotinas a veces se denomina \emph{paralelizar} el trabajo.
deberías preocuparte menos por el thrashing. Además, las corrutinas pueden proporcionar aumentos dramáticos de velocidad en este tipo de máquina, que a menudo se llama una computadora \emph{paralela}; de manera análoga, descomponer un proceso en corrutinas a veces se denomina \emph{paralelizar} el trabajo.
Normalmente, cuando inicias un trabajo en segundo plano en una máquina con múltiples CPUs, la computadora lo asigna al siguiente procesador disponible. Esto significa que los dos trabajos están realmente, no solo metafóricamente, ejecutándose al mismo tiempo.
En este caso, el tiempo de ejecución de las corotinas es esencialmente igual al del trabajo de mayor duración más un poco de sobrecarga, en lugar de la suma de los tiempos de ejecución de todos los procesos (aunque si todas las CPUs comparten una unidad de disco común, aún existe la posibilidad de thrashing relacionado con la E/S). En el mejor caso, con todos los trabajos teniendo el mismo tiempo de ejecución y sin contención de E/S, obtienes un factor de aceleración igual al número de CPUs.
En este caso, el tiempo de ejecución de las corrutinas es esencialmente igual al del trabajo de mayor duración más un poco de sobrecarga, en lugar de la suma de los tiempos de ejecución de todos los procesos (aunque si todas las CPUs comparten una unidad de disco común, aún existe la posibilidad de thrashing relacionado con la E/S). En el mejor caso, con todos los trabajos teniendo el mismo tiempo de ejecución y sin contención de E/S, obtienes un factor de aceleración igual al número de CPUs.
Paralelizar un programa a menudo no es fácil; hay varios problemas sutiles involucrados y hay mucho margen para el error. Sin embargo, vale la pena saber cómo paralelizar un script de shell, ya sea que tengas o no una máquina paralela, especialmente porque estas máquinas son cada vez más comunes, incluso en el escritorio.
@ -781,10 +781,10 @@ Pero no toda la vida es tan simple; a veces, simplemente iniciar más trabajos e
Las cosas se complican aún más al trabajar a un nivel más bajo, con múltiples hilos de control dentro de un solo proceso (algo que afortunadamente no es visible a nivel de shell). Dichos problemas, conocidos como problemas de \emph{control de concurrencia}, se vuelven mucho más difíciles a medida que aumenta la complejidad de la aplicación. Los programas concurrentes complejos a menudo tienen mucho más código para manejar los casos especiales que para el trabajo real que se supone deben hacer.
Por lo tanto, no debería sorprenderte que se haya hecho y se esté haciendo mucha investigación sobre la paralelización, siendo el objetivo final idear una herramienta que paralelice el código automáticamente. (Tales herramientas existen; generalmente trabajan dentro de algún subconjunto estrecho del problema). Incluso si no tienes acceso a una máquina con múltiples CPUs, paralelizar un script de shell es un ejercicio interesante que debería familiarizarte con algunos de los problemas que rodean a las corotinas.
Por lo tanto, no debería sorprenderte que se haya hecho y se esté haciendo mucha investigación sobre la paralelización, siendo el objetivo final idear una herramienta que paralelice el código automáticamente. (Tales herramientas existen; generalmente trabajan dentro de algún subconjunto estrecho del problema). Incluso si no tienes acceso a una máquina con múltiples CPUs, paralelizar un script de shell es un ejercicio interesante que debería familiarizarte con algunos de los problemas que rodean a las corrutinas.
\subsection{Corrutinas con tuberías bidireccionales}
Ahora que hemos visto cómo programar corotinas que no se comunican entre sí, construiremos sobre esa base y discutiremos cómo hacer que se comuniquen, de una manera más sofisticada que con una canalización. El shell Korn tiene un conjunto de características que permiten a los programadores establecer una comunicación bidireccional entre corotinas. Estas características no están incluidas en la mayoría de los shells Bourne.
Ahora que hemos visto cómo programar corrutinas que no se comunican entre sí, construiremos sobre esa base y discutiremos cómo hacer que se comuniquen, de una manera más sofisticada que con una canalización. El shell Korn tiene un conjunto de características que permiten a los programadores establecer una comunicación bidireccional entre corrutinas. Estas características no están incluidas en la mayoría de los shells Bourne.
Si inicias un proceso en segundo plano agregando |\& a un comando en lugar de \&, el shell Korn configura una tubería bidireccional especial entre el shell principal y el nuevo proceso en segundo plano. \texttt{read -p} en el shell principal lee una línea de la salida estándar del proceso en segundo plano; de manera similar, \texttt{print -p} en el shell principal alimenta la entrada estándar del proceso en segundo plano. La Figura \ref{fig:8-2} muestra cómo funciona esto.
@ -795,7 +795,7 @@ Si inicias un proceso en segundo plano agregando |\& a un comando en lugar de \&
\label{fig:8-2}
\end{figure}
Este esquema tiene algunas posibilidades intrigantes. Observa lo siguiente: primero, el shell principal se comunica con el proceso en segundo plano de manera independiente de su propia entrada y salida estándar. En segundo lugar, el proceso en segundo plano no necesita tener idea de que un script de shell se está comunicando con él de esta manera. Esto significa que el proceso en segundo plano puede ser casi cualquier programa preexistente que use su entrada y salida estándar de manera normal.\footnote{Observa que \emph{sort(1)} no encaja del todo aquí. sort debe leer toda su entrada antes de poder generar cualquier salida. Todavía puedes usar sort en un coproceso, pero tendrías que cerrar el descriptor de archivo utilizado para escribir en el coproceso primero. La forma de hacer esto es mover el descriptor de archivo de entrada del coproceso a un descriptor de archivo numerado y luego cerrarlo. Ambas cosas involucran el comando \emph{exec}, que se trata en el próximo capítulo.}
Este esquema tiene algunas posibilidades intrigantes. Observa lo siguiente: primero, el shell principal se comunica con el proceso en segundo plano de manera independiente de su propia entrada y salida estándar. En segundo lugar, el proceso en segundo plano no necesita tener idea de que un script de shell se está comunicando con él de esta manera. Esto significa que el proceso en segundo plano puede ser casi cualquier programa preexistente que use su entrada y salida estándar de manera normal.\footnote{Observa que \emph{sort(1)} no encaja del todo aquí. \emph{sort} debe leer toda su entrada antes de poder generar cualquier salida. Todavía puedes usar \emph{sort} en un coproceso, pero tendrías que cerrar el descriptor de archivo utilizado para escribir en el coproceso primero. La forma de hacer esto es mover el descriptor de archivo de entrada del coproceso a un descriptor de archivo numerado y luego cerrarlo. Ambas cosas involucran el comando \emph{exec}, que se trata en el próximo capítulo.}
La \hyperref[box:8-4]{Tarea 8-4} es una tarea que muestra un ejemplo sencillo.
@ -817,7 +817,7 @@ while read line'?adc> '; do
done
\end{lstlisting}
La primera línea de este código inicia \emph{dc} como una corutina con una tubería bidireccional. Luego, el bucle \texttt{while} solicita al usuario una línea y la lee hasta que el usuario escribe CTRL-D para el final de la entrada. El cuerpo del bucle convierte la línea a RPN, la pasa a dc a través de la tubería, lee la respuesta de \emph{dc} e imprime después un signo igual. Por ejemplo:
La primera línea de este código inicia \emph{dc} como una corrutina con una tubería bidireccional. Luego, el bucle \texttt{while} solicita al usuario una línea y la lee hasta que el usuario escribe CTRL-D para el final de la entrada. El cuerpo del bucle convierte la línea a RPN, la pasa a \emph{dc} a través de la tubería, lee la respuesta de \emph{dc} e imprime después un signo igual. Por ejemplo:
\begin{lstlisting}[language=bash]
$ adc
@ -845,7 +845,7 @@ La única diferencia con lo anterior es la falta del signo igual antes de imprim
Todo esto sugiere que el esquema de tubería bidireccional es excelente para escribir scripts de shell que interponen una capa de software entre el usuario (o algún otro programa) y un programa existente que utiliza entrada y salida estándar. En particular, es excelente para escribir nuevas interfaces para programas Unix estándar antiguos que esperan entrada y salida de usuario basada en caracteres, línea por línea. Las nuevas interfaces podrían ser GUI o podrían ser programas de interfaz de red que se comuniquen con usuarios a través de enlaces a máquinas remotas. En otras palabras, ¡la construcción de tuberías bidireccionales del shell Korn está diseñada para ayudar a desarrollar software muy actualizado!
\subsection{Tuberías Bidireccionales versus Tuberías Estándar}
Antes de abandonar el tema de las corotinas, completaremos el círculo mostrando cómo se compara la construcción de tuberías bidireccionales con las canalizaciones regulares. Como probablemente hayas podido deducir hasta ahora, es posible programar una canalización estándar usando |\& con \texttt{print -p}.
Antes de abandonar el tema de las corrutinas, completaremos el círculo mostrando cómo se compara la construcción de tuberías bidireccionales con las canalizaciones regulares. Como probablemente hayas podido deducir hasta ahora, es posible programar una canalización estándar usando |\& con \texttt{print -p}.
Esto tiene la ventaja de reservar la salida estándar del shell principal para otro uso. La desventaja es que la salida estándar del proceso secundario se dirige a la tubería bidireccional: si el proceso principal no la lee con \texttt{read -p}, se pierde efectivamente.
@ -929,5 +929,5 @@ Este ha sido un capítulo largo y ha cubierto mucho terreno. Aquí tienes alguno
\item Necesitas escribir una rutina que convierta la notación algebraica en RPN. Esto debería ser (o incluir) una función que se llame a sí misma (conocida como una función \emph{recursiva}) cada vez que encuentra una subexpresión. Es especialmente importante que esta función lleve un registro de dónde está en la cadena de entrada y cuánto de la cadena consume durante su procesamiento. (Pista: utiliza los operadores de coincidencia de patrones discutidos en el \hyperref[sec:Chapter4]{Capítulo 4} para facilitar la tarea de analizar cadenas de entrada). \\
Para facilitarte la vida, no te preocupes por la precedencia de operadores por ahora; simplemente convierte a RPN de izquierda a derecha. Por ejemplo, trata $3+4x5$ como $(3+4)x5$ y $3x4+5$ como $(3x4)+5$. Esto hace posible que conviertas la cadena de entrada sobre la marcha, es decir, sin tener que leerla completa antes de hacer cualquier procesamiento.
\item Mejora tu solución al ejercicio anterior para que admita la precedencia de operadores en el orden usual: x, /, \% (resto) +, -. Por ejemplo, trata $3+4x5$ como $3+(4x5)$ y $3x4+5$ como $(3x4)+5$.
\end{enumerate}
\end{enumerate}
\end{enumerate}

View File

@ -3,14 +3,14 @@ Esperamos haber logrado convencerte de que el shell Korn puede utilizarse como u
Pero, ¿qué hay de las herramientas de soporte para el Korn shell? Por supuesto, puedes usar cualquier editor que desees, incluyendo \emph{vi} y \emph{Emacs}. Y debido a que el shell es un lenguaje interpretado, no necesitas un compilador.\footnote{De hecho, si realmente te preocupa la eficiencia, hay compiladores de código de shell en el mercado; algunos convierten scripts de shell a código C que a menudo se ejecuta bastante más rápido; sin embargo, estas herramientas suelen ser para scripts de Bourne shell. Otros <<compiladores>> simplemente convierten el script a una forma binaria para que los clientes no puedan leer el programa.}
Pero no hay otras herramientas disponibles. El problema más serio es la falta de un depurador.
Este capítulo aborda esa carencia. El shell tiene algunas características que ayudan en la depuración de scripts de shell; veremos estas en la primera parte del capítulo. El shell Korn también tiene un par de características nuevas, no presentes en la mayoría de los shells Bourne, que hacen posible implementar una herramienta de depuración completa. Mostramos estas características; más importante aún, presentamos \emph{kshdb}, un depurador de Korn shell que las utiliza. \emph{kshdb} es básico pero bastante utilizable, y su implementación sirve como un ejemplo extendido de varias técnicas de programación de shell de todo este libro.
Este capítulo aborda esa carencia. El shell tiene algunas características que ayudan en la depuración de scripts de shell; veremos estas en la primera parte del capítulo. El shell Korn también tiene un par de características nuevas, no presentes en la mayoría de los shells de Bourne, que hacen posible implementar una herramienta de depuración completa. Mostramos estas características; más importante aún, presentamos \emph{kshdb}, un depurador de Korn shell que las utiliza. \emph{kshdb} es básico pero bastante utilizable, y su implementación sirve como un ejemplo extendido de varias técnicas de programación de shell de todo este libro.
\section{Ayudas básicas para depuración}
¿Qué tipo de funcionalidad necesitas para depurar un programa? En el nivel más empírico, necesitas una forma de determinar \emph{qué} está causando que tu programa se comporte mal y dónde está el problema en el código. Por lo general, comienzas con un \emph{qué} obvio (como un mensaje de error, una salida inapropiada, un bucle infinito, etc.), intentas retroceder hasta encontrar un "qué" que esté más cerca del problema real (por ejemplo, una variable con un valor incorrecto, una opción incorrecta para un comando) y eventualmente llegas al "dónde" exacto en tu programa. Luego puedes preocuparte por \emph{cómo} solucionarlo.
Observa que estos pasos representan un proceso de empezar con información obvia y terminar con hechos a menudo oscuros deducidos e intuidos. Las ayudas para la depuración facilitan la deducción e intuición al proporcionar información relevante fácilmente o incluso automáticamente, preferiblemente sin modificar tu código.
La ayuda más simple para la depuración (para cualquier lenguaje) es la instrucción de salida, como print en el caso del shell. De hecho, los programadores de la vieja escuela depuraban su código Fortran insertando tarjetas WRITE en sus mazos. Puedes depurar colocando muchas declaraciones de salida en tu código (y eliminándolas más tarde), pero tendrás que dedicar mucho tiempo a reducir no solo la información exacta que deseas sino también dónde necesitas verla. También probablemente tendrás que sumergirte en mucha salida para encontrar la información que realmente deseas.
La ayuda más simple para la depuración (para cualquier lenguaje) es la instrucción de salida, como \emph{print} en el caso del shell. De hecho, los programadores de la vieja escuela depuraban su código Fortran insertando tarjetas WRITE en sus mazos. Puedes depurar colocando muchas declaraciones de salida en tu código (y eliminándolas más tarde), pero tendrás que dedicar mucho tiempo a reducir no solo la información exacta que deseas sino también dónde necesitas verla. También probablemente tendrás que sumergirte en mucha salida para encontrar la información que realmente deseas.
\subsection{Establecer opciones}
Afortunadamente, el shell tiene algunas características básicas que te brindan funcionalidad de depuración más allá de la de \emph{print}. Las más básicas son las opciones del comando \texttt{set -o} (como se cubrió en el \hyperref[sec:Chapter3]{Capítulo 3}). Estas opciones también se pueden usar en la línea de comandos al ejecutar un script, como muestra la Tabla \ref{Tab:9-1}.
@ -71,7 +71,7 @@ $
\end{lstlisting}
Como puedes ver, \emph{xtrace} inicia cada línea que imprime con +. Esto es realmente personalizable: es el valor de la variable de shell integrada PS4.\footnote{Como con PS1 y PS3, esta variable también se somete a la sustitución de parámetros, comandos y aritmética antes de que se imprima su valor.}
Si estableces PS4 en \texttt{xtrace-> } (por ejemplo, en tu \emph{.profile} o archivo de entorno), obtendrás listados de xtrace que se ven así:
Si estableces PS4 en \texttt{xtrace-> } (por ejemplo, en tu \emph{.profile} o archivo de entorno), obtendrás listados de \emph{xtrace} que se ven así:
\begin{lstlisting}[language=bash]
$ ls -l $(whence emacs)
@ -81,7 +81,7 @@ xtrace-> ls -l /usr/bin/emacs
$
\end{lstlisting}
Una forma aún mejor de personalizar PS4 es usar una variable integrada que aún no hayamos visto: \texttt{LINENO}, que contiene el número de la línea que se está ejecutando actualmente en un script de shell. Coloca esta línea en tu .profile o archivo de entorno:
Una forma aún mejor de personalizar PS4 es usar una variable integrada que aún no hayamos visto: \texttt{LINENO}, que contiene el número de la línea que se está ejecutando actualmente en un script de shell. Coloca esta línea en tu \emph{.profile} o archivo de entorno:
\begin{lstlisting}[language=bash]
PS4='line $LINENO: '
@ -110,14 +110,14 @@ texttt{ksh -x fred bob}, y ves esto:
+ + cut -f3 -d
\end{lstlisting}
Se cuelga nuevamente en este punto. Notas que cut no tiene un argumento de nombre de archivo, lo que significa que debe haber algo mal con la variable \emph{dbfmq}. Pero ha ejecutado correctamente la instrucción de asignación \texttt{dbfmq=bob.fmq}... ¡ah, ja! Cometiste un error tipográfico en el nombre de la variable dentro de la construcción de sustitución de comandos.\footnote{Deberíamos admitir que si hubieras activado la opción \emph{nounset} en la parte superior de este script, el shell habría señalado este error.}
Se cuelga nuevamente en este punto. Notas que \emph{cut} no tiene un argumento de nombre de archivo, lo que significa que debe haber algo mal con la variable \emph{dbfmq}. Pero ha ejecutado correctamente la instrucción de asignación \texttt{dbfmq=bob.fmq}... ¡ah, ja! Cometiste un error tipográfico en el nombre de la variable dentro de la construcción de sustitución de comandos.\footnote{Deberíamos admitir que si hubieras activado la opción \emph{nounset} en la parte superior de este script, el shell habría señalado este error.}
Lo corriges y el script funciona correctamente.
Cuando se establece a nivel global, la opción \emph{xtrace} se aplica al script principal y a cualquier función de estilo POSIX (aquellas creadas con la sintaxis de \texttt{nombre ()}). Si el código que estás tratando de depurar llama a funciones de estilo \texttt{function} que están definidas en otro lugar (por ejemplo, en tu \emph{.profile} o archivo de entorno), puedes rastrear estas de la misma manera con una opción al comando \emph{typeset}. Simplemente escribe el comando \texttt{typeset -ft nombrefuncion} y la función con el nombre dado se rastreará cada vez que se ejecute. Escribe \texttt{typeset +ft nombrefuncion} para apagar el rastreo. También puedes poner \texttt{set -o xtrace} en el cuerpo de la función, lo cual es bueno cuando la función está dentro del script que se está depurando.
La última opción es \emph{noexec}, que lee el script de shell y verifica errores de sintaxis pero no ejecuta nada. Vale la pena usarla si tu script es sintácticamente complejo (muchos bucles, bloques de código, operadores de cadenas, etc.) y el error tiene efectos secundarios (como crear un archivo grande o colgar el sistema).
Puedes activar estas opciones con \texttt{set -o} en tus scripts de shell, y, como se explica en el \hyperref[sec:Chapter3]{Capítulo 3}, desactivarlas con \texttt{set +o opcion}. Por ejemplo, si estás depurando un script con un efecto secundario desagradable, y lo has localizado en un cierto fragmento de código, puedes preceder ese fragmento con \texttt{set -o xtrace} (y, tal vez, cerrarlo con \texttt{set +o xtrace}) para observarlo con más detalle.
Puedes activar estas opciones con \texttt{set -o} en tus scripts de shell, y, como se explica en el \hyperref[sec:Chapter3]{Capítulo 3}, desactivarlas con \texttt{set +o opción}. Por ejemplo, si estás depurando un script con un efecto secundario desagradable, y lo has localizado en un cierto fragmento de código, puedes preceder ese fragmento con \texttt{set -o xtrace} (y, tal vez, cerrarlo con \texttt{set +o xtrace}) para observarlo con más detalle.
\textbf{NOTA:} La opción \emph{noexec} es una opción <<unidireccional>>. ¡Una vez activada, no puedes desactivarla! Esto se debe a que el shell solo imprime comandos y no los ejecuta. Esto incluye el comando \texttt{set +o noexec} que querrías usar para desactivar la opción. Afortunadamente, esto solo se aplica a scripts de shell; el shell ignora esta opción cuando es interactivo.
@ -245,7 +245,7 @@ trap 'errtrap $LINENO' ERR
Si usas esto con el ejemplo anterior, el resultado es el mensaje \texttt{ERROR línea 12: El comando salió con estado 17}. Esto es mucho más útil. Veremos una variación de esta técnica en breve.
Este código simple no es realmente un mal mecanismo de depuración universal. Toma en cuenta que un estado de salida distinto de cero no necesariamente indica una condición o evento indeseable: recuerda que cada construcción de control con una condición (\texttt{if, while}, etc.) usa un estado de salida distinto de cero para significar <<falso>>. En consecuencia, el shell no genera trampas ERR cuando las declaraciones o expresiones en las partes <<condición>> de las estructuras de control producen estados de salida distintos de cero.
Este código simple no es realmente un mal mecanismo de depuración universal. Toma en cuenta que un estado de salida distinto de cero no necesariamente indica una condición o evento indeseable: recuerda que cada construcción de control con una condición (\texttt{if, while}, etc.) usa un estado de salida distinto de cero para significar <<falso>>. En consecuencia, el shell no genera trampas \emph{ERR} cuando las declaraciones o expresiones en las partes <<condición>> de las estructuras de control producen estados de salida distintos de cero.
Pero una desventaja es que los estados de salida no son tan uniformes (o incluso tan significativos) como deberían ser, como explicamos en el \hyperref[sec:Chapter5]{Capítulo 5}. Un estado de salida específico no tiene por qué decir nada sobre la naturaleza del error o incluso que hubo un error.
@ -357,7 +357,7 @@ Los depuradores disponibles comercialmente ofrecen mucha más funcionalidad que
\item Especificar puntos en los que el programa detiene la ejecución y entra en el depurador. Estos se llaman puntos de interrupción \emph{breakpoints}.
\item Ejecutar solo una parte del programa a la vez, generalmente medida en declaraciones de código fuente. Esta capacidad se llama a menudo paso a paso \emph{stepping}.
\item Examinar y posiblemente cambiar el estado del programa (por ejemplo, valores de variables) en medio de una ejecución, es decir, cuando se detiene en un punto de interrupción o después de un paso a paso.
\item Especificar variables cuyos valores deben imprimirse cuando se cambian o acceden. Estas se llaman a menudo puntos de observación {watchpoints}.
\item Especificar variables cuyos valores deben imprimirse cuando se cambian o acceden. Estas se llaman a menudo puntos de observación (\emph{watchpoints}).
\item Hacer todo lo anterior sin tener que cambiar el código fuente.
\end{itemize}
@ -394,7 +394,7 @@ exec ksh $_dbgfile $_guineapig $_tmpdir $_libdir "$@"
Si el argumento es inválido (el archivo no es legible), \emph{kshdb} sale con un estado de error. De lo contrario, después de un mensaje introductorio, construye un nombre de archivo temporal como vimos en el \hyperref[sec:Chapter8]{Capítulo 8}. Si no tienes (o no tienes acceso a) \texttt{/tmp} en tu sistema, puedes sustituir un directorio diferente por \texttt{\_tmpdir}. \footnote{Todos los nombres de funciones y variables (excepto los locales de las funciones) en \emph{kshdb} comienzan con un guion bajo (\_), para minimizar la posibilidad de conflictos con los nombres en programa de pruebas. Una solución más orientada a \emph{ksh93} sería usar una variable compuesta, por ejemplo, \texttt{\_db.tmpdir}, \texttt{\_db.libdir}, y así sucesivamente.}
Además, asegúrate de que \texttt{\_libdir} esté configurado con el directorio donde residen los archivos \emph{kshdb.pre} y \emph{kshdb.fns} (que veremos pronto). \texttt{/usr/share/lib} es una buena opción si tienes acceso a él.
La instrucción \emph{cat} construye el archivo temporal: consiste en un archivo que veremos pronto llamado \emph{kshdb.pre}, que contiene el código real del depurador, seguido inmediatamente por una copia del programa en cuestion. Por lo tanto, el archivo temporal contiene un script de shell que se ha convertido en un depurador para sí mismo.
La instrucción \emph{cat} construye el archivo temporal: consiste en un archivo que veremos pronto llamado \emph{kshdb.pre}, que contiene el código real del depurador, seguido inmediatamente por una copia del programa en cuestión. Por lo tanto, el archivo temporal contiene un script de shell que se ha convertido en un depurador para sí mismo.
\subsubsection{exec}
La última línea ejecuta este script con \emph{exec}, una instrucción que aún no hemos visto. Hemos elegido esperar hasta ahora para presentarla porque, como creemos que estarás de acuerdo, puede ser peligrosa. \emph{exec} toma sus argumentos como una línea de comandos y ejecuta el comando en lugar del programa actual, en el mismo proceso. En otras palabras, el shell que ejecuta el script anterior \emph{terminará inmediatamente} y será reemplazado por los argumentos de \emph{exec}. Las situaciones en las que querrías usar \emph{exec} son pocas, raras y bastante arcanas, aunque esta es una de ellas.
@ -604,7 +604,7 @@ function _setbp {
\emph{\_setbp} establece los puntos de interrupción almacenándolos en las variables \texttt{\_linebp} (puntos de interrupción de número de línea) y \texttt{\_stringbp} (puntos de interrupción de cadena). Ambos tienen puntos de interrupción separados por caracteres de tubería, por razones que se harán claras en breve. Esto implica que los puntos de interrupción son acumulativos; establecer nuevos puntos de interrupción no borra los antiguos.
La única forma de eliminar los puntos de interrupción es con el comando \#cb, que (en la función \emph{\_clearbp}) los borra todos de una vez simplemente restableciendo las dos variables a nulo. Si no recuerdas qué puntos de interrupción has establecido, el comando \#bp sin argumentos los enumera.
La única forma de eliminar los puntos de interrupción es con el comando \emph{\#cb}, que (en la función \emph{\_clearbp}) los borra todos de una vez simplemente restableciendo las dos variables a nulo. Si no recuerdas qué puntos de interrupción has establecido, el comando \#bp sin argumentos los enumera.
Las funciones \emph{\_at\_linenumbp} y \emph{\_at\_stringbp} son llamadas por \emph{\_steptrap} después de cada declaración; verifican si el shell ha llegado a un punto de interrupción de número de línea o de cadena, respectivamente.

View File

@ -14,14 +14,14 @@ Para saber qué versión tienes, escribe el comando \emph{set -o emacs}, y luego
\subsection*{Resumen de las características del Shell de Korn}
El shell de Korn es el más avanzado de los shells que se distribuyen <<oficialmente>> con los sistemas Unix. Se trata de un sucesor evolutivo del shell Bourne, compatible con las versiones anteriores, que incluye la mayoría de las principales ventajas del shell C, así como una serie de nuevas características propias.
El shell de Korn es el más avanzado de los shells que se distribuyen <<oficialmente>> con los sistemas Unix. Se trata de un sucesor evolutivo del shell de Bourne, compatible con las versiones anteriores, que incluye la mayoría de las principales ventajas del shell C, así como una serie de nuevas características propias.
Entre las características apropiadas del intérprete de comandos C se incluyen:
\begin{description}
\item[Control de trabajo:] La capacidad de detener trabajos con CTRL-Z y moverlos al primer plano o al fondo con los comandos \emph{fg} y \emph{bg}.
\item[Alias:] La capacidad de definir nombres abreviados para comandos o líneas de comando.
\item[Funciones:] La capacidad de almacenar su propio código de shell en la memoria en lugar de archivos. Las funciones aumentan la programabilidad y la eficiencia. (Las funciones han sido comunes en el shell Bourne durante muchos años).
\item[Funciones:] La capacidad de almacenar su propio código de shell en la memoria en lugar de archivos. Las funciones aumentan la programabilidad y la eficiencia. (Las funciones han sido comunes en el shell de Bourne durante muchos años).
\item[Historial de comandos:] La capacidad de recordar comandos introducidos previamente. \\
\end{description}
@ -86,7 +86,7 @@ Si desea investigar temas específicos en lugar de leer todo el libro, aquí hay
\item \hyperref[sec:Chapter1]{Capítulo 1} \\
Presenta el shell de Korn y le indica cómo instalarlo como su shell de inicio de sesión. Luego presenta los conceptos básicos del uso de shell interactivo, incluidas las descripciones generales del esquema de archivos y directorios de Unix, E/S estándar y trabajos en segundo plano.
\item \hyperref[sec:Chapter2]{Capítulo 2} \\
Describe el mecanismo de historial de comandos del shell, incluidos los modos de edición de emacs y vi y el comando \emph{hist} history.
Describe el mecanismo de historial de comandos del shell, incluidos los modos de edición de \emph{emacs} y \emph{vi} y el comando \emph{hist} history.
\item \hyperref[sec:Chapter3]{Capítulo 3} \\
Cubre formas de personalizar su entorno de shell sin programación, mediante el uso de los archivos \emph{.profile} y de entorno. Los alias, las opciones y las variables de shell son las técnicas de personalización discutidas.
\item \hyperref[sec:Chapter4]{Capítulo 4} \\
@ -124,7 +124,7 @@ Este libro utiliza las siguientes convenciones tipográficas:
\begin{itemize}
\item \emph{Cursiva} \\
Se utiliza cuando se habla de nombres de archivos Unix, comandos externos e incorporados, nombres de alias, opciones de comandos, opciones del shell y funciones del shell. La cursiva también se utiliza en el texto cuando se discuten parámetros ficticios que deben ser reemplazados por un valor real, para distinguir los programas vi y emacs de sus modos Korn-shell, y para resaltar términos especiales la primera vez que se definen.
Se utiliza cuando se habla de nombres de archivos Unix, comandos externos e incorporados, nombres de alias, opciones de comandos, opciones del shell y funciones del shell. La cursiva también se utiliza en el texto cuando se discuten parámetros ficticios que deben ser reemplazados por un valor real, para distinguir los programas \emph{vi} y \emph{emacs} de sus modos Korn-shell, y para resaltar términos especiales la primera vez que se definen.
\item \texttt{Anchura constante} \\
Se utiliza para los nombres de las variables y las palabras clave del shell, los sufijos de los nombres de archivo y en los ejemplos para mostrar el contenido de los archivos o la salida de los comandos, así como para las líneas de comando cuando están dentro de un texto normal.
\item \textbf{\texttt{Negrita de ancho constante}} \\
@ -163,7 +163,7 @@ La primera edición de este libro cubría la versión de 1988 del shell de Korn.
Aunque \emph{ksh93} ha tardado en difundirse en el mundo comercial de Unix, el código fuente está ahora disponible, por lo que cualquiera que quiera una copia de la última y mejor versión de \emph{ksh93} no tiene más que descargar el código fuente y compilarlo. Teniendo esto en cuenta, hemos hecho de \emph{ksh93} el centro de la segunda edición, con un resumen de las diferencias disponible en un apéndice. Esta edición cubre la versión más reciente de \emph{ksh93} disponible en el momento de escribir este artículo, que incluye algunas características significativas que no se encuentran en las versiones anteriores.
La estructura básica y el flujo del libro siguen siendo los mismos, aunque hemos corregido varios errores y erratas de la primera edición y hemos actualizado kshdb, el depurador de Korn Shell, para que funcione con \emph{ksh93}. El \hyperref[sec:ApendiceA]{Apéndice A} incluye ahora más información sobre los programas similares al shell de Korn, tanto para sistemas Unix como Windows.
La estructura básica y el flujo del libro siguen siendo los mismos, aunque hemos corregido varios errores y erratas de la primera edición y hemos actualizado \emph{kshdb}, el depurador de Korn Shell, para que funcione con \emph{ksh93}. El \hyperref[sec:ApendiceA]{Apéndice A} incluye ahora más información sobre los programas similares al shell de Korn, tanto para sistemas Unix como Windows.
También se incluye en esta edición una tarjeta de referencia que cubre muchas de las características de \emph{ksh93} descritas en este libro. Esta tarjeta tiene el copyright de Specialized Systems Consultants, Inc. (SSC), y se reimprime con permiso. SSC vende una versión de la tarjeta en cuatro colores, 26 paneles, de 3,5 por 8,5 pulgadas, que cubre tanto \emph{ksh88} como \emph{ksh93} con mucho más detalle. Para más información, consulte \url{http://www.ssc.com}.
@ -198,11 +198,11 @@ Para obtener más información sobre nuestros libros, conferencias, centros de r
\subsection*{Agradecimientos}
Escribir un libro desde cero no es fácil. Actualizar un libro es aún más difícil; el truco consiste en hacer imposible (o al menos difícil) que el lector sepa qué autor escribió cada parte. Espero haberlo conseguido. Quiero dar las gracias a Bill Rosenblatt por haber escrito la primera edición y haberme proporcionado un excelente material con el que trabajar. Es uno de los mejores libros de O'Reilly que he leído, y ha sido un placer trabajar con él.
Me gustaría dar las gracias (en orden alfabético) a Nelson A. Beebe (Departamento de Matemáticas de la Universidad de Utah), al Dr. David G. Korn (AT\&T Research), a Chet Ramey (mantenedor de bash), a Bill Rosenblatt (GiantSteps/Media Technology Strategies) y al Dr. Eugene H. Spafford (Departamento de Ciencias de la Computación de la Universidad de Purdue) por haber revisado el libro y haber aportado muchos comentarios útiles. Mike Loukides, el editor del libro, fue muy paciente conmigo durante varios retrasos en la actualización. David Chu, del equipo editorial de O'Reilly, hizo un gran trabajo asegurándose de que muchas de las partes <<tuercas y tornillos>> del proyecto se hicieran, por lo que estoy agradecido.
Me gustaría dar las gracias (en orden alfabético) a Nelson A. Beebe (Departamento de Matemáticas de la Universidad de Utah), al Dr. David G. Korn (AT\&T Research), a Chet Ramey (mantenedor de \emph{bash}), a Bill Rosenblatt (GiantSteps/Media Technology Strategies) y al Dr. Eugene H. Spafford (Departamento de Ciencias de la Computación de la Universidad de Purdue) por haber revisado el libro y haber aportado muchos comentarios útiles. Mike Loukides, el editor del libro, fue muy paciente conmigo durante varios retrasos en la actualización. David Chu, del equipo editorial de O'Reilly, hizo un gran trabajo asegurándose de que muchas de las partes <<tuercas y tornillos>> del proyecto se hicieran, por lo que estoy agradecido.
David Korn, ahora de AT\&T Research Laboratories, y autor del shell de Korn, respondió a varias preguntas y proporcionó acceso temprano a la documentación de ksh93l, lo que ayudó considerablemente, así como acceso previo a la liberación de ksh93n. Glenn Fowler, también de AT\&T Research, me ayudó con problemas de compilación bajo GNU/Linux, así como a entender algunos de los puntos más finos del uso de ksh. Steve Alston aportó algunas mejoras al depurador kshdb en el \hyperref[sec:Chapter9]{Capítulo 9}. George Kraft IV proporcionó información útil sobre dtksh para el \hyperref[sec:ApendiceA]{Apéndice A}. Glenn Barry, de Sun Microsystems, proporcionó información sobre zsh para el \hyperref[sec:ApendiceA]{Apéndice A}.
David Korn, ahora de AT\&T Research Laboratories, y autor del shell de Korn, respondió a varias preguntas y proporcionó acceso temprano a la documentación de \emph{ksh93l}, lo que ayudó considerablemente, así como acceso previo a la liberación de \emph{ksh93n}. Glenn Fowler, también de AT\&T Research, me ayudó con problemas de compilación bajo GNU/Linux, así como a entender algunos de los puntos más finos del uso de \emph{ksh}. Steve Alston aportó algunas mejoras al depurador \emph{kshdb} en el \hyperref[sec:Chapter9]{Capítulo 9}. George Kraft IV proporcionó información útil sobre \emph{dtksh} para el \hyperref[sec:ApendiceA]{Apéndice A}. Glenn Barry, de Sun Microsystems, proporcionó información sobre zsh para el \hyperref[sec:ApendiceA]{Apéndice A}.
Gracias a Phil Hughes, presidente de SSC, por el permiso para reimprimir partes de su tarjeta de referencia de ksh.
Gracias a Phil Hughes, presidente de SSC, por el permiso para reimprimir partes de su tarjeta de referencia de \emph{ksh}.
Otros miembros del personal de O'Reilly también han contribuido al libro: Leanne Soylemez fue la editora de producción y correctora; Mary Brady y Jane Ellin proporcionaron un control de calidad adicional; Brenda Miller escribió el índice.