Aprendiendo_Korn_Shell/Secciones/Capitulo2.tex

934 lines
84 KiB
TeX

Siempre es posible cometer errores cuando se escribe en el teclado de un ordenador, pero quizás aún más cuando se utiliza una shell Unix. La sintaxis del shell Unix es potente, pero concisa, llena de caracteres extraños y no especialmente mnemotécnica, lo que permite construir líneas de órdenes tan crípticas como complejas. Los shells Bourne y C agravan esta situación al ofrecerte formas extremadamente limitadas de editar tus líneas de órdenes.
En particular, no hay forma de recuperar una línea de órdenes anterior para poder corregir un error. Por ejemplo, en el \hyperref[sec:Chapter7]{Capítulo 7} veremos líneas de comando complejas como:
\begin{lstlisting}[language=bash]
eval cat \$srcname \| ccom \| optimize \| as \> \$objname
\end{lstlisting}
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 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 \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 \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 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]
VISUAL=$(whence emacs)
\end{lstlisting}
o
\begin{lstlisting}[language=bash]
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{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}:
\begin{lstlisting}[language=bash]
set -o emacs
\end{lstlisting}
o
\begin{lstlisting}[language=bash]
set -o vi
\end{lstlisting}
Los usuarios de vi pueden desear añadir:
\begin{lstlisting}[language=bash]
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 \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 \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:
\begin{itemize}
\item \emph{ksh} indica que una línea es más ancha que su pantalla marcando la última columna de la línea visible con un carácter especial: < indica que hay más texto a la izquierda de lo que se ve actualmente, > indica que hay más texto a la derecha de lo que se ve, y * indica que hay texto a ambos lados de lo que se ve actualmente.
\begin{lstlisting}[language=bash]
print this is a very long line that just runs on and >
\end{lstlisting}
\item La personalización de los modos de edición de \emph{ksh93} es posible pero requiere el conocimiento de características avanzadas que aún no hemos cubierto. Consulte el \hyperref[sec:Chapter10]{Capítulo 10} para más detalles.\footnote{El shell de dominio público Korn, \emph{bash} y \emph{zsh} tienen modos de edición personalizables, pero de forma diferente a \emph{ksh93}. Véase el \hyperref[sec:ApendiceA]{Apéndice A.}}
\end{itemize}
\section{El Archivo 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}:
\begin{lstlisting}[language=bash]
HISTFILE=~/.hist.$(tty | sed 's;.*/;;')
\end{lstlisting}
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 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 \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}.
\begin{table}[h]
\center
\caption{Comandos básicos del modo emacs}
\label{tab2.1}
\begin{tabular}{m{2cm}|m{10cm}} \hline
\textbf{Comando} & \textbf{Descripción} \\ \hline
CTRL-B & Retroceder un carácter (sin borrar) \\
CTRL-F & Avanzar un carácter \\
DEL & Borrar un carácter hacia atrás \\
CTRL-D & Borrar un carácter hacia delante \\
CTRL-Y & Recuperar (<<yank>>) el último elemento borrado \\
\end{tabular}
\end{table}
\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 \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 \emph{emacs} no usa las teclas de dirección,\footnote{De hecho, como se describe en el \hyperref[sec:ApendiceB]{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 \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:
\begin{lstlisting}[language=bash, escapeinside={(*}{*)}]]
$ (*\highlight{f}*)grep -l Bob < ~pete/wk/names
\end{lstlisting}
Ahora el cursor está en la f, y el punto está al principio de la línea, justo antes de la f. Si tecleas DEL, no ocurrirá nada porque no hay caracteres a la izquierda del punto. Sin embargo, si pulsas CTRL-D (el comando <<borrar carácter hacia delante>>) borrarás la primera letra:
\begin{lstlisting}[language=bash, escapeinside={(*}{*)}]]
$ (*\highlight{g}*)rep -l Bob < ~pete/wk/names
\end{lstlisting}
El punto todavía está al principio de la línea. Si este fuera el comando deseado, podría pulsar ENTER ahora y ejecutarlo; no necesita mover el cursor de vuelta al final de la línea. Sin embargo, si quisiera, podría teclear CTRL-F repetidamente para llegar allí:
\begin{lstlisting}[language=bash]
$ grep -l Bob < ~pete/wk/names
\end{lstlisting}
En este punto, teclear CTRL-D no haría nada, pero pulsar DEL borraría la s final. Si tecleas DEL y decides que quieres recuperar la s, pulsa CTRL-Y para recuperarla. Si piensas que este ejemplo es una tontería, tienes razón en este caso concreto, pero ten en cuenta que CTRL-Y deshace el último comando de borrado de cualquier tipo, incluidos los comandos borrar-palabra y borrar-línea que veremos en breve \footnote{Los usuarios de Emacs deben tener en cuenta que este uso de CTRL-Y es diferente del editor completo, que no guarda los borrados de caracteres.}.
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 \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.
\begin{table}[h]
\center
\caption{Comandos de palabra en modo Emacs}
\label{tab2.2}
\begin{tabular}{m{6cm}|m{7cm}} \hline
\textbf{Opción} & \textbf{Significado} \\ \hline
ESC b & Retroceder una palabra \\
ESC f & Mover una palabra hacia adelante \\
ESC DEL, ESC h, ESC CTRL-H & Borrar una palabra hacia atrás \\
ESC d & Borrar una palabra hacia adelante \\
\end{tabular}
\end{table}
Volviendo a nuestro ejemplo: si tecleamos ESC b, point retrocede una palabra. Como / no es un carácter alfanumérico, emacs-mode se detiene ahí:
\begin{lstlisting}[language=bash, escapeinside={(*}{*)}]]
$ grep -l Bob < ~pete/wk/(*\highlight{n}*)ames
\end{lstlisting}
El cursor está sobre la \texttt{n} en \emph{names}, y el punto está entre la / y la \texttt{n}. Ahora digamos que queremos cambiar el argumento de la opción \emph{-l} de este comando de \emph{Bob} a \emph{Dave}. Necesitamos retroceder en la línea de comandos, así que tecleamos ESC b dos veces más. Esto nos lleva aquí:
\begin{lstlisting}[language=bash, escapeinside={(*}{*)}]]
$ grep -l Bob < ~(*\highlight{p}*)ete/wk/names
\end{lstlisting}
Si tecleamos ESC b de nuevo, acabaremos al principio de Bob:
\begin{lstlisting}[language=bash, escapeinside={(*}{*)}]]
$ grep -l (*\highlight{B}*)ob < ~pete/wk/names
\end{lstlisting}
¿Por qué? Recuerde que una palabra se define como una secuencia de caracteres alfanuméricos solamente; por lo tanto < no es una palabra, y la siguiente palabra en la dirección hacia atrás es Bob. Ahora estamos en la posición correcta para borrar Bob, así que tecleamos ESC d y obtenemos:
\begin{lstlisting}[language=bash]
$ grep -l < ~pete/wk/names
\end{lstlisting}
Ahora podemos escribir el argumento deseado:
\begin{lstlisting}[language=bash]
$ grep -l Dave< ~pete/wk/names
\end{lstlisting}
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 \emph{emacs}. Unos pocos comandos se ocupan de toda la línea; se muestran en la Tabla \ref{tab2.3}.
\begin{table}[h]
\center
\caption{Comandos de línea en modo Emacs}
\label{tab2.3}
\begin{tabular}{m{2cm}|m{10cm}} \hline
\textbf{Comando} & \textbf{Descripción} \\ \hline
CTRL-A & Mover al principio de la línea \\
CTRL-E & Mover al final de la línea \\
CTRL-K & Suprimir (<<kill>>) hacia delante hasta el final de línea \\
CTRL-C & Poner en mayúscula el carácter después del punto \\
\end{tabular}
\end{table}
CTRL-C es a menudo la tecla de <<interrupción>> que Unix proporciona a través de su interfaz con tu terminal. Si este es el caso, CTRL-C en modo emacs borrará toda la línea, como si se pulsaran CTRL-A y CTRL-K. En sistemas donde la tecla de interrupción está configurada para otra cosa (a menudo DEL), CTRL-C pone en mayúsculas el carácter actual.
Usar CTRL-A, CTRL-E y CTRL-K debería ser sencillo. Recuerda que CTRL-Y siempre deshará lo último borrado, ya sea de un solo comando de borrado o de varios comandos de borrado seguidos. Si usas CTRL-K, podrían ser bastantes caracteres.
\subsection{Desplazarse por el archivo histórico}
Ahora sabemos cómo movernos eficientemente por la línea de comandos y hacer cambios. Pero eso no resuelve el problema original de recuperar comandos anteriores accediendo al fichero de historial. El modo Emacs tiene varios comandos para hacer esto, resumidos en la Tabla \ref{tab2.4}.
\newpage
\begin{table}[h]
\center
\caption{Comandos del modo Emacs para moverse por el fichero histórico}
\label{tab2.4}
\begin{tabular}{m{2cm}|m{7cm}} \hline
\textbf{Comando} & \textbf{Descripción} \\ \hline
CTRL-P & Ir a la línea anteriora \\
CTRL-N & Ir a la línea siguiente \\
CTRL-R & Buscar hacia atrás \\
ESC < & Ir a la primera línea del historial \\
ESC > & Ir a la última línea del historial \\
\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 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
\end{lstlisting}
Después de CTRL-A, ESC f, dos CTRL-F y CTRL-D, tienes:
\begin{lstlisting}[language=bash]
ve < ~pete/wk/names
\end{lstlisting}
Decides probar con \emph{-s} en lugar de \emph{-l}, así que tecleas \texttt{s} y pulsas ENTER. Obtienes el mismo mensaje de error, así que te rindes y buscas en el manual. Descubres que el comando que quieres es \emph{fgrep} -- no \emph{grep} -- después de todo. Suspiras pesadamente y vuelves a buscar el comando \emph{fgrep} que tecleaste hace una hora. Para ello, tecleas CTRL-R; lo que había en la línea desaparece y es sustituido por \^{}R. Luego escribes \emph{fgrep}, y ves esto:
\begin{lstlisting}[language=bash]
$ ^Rfgrep
\end{lstlisting}
Pulsa ENTER, y el intérprete de comandos buscará en el historial una línea que contenga <<fgrep>>. Si no encuentra ninguna, emite un pitido. Pero si encuentra una, la muestra, y tu <<línea actual>> será esa línea (es decir, estarás en algún lugar en medio del fichero histórico, no al final como es habitual):
\begin{lstlisting}[language=bash]
$ fgrep -l Bob < ~pete/wk/names
\end{lstlisting}
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 \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 \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 \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 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 \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.}
\item{Si hay exactamente una forma de completar el nombre del archivo, y el archivo es un archivo normal, el shell escribe el resto del nombre del archivo y lo sigue con un espacio para que pueda escribir más argumentos de comando.}
\item{Si hay exactamente una forma de completar el nombre del archivo, y el archivo es un directorio, el shell completa el nombre del archivo y lo sigue con una barra.}
\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 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.
A partir de \emph{ksh93m}, el comando ESC = acepta un prefijo numérico. Cuando se proporciona un prefijo, el shell lo trata como el número de uno de los comandos mostrados por un listado ESC = anterior y completa el nombre de archivo. (Más adelante en este capítulo se proporciona un ejemplo donde se describe la versión en modo vi de este comando).
Cuando se usan TAB, ESC * y ESC = en la primera palabra de la línea de comandos, expanden alias, funciones y comandos. Esta característica tan útil se conoce como \emph{finalización 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 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 \emph{emacs}; se muestran en la Tabla \ref{tab2.5}.
\begin{table}[h]
\center
\caption{Comandos varios en modo Emacs}
\label{tab2.5}
\begin{tabular}{|m{4cm}|m{11cm}|} \hline
\textbf{Comando} & \textbf{Descripción} \\ \hline
CTRL-J & Igual que ENTER. \\\hline
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 \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 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 \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
CTRL-@ & Marca el punto. \\\hline
ESC c & Cambia la palabra después del punto a mayúsculas. \\\hline
ESC l & Cambiar la palabra después del punto a todas las letras minúsculas. \\\hline
ESC p & Guardar todos los caracteres entre el punto y la marca como si se hubieran borrado. \\\hline
ESC . & Inserta la última palabra de la línea de comando anterior después del punto. \\\hline
ESC \_ & Igual que la entrada anterior. \\\hline
ESC CTRL-] x & Buscar x hacia atrás, donde x es cualquier carácter. \\\hline
ESC SPACE & Poner marca en el punto. \\\hline
ESC \# & Antepone \# (carácter de comentario) a la línea y la envía al archivo de historial; útil para guardar un comando que se ejecutará 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 las nuevas líneas en un comando multilínea. \\\hline
\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 \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 \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 \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
\end{lstlisting}
y necesitas volver atrás y cambiar <<very>> por <<really>>, puedes teclear CTRL-U ESC b y tu cursor terminará aquí:
\begin{lstlisting}[language=bash, escapeinside={(*}{*)}]]
$ ls -l /a/(*\highlight{v}*)ery/long/pathname/filename
\end{lstlisting}
A continuación, puedes hacer el cambio. Primero, deshazte de <<very>> escribiendo CTRL-U CTRL-D:
\begin{lstlisting}[language=bash, escapeinside={(*}{*)}]]
$ ls -l /a/(*\highlight{/}*)long/pathname/filename
\end{lstlisting}
A continuación, inserta el nuevo texto:
\begin{lstlisting}[language=bash, escapeinside={(*}{*)}]]
$ ls -l /a/really(*\highlight{/}*)long/pathname/filename
\end{lstlisting}
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 \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>>:
\begin{lstlisting}[language=bash, escapeinside={(*}{*)}]]
$ ls -l /a/(*\highlight{r}*)eally/long/pathname/filename
\end{lstlisting}
Luego podrías teclear ESC d para borrar <<really>> y hacer el cambio. Por supuesto, podrías hacer esto más rápido tecleando ESC DEL en lugar de CTRL-X CTRL-X y ESC d.
De los comandos de cambio de mayúsculas y minúsculas, ESC l (letra ell) es útil cuando pulsas la tecla BLOQ MAYÚS por accidente y no te das cuenta inmediatamente. Como las palabras en mayúsculas no se usan muy a menudo en el mundo Unix, es posible que no uses ESC c muy a menudo.
Si le parece que hay demasiados sinónimos de ENTER, tenga en cuenta que CTRL-M es en realidad el mismo carácter (ASCII) que ENTER, y que CTRL-J es en realidad lo mismo que nueva línea, que Unix suele aceptar en lugar de ENTER de todos modos.
ESC . y ESC \_ son útiles si desea ejecutar varios comandos en un archivo dado. La convención habitual de Unix es que un nombre de fichero es el último argumento de un comando. Por lo tanto, puede ahorrar tecleando simplemente cada comando seguido de SPACE y luego tecleando ESC . o ESC \_. Por ejemplo, digamos que quieres examinar un archivo usando \emph{more}, así que tecleas:
\begin{lstlisting}[language=bash]
$ 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 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 \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 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
\begin{lstlisting}[language=bash]
alias _C='^[b^C' # El valor es ESC b CTRL-C
\end{lstlisting}
Ahora, cada vez que escriba ESC C, el intérprete de comandos se moverá al principio de la palabra actual (ESC b) y, a continuación, pondrá en mayúscula la letra actual (CTRL-C).
\begin{lstlisting}[language=bash, escapeinside={(*}{*)}]]
$ print here is a word # Type ESC C
$ print here is a W(*\highlight{o}*)rd
\end{lstlisting}
\section{Modo de Edición Vi}
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}, \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
\caption{Comandos de edición en modo de entrada vi}
\label{tab2.6}
\begin{tabular}{m{2cm}|m{13cm}}
\hline
\textbf{Comando} & \textbf{Descripción} \\ \hline
DEL & Borrar el carácter anterior \\
CTRL-W & Borrar palabra anterior (es decir, borrar hasta el espacio en blanco) \\
CTRL-V & <<Citar>> el carácter siguiente \\
ESC & Entrar en modo de control (véase más abajo) \\
\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. \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 \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
\caption{Comandos básicos del modo de control vi}
\label{Tab:2-7}
\begin{tabular}{m{2cm}|m{10cm}}
\hline
\textbf{Comando} & \textbf{Descripción} \\ \hline
h & Mover un carácter a la izquierda. \\
l & Mover un carácter a la derecha. \\
space & Mover a la derecha un caracter. \\
w & Mover a la derecha una palabra. \\
b & Mover una palabra a la izquierda. \\
W & Mover al principio de la siguiente palabra no en blanco. \\
B & Mover al principio de la palabra anterior. \\
e & Mover al final de la palabra actual. \\
E & Mover al final de la palabra actual no en blanco. \\
0 & Va al principio de la línea. \\
\^{} & Va al primer carácter no en blanco de la línea. \\
\$ & Va al final de la línea. \\
\end{tabular}
\end{table}
Todos estos comandos, excepto los tres últimos, pueden ir precedidos de un número que actúa como \emph{contador de repeticiones}. Los dos últimos resultarán familiares a los usuarios de utilidades Unix (como \emph{grep}) que utilizan expresiones regulares, así como a los usuarios de vi.
Veamos algunos ejemplos. Digamos que escribes esta línea y, antes de pulsar ENTER, decides que quieres cambiarla:
\begin{lstlisting}[language=bash]
$ fgrep -l Bob < ~pete/wk/names
\end{lstlisting}
Como se muestra, su cursor está más allá del último carácter de la línea. Primero, teclea ESC para entrar en modo de control; tu cursor retrocede un espacio de modo que se encuentra en la \texttt{s}. Luego, si tecleas h, tu cursor retrocede a la \texttt{e}. Si tecleas \texttt{3h} desde la \texttt{e}, terminas en la \emph{n}.
Ahora veremos la diferencia entre los dos conceptos de <<palabra>>. Vuelve al final de la línea tecleando \$. Si tecleas b, la palabra en cuestión es <<names>>, y el cursor acaba en la \texttt{n}:
\begin{lstlisting}[language=bash, escapeinside={(*}{*)}]]
$ fgrep -l Bob < ~pete/wk/(*\highlight{n}*)ames
\end{lstlisting}
Si vuelves a teclear \texttt{b}, la siguiente palabra es la barra (es una <<secuencia>> de caracteres no alfanuméricos), por lo que el cursor acaba sobre ella:
\begin{lstlisting}[language=bash, escapeinside={(*}{*)}]]
$ fgrep -l Bob < ~pete/wk(*\highlight{/}*)names
\end{lstlisting}
Sin embargo, si tecleas \texttt{B} en lugar de \texttt{b}, la palabra no en blanco será el nombre completo de la ruta, y el cursor terminará al principio de la misma, es decir, sobre la tilde:
\begin{lstlisting}[language=bash, escapeinside={(*}{*)}]]
$ fgrep -l Bob < (*\highlight{\~{}}*)pete/wk/names
\end{lstlisting}
Habría tenido que escribir \texttt{b} cuatro veces -- o simplemente \texttt{4b} -- para obtener el mismo efecto, ya que hay cuatro <<palabras>> en la parte de la ruta a la izquierda de \emph{/names: wk, slash, pete} y la tilde inicial.
En este punto, \texttt{w} y \texttt{W} hacen lo contrario: teclear \texttt{w} te lleva sobre la \texttt{p}, ya que la tilde es una <<palabra>>, mientras que teclear \texttt{W} te lleva al final de la línea. Pero mientras que \texttt{w} y \texttt{W} te llevan al principio de la siguiente palabra, \texttt{e} y \texttt{E} te llevan al final de la palabra actual. Así, si tecleas \texttt{w} con el cursor sobre la tilde, llegas a:
\begin{lstlisting}[language=bash, escapeinside={(*}{*)}]]
$ fgrep -l Bob < ~(*\highlight{p}*)ete/wk/names
\end{lstlisting}
Entonces tecleando \emph{e} te lleva a:
\begin{lstlisting}[language=bash, escapeinside={(*}{*)}]]
$ fgrep -l Bob < ~pet(*\highlight{e}*)/wk/names
\end{lstlisting}
Y escribiendo una \emph{w} adicional te lleva a:
\begin{lstlisting}[language=bash, escapeinside={(*}{*)}]]
$ 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 \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.
\begin{table}[h]
\center
\caption{Comandos para entrar en el modo de entrada de vi}
\label{tab2.8}
\begin{tabular}{m{2cm}|m{10cm}}
\hline
\textbf{Comando} & \textbf{Descripción} \\ \hline
i & Texto insertado antes del carácter actual (insertar) \\
a & Texto insertado después del carácter actual (append) \\
I & Texto insertado al principio de la línea \\
A & Texto insertado al final de la línea \\
r & Sustituir un carácter (no entra en modo de entrada) \\
R & El texto sobrescribe el texto existente (reemplazar) \\
\end{tabular}
\end{table}
Lo más probable es que utilices siempre \texttt{i} o \texttt{a}, y puede que ocasionalmente utilices \texttt{R}. \texttt{I} y \texttt{A} son abreviaturas de \texttt{0i} y \texttt{\$a} respectivamente. Para ilustrar la diferencia entre \texttt{i}, \texttt{a} y \texttt{R}, digamos que empezamos con nuestra línea de ejemplo:
\begin{lstlisting}[language=bash, escapeinside={(*}{*)}]]
$ fgrep -l Bob < ~pete/wk(*\highlight{/}*)names
\end{lstlisting}
Si escribes \texttt{i} seguido de end, obtienes:
\begin{lstlisting}[language=bash, escapeinside={(*}{*)}]]
$ fgrep -l Bob < ~pete/wkend(*\highlight{/}*)names
\end{lstlisting}
Es decir, el cursor siempre aparece sobre \texttt{/} antes de \emph{names}. Pero si escribes \texttt{a} en lugar de \texttt{i}, verás que el cursor se mueve un espacio a la derecha. Entonces, si escribes \texttt{nick}, obtendrás
\begin{lstlisting}[language=bash, escapeinside={(*}{*)}]]
$ fgrep -l Bob < ~pete/wk/nick(*\highlight{n}*)ames
\end{lstlisting}
Es decir, el cursor está siempre justo después del último carácter que has tecleado, hasta que tecleas ESC para finalizar tu entrada. Por último, si vuelve a la \texttt{n} en \emph{names}, escriba \texttt{R} en su lugar, y luego escriba \texttt{task}, verá:
\begin{lstlisting}[language=bash, escapeinside={(*}{*)}]]
$ fgrep -l Bob < ~pete/wk/task(*\highlight{s}*)
\end{lstlisting}
En otras palabras, usted estará \emph{reemplazando} (de ahí \texttt{R}) en lugar de insertar texto.
¿Por qué \texttt{R} mayúscula en lugar de \texttt{r} minúscula? Este último es un comando ligeramente diferente, que sustituye sólo un carácter y no entra en modo de entrada. Con \texttt{r}, el siguiente carácter sobrescribe el carácter situado bajo el cursor. Así que si empezamos con la línea de comandos original y tecleamos \texttt{r} seguido de un punto y coma, obtendremos:
\begin{lstlisting}[language=bash, escapeinside={(*}{*)}]]
$ fgrep -l Bob < ~pete/wk(*\highlight{;}*)names
\end{lstlisting}
Si precedes \texttt{r} con un número \emph{N}, te permite reemplazar los siguientes \emph{N} caracteres existentes en la línea -- pero aún no entras en modo de entrada. El modo Vi sustituye los \texttt{N} caracteres de la línea por \texttt{N} copias del carácter que escriba después de la \texttt{r}. La \texttt{r} minúscula es eficaz para corregir letras de opción erróneas, caracteres de redirección de E/S, puntuación, etc.
\subsection{Comandos de eliminación}
Ahora que sabes cómo introducir comandos y moverte por la línea, necesitas saber cómo borrar. El comando básico de borrado en modo vi es \texttt{d} seguido de otra letra. Esta letra determina cuál es la unidad y la dirección de borrado, y corresponde a un comando de movimiento, como los listados previamente en la Tabla \ref{Tab:2-7}. La Tabla \ref{tab2.9} muestra algunos ejemplos de uso común.
\begin{table}[h]
\center
\caption{Algunos comandos de borrado en modo vi}
\label{tab2.9}
\begin{tabular}{m{3cm}|m{10cm}} \hline
\textbf{Commando} & \textbf{Descripción} \\ \hline
dh & Borrar un carácter hacia atrás. \\
dl & Borrar un carácter hacia delante. \\
db & Borrar una palabra hacia atrás. \\
dw & Borrar una palabra hacia delante. \\
dB & Borrar una palabra no en blanco hacia atrás. \\
dW & Borrar una palabra no en blanco hacia delante. \\
d\$ & Borrar hasta el final de línea. \\
d0 & Borrar hasta el principio de línea. \\
\end{tabular}
\end{table}
Estos comandos tienen algunas variaciones y abreviaturas. Si utiliza una \texttt{c} en lugar de \texttt{d}, entrará en el modo de entrada después de que se realice el borrado. Puede proporcionar un número de repetición antes o después de la \texttt{d} (o \texttt{c}). La Tabla \ref{tab2.10} lista las abreviaturas disponibles.
La mayoría de la gente tiende a usar \texttt{D} para borrar hasta el final de la línea, \texttt{dd} para borrar una línea entera, y \texttt{x} (como <<retroceso>>) para borrar caracteres individuales. Si no eres un usuario empedernido de vi, puede que te resulte difícil dominar algunos de los comandos de borrado más esotéricos bajo tus dedos.
\newpage
\begin{table}[h]
\center
\caption{Abreviaturas de los comandos de borrado en modo vi}
\label{tab2.10}
\begin{tabular}{|m{2cm}|m{13cm}|} \hline
\textbf{Comando} & \textbf{Descripción} \\ \hline
D & Equivale a d\$ (borrar hasta el final de la línea) \\\hline
dd & Equivale a 0d\$ (borrar toda la línea) \\\hline
C & Equivale a c\$ (borrar hasta el final de la línea, entrar en modo de entrada) \\\hline
cc & Equivale a 0c\$ (borrar toda la línea, entrar en modo de entrada) \\\hline
s & Equivale a xi (borrar el carácter actual, entrar en modo de entrada) \\\hline
S & Equivale a cc (borrar toda la línea, entrar en modo de entrada) \\\hline
x & Equivale a dl (borrar carácter hacia adelante) \\\hline
X & Equivale a dh (borrar carácter hacia atrás) \\\hline
\end{tabular}
\end{table}
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}.
\begin{table}[h]
\center
\caption{Comandos para cortar y pegar en modo Vi}
\label{tab2.11}
\begin{tabular}{|m{2cm}|m{13cm}|} \hline
\textbf{Texto} & \textbf{Descripción} \\ \hline
y & Corta (guarda) texto, no cambia realmente la línea. \\\hline
p & Pone el último texto arrancado o borrado en la línea después del cursor. \\\hline
P & Coloca el último texto arrancado o borrado en la línea anterior al cursor. \\\hline
u & Deshace el cambio más reciente. \\\hline
U & Deshacer todos los cambios de la línea. \\\hline
. (punto) & Rehacer el último cambio en la posición actual del cursor. \\\hline
\end{tabular}
\end{table}
Los comandos \texttt{d} y \texttt{p} son bastante útiles juntos para reorganizar el orden de las opciones o argumentos en una línea de comandos. Por ejemplo, la mayoría de los compiladores C de Unix aceptan una opción \emph{-l} que indica el nombre de una biblioteca a utilizar al enlazar un programa compilado. La opción \emph{-L} especifica un directorio en el que el compilador debe buscar las bibliotecas, además de buscar en los lugares estándar para las bibliotecas del sistema.
\begin{lstlisting}[language=bash]
cc -o myprog myprog.c -Lmylibdir -lmylib
\end{lstlisting}
Este comando busca el archivo de biblioteca \emph{libmylib.a} en el directorio \emph{mylibdir} al compilar y enlazar \emph{myprog.c}. Hasta aquí todo bien. El problema es que normalmente la opción \emph{-L} debe aparecer en la línea de comandos antes de la opción \emph{-l}. Supongamos que accidentalmente las has escrito al revés y, por tanto, la compilación ha fallado. Puedes utilizar los comandos \texttt{d} y \texttt{p} para reordenar las cosas. Empieza por recuperar la línea
\begin{lstlisting}[language=bash, escapeinside={(*}{*)}]]
$ (*\highlight{c}*)c -o myprog myprog.c -lmylib -Lmylibdir
\end{lstlisting}
A continuación, desplázate hasta la última opción con \texttt{5w}. A continuación, retroceda hasta el espacio anterior con \texttt{h}. Su línea de comandos tiene ahora este aspecto:
\begin{lstlisting}[language=bash]
$ cc -o myprog myprog.c -lmylib-Lmylibdir
\end{lstlisting}
Escribe \texttt{D} para borrar el resto de la línea:
\begin{lstlisting}[language=bash, escapeinside={(*}{*)}]]
$ cc -o myprog myprog.c -lmyli(*\highlight{b}*)
\end{lstlisting}
Ahora retrocede hasta el carácter \texttt{c} anterior con \texttt{Bhh}:
\begin{lstlisting}[language=bash, escapeinside={(*}{*)}]]
$ cc -o myprog myprog.(*\highlight{c}*) -lmylib
\end{lstlisting}
Por último, utilice \texttt{p} para insertar la opción desplazada:
\begin{lstlisting}[language=bash, escapeinside={(*}{*)}]]
$ cc -o myprog myprog.c -Lmylibdi(*\highlight{r}*) -lmylib
\end{lstlisting}
Luego pulsa ENTER y ya está. Esto parece mucho tecleo. Pero, como veremos pronto, hay comandos adicionales que te permiten buscar caracteres en la línea de comandos, haciendo mucho más fácil moverse por ella. Y si eres un usuario experimentado de \emph{vi}, estarás como en casa.
\newpage
\subsection{Desplazarse por el archivo histórico}
El siguiente grupo de comandos del modo de control de vi que cubrimos te permite moverte y buscar en tu archivo de historial. Esta es la funcionalidad más importante que te permite volver atrás y corregir un comando erróneo sin tener que volver a escribir toda la línea. Estos comandos se resumen en la Tabla \ref{tab2.12}.
\begin{table}[h]
\center
\caption{Comandos del modo de control Vi para buscar en el fichero histórico}
\label{tab2.12}
\begin{tabular}{|m{2cm}|m{13cm}|}
\hline
\textbf{Comando} & \textbf{Descripción} \\ \hline
k o - & Retroceder una línea. \\\hline
j o + & Avanzar una línea. \\\hline
G & Desplazarse a la línea indicada por la cuenta de repeticiones, o a la primera línea del historial si no hay cuenta de repeticiones. \\\hline
?cadena & Buscar cadena hacia atrás. \\\hline
/cadena & Buscar cadena hacia delante. \\\hline
n & Repite la búsqueda en la misma dirección que la anterior. \\\hline
N & Repite la búsqueda en la dirección opuesta a la anterior. \\\hline
\end{tabular}
\end{table}
Los tres primeros pueden ir precedidos de cuentas de repetición (por ejemplo, 3k o 3- retrocede tres líneas en el archivo histórico).
Si no estás familiarizado con \emph{vi} y su historia cultural, puede que te estés preguntando la sabiduría de elegir mnemónicos tan aparentemente pobres como \texttt{h, j, k,} y \texttt{l} para carácter de retroceso, línea de avance, línea de retroceso y carácter de avance, respectivamente. Bueno, en realidad hay una razón para las opciones - aparte de que están todos juntos en el teclado estándar.
Bill Joy desarrolló originalmente \emph{vi} para ejecutarse en terminales Lear-Siegler ADM-3a, que fueron los primeros modelos populares con cursores direccionables (lo que significa que un programa podía enviar un comando a un ADM-3a para hacer que moviera el cursor a un lugar específico de la pantalla). Las teclas \texttt{h, j, k} y \texttt{l} de la ADM-3a tenían pequeñas flechas, así que Joy decidió usar esas teclas para los comandos apropiados en \emph{vi}.
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 \emph{emacs}.
Introduce el comando de ejemplo (ENTER funciona tanto en modo de entrada como de control, al igual que newline o CTRL-J):
\begin{lstlisting}[language=bash]
$ fgrep -l Bob < ~pete/wk/names
\end{lstlisting}
Pero recibe un mensaje de error diciendo que la letra de su opción era incorrecta. Quieres cambiarla a \emph{-s} sin tener que volver a escribir todo el comando. Asumiendo que estás en modo control (puede que tengas que teclear ESC para ponerte en modo control), tecleas \texttt{k} o \texttt{-} para recuperar el comando. Tu cursor estará al principio de la línea:
\begin{lstlisting}[language=bash, escapeinside={(*}{*)}]]
$ (*\highlight{f}*)grep -l Bob < ~pete/wk/names
\end{lstlisting}
Escribe \texttt{w} para llegar al \texttt{-}, luego \emph{l} o espacio para llegar a la \texttt{l}. Ahora puedes reemplazarlo escribiendo \texttt{rs}; presiona ENTER para ejecutar el comando.
Ahora digamos que recibes otro mensaje de error, y finalmente decides mirar la página del manual del comando \texttt{fgrep}. Recuerdas haber hecho esto hoy hace un rato, así que en lugar de teclear el comando \emph{man(1)} entero, buscas el último que usaste. Para ello, teclea ESC para entrar en modo control (si ya estás en modo control, esto no tiene ningún efecto), luego teclea / seguido de \emph{man} o \emph{ma}. Para estar seguro, también puede escribir \texttt{\^{}ma}; el \^{} significa que sólo se buscarán las líneas que empiecen por \texttt{ma}.\footnote{Los aficionados a \emph{vi} y a las utilidades de búsqueda como \emph{grep} deben tener en cuenta que el signo de intercalación (\^{}) para el inicio de línea es el único operador contextual que el modo \emph{vi} proporciona para las cadenas de búsqueda.}
Pero teclear \texttt{/\^{}ma} no te da lo que quieres; en su lugar, el shell te da:
\begin{lstlisting}[language=bash, escapeinside={(*}{*)}]]
$ (*\highlight{m}*)ake myprogram
\end{lstlisting}
Para buscar <<man>> de nuevo, puede escribir \texttt{n}, que realiza otra búsqueda hacia atrás utilizando la última cadena de búsqueda. Escribiendo / de nuevo sin un argumento y pulsando ENTER se consigue lo mismo.
El comando \texttt{G} recupera el comando cuyo número es el mismo que el prefijo numérico del argumento que proporcione. \texttt{G} depende del esquema de numeración de comandos descrito en la \hyperref[sec:3423]{Sección 3.4.2.3}, en el \hyperref[sec:Chapter3]{Capítulo 3}. Sin un argumento de prefijo, va al comando número 1. Esto puede ser útil para los antiguos usuarios del intérprete de comandos C que todavía quieran utilizar números de comando.
\subsection{Comandos de Búsqueda de Caracteres}
Hay algunos comandos de movimiento adicionales en el modo vi. Estos comandos le permiten moverse a la posición de un carácter particular en la línea. Se resumen en la Tabla \ref{tab2.13}, en la que x denota cualquier carácter.
Todos estos comandos pueden ir precedidos de una cuenta de repetición.
\begin{table}[h]
\center
\caption{Comandos de búsqueda de caracteres en modo Vi}
\label{tab2.13}
\begin{tabular}{|m{2cm}|m{13cm}|} \hline
\textbf{Comando} & \textbf{Descripción} \\ \hline
fx & Mover a la derecha a la siguiente ocurrencia de x (buscar). \\\hline
Fx & Mover a la izquierda a la ocurrencia anterior de x (encontrar hacia atrás). \\\hline
tx & Mover a la derecha a la siguiente ocurrencia de x, luego hacia atrás una posición (ir al carácter). \\\hline
Tx & Mover a la izquierda a la ocurrencia anterior de x, luego hacia adelante una posición (ir hacia atrás al carácter). \\\hline
; & Rehacer el último comando de búsqueda de caracteres. \\\hline
, & Rehacer el último comando de búsqueda de caracteres en dirección opuesta. \\\hline
\% & Moverse a la coincidencia (, ), \{, \}, [, o ]. \\\hline
\end{tabular}
\end{table}
Empezando por el ejemplo anterior: supongamos que quieres cambiar \emph{Bob} por \emph{Rob}. Asegúrate de que estás al final de la línea (o, en cualquier caso, a la derecha de la \texttt{B} de \emph{Bob}); entonces, si escribes \texttt{FB}, el cursor se desplaza a la \texttt{B}:
\begin{lstlisting}[language=bash, escapeinside={(*}{*)}]]
$ fgrep -l (*\highlight{B}*)ob < ~pete/wk/names
\end{lstlisting}
En este punto, podrías escribir \texttt{rR} para reemplazar la \texttt{B} por \texttt{R}. Pero digamos que quieres cambiar \emph{Bob} por \emph{Blob}. Necesitarías moverte un espacio a la derecha de la \texttt{B}. Por supuesto, podrías simplemente teclear \texttt{l}. Pero, dado que estás en algún lugar a la derecha de \emph{Bob}, la forma más rápida de moverte a la o sería teclear \texttt{TB} en lugar de \texttt{FB} seguido de \emph{l}.
Como ejemplo de cómo se puede usar la cuenta de repetición con comandos de búsqueda de caracteres, digamos que quieres cambiar el nombre del archivo de \emph{names} a \emph{namfile}. En este caso, asumiendo que tu cursor está todavía en la \texttt{B}, necesitas llegar a la tercera \texttt{e} a la derecha, así que puedes teclear \texttt{3te}, seguido de l para poner el cursor de nuevo en la \texttt{e} de \emph{names}.
Los comandos de búsqueda de caracteres también tienen comandos de borrado asociados. Lee las definiciones de los comandos de la tabla anterior y sustituye mentalmente <<borrar>> por <<mover>>. Obtendrá lo que ocurre cuando precede al comando de búsqueda de caracteres dado con una d. El borrado incluye el carácter dado como argumento. Por ejemplo, suponga que su cursor está bajo la n en \emph{names}:
\begin{lstlisting}[language=bash, escapeinside={(*}{*)}]]
$ fgrep -l Bob < ~pete/wk/(*\highlight{n}*)ames
\end{lstlisting}
Si desea cambiar \emph{names} por \emph{aides}, una posibilidad es escribir \texttt{dfm}. Esto significa <<borrar hasta la siguiente aparición de m>>, es decir, borrar <<nam>>. A continuación, puede escribir \texttt{i} (para entrar en el modo de entrada) y luego <<aid>> para completar el cambio.
Una forma mejor, sin embargo, es utilizar \texttt{cfm}. Esto significa <<cambiar todo desde debajo del cursor hasta la siguiente aparición de m inclusive>>. Esto elimina <<nam>> y entra en el modo de entrada.
El comando \% es muy útil para encontrar el carácter <<pair>> coincidente cuando se utiliza con paréntesis, corchetes y llaves. Todos ellos aparecen con frecuencia en pares coincidentes en las líneas de comandos del shell.
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 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 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.}
\item{Si hay exactamente una forma de completar el nombre del fichero, y el fichero es un fichero normal, el shell teclea el resto del nombre del fichero, seguido de un espacio por si quieres teclear más argumentos de comando.}
\item{Si hay exactamente una forma de completar el nombre del archivo, y el archivo es un directorio, el shell completa el nombre del archivo, seguido de una barra.}
\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 \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 \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 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
1) problema.c
2) programa.c
$ cc pr(*\highlight{o}*)
\end{lstlisting}
A partir de \emph{ksh93m}, prefijar el comando = con un contador indica la selección de una opción en particular. Volviendo al ejemplo anterior: después de listar tanto \emph{problem.c} como \emph{program.c}, la línea de comandos queda así:
\begin{lstlisting}[language=bash, escapeinside={(*}{*)}]]
$ cc pr(*\highlight{o}*)
\end{lstlisting}
Si desea \emph{program.c}, basta con escribir 2 =, y el intérprete de comandos elige la expansión número 2. La línea de comandos cambia a:
\begin{lstlisting}[language=bash]
$ cc programa.c
\end{lstlisting}
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}.
\begin{table}[h]
\center
\caption{Comandos varios del modo vi}
\label{tab2.14}
\begin{tabular}{|m{2cm}|m{12cm}|} \hline
\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 \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 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 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 \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:
\begin{lstlisting}[language=bash]
alias _C='B~'
\end{lstlisting}
Ahora, si escribe ESC @ C, el cursor se mueve al principio de la palabra actual (B), y luego pone en mayúscula la letra actual (\~{}).
\begin{lstlisting}[language=bash, escapeinside={(*}{*)}]]
$ print here is a word # Escribe ESC @ C
$ print here is a w(*\highlight{o}*)rd
\end{lstlisting}
\section{El comando histórico}
\emph{hist} es un comando incorporado en el shell \footnote{En ksh88, este comando se llama \emph{fc}, por <<fix command>>. \emph{ksh93} proporciona un alias incorporado para \emph{fc} a \emph{hist}, para aquellos que están acostumbrados a usar el comando \emph{fc}. Las versiones recientes también tienen \emph{fc} como una orden incorporada que se comporta de forma idéntica a \emph{hist}; esto se debe a que POSIX requiere que esta orden esté incorporada.} que proporciona un superconjunto del mecanismo de historial del shell C. Puedes usarlo para examinar los comandos más recientes que has introducido, para editar uno o más comandos con tu editor <<real>> favorito, y para ejecutar comandos antiguos con cambios sin tener que escribir el comando entero de nuevo. Veremos cada uno de estos usos.
La opción \emph{-l} para \emph{hist} lista los comandos anteriores. Toma argumentos que se refieren a órdenes en el fichero histórico. Los argumentos pueden ser números o cadenas alfanuméricas; los números se refieren a las órdenes del fichero histórico, mientras que las cadenas se refieren a la orden más reciente que empiece por la cadena. \emph{hist} trata los argumentos de una forma bastante compleja:
\begin{itemize}
\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 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 \emph{history} y el shell de Korn ejecutará el comando \texttt{hist -l.}
}
\end{itemize}
Algunos ejemplos le aclararán estas opciones. Supongamos que te conectas e introduces estos comandos:
\begin{lstlisting}[language=bash]
ls -l
more myfile
vi myfile
wc -l myfile
pr myfile | lp -h
\end{lstlisting}
Si escribe \texttt{hist -l} (o \texttt{history}) sin argumentos, verá la lista anterior con números de comando, como en:
\begin{lstlisting}[language=bash]
1 ls -l
2 more myfile
3 vi myfile
4 wc -l myfile
5 pr mifichero | lp -h
\end{lstlisting}
La opción -n suprime los números de línea. Si quiere ver sólo los comandos 2 a 4, escriba \texttt{hist -l 2 4}. Si quiere ver sólo el comando \emph{vi}, escriba \texttt{hist -l 3}. Para ver todo desde el comando \\emph{vi} hasta el presente, escriba \texttt{hist -l v}. Finalmente, si desea ver los comandos entre \emph{more} y \emph{wc}, puede escribir \texttt{hist -l m w}, \texttt{hist -l m 4}, \texttt{hist -l 2 4}, etc.
Los números de historial negativos indican valores relativos al número de comando actual. Por ejemplo, \texttt{hist -l -3} muestra el tercer comando anterior. Una forma menos confusa de hacer esto es con la opción \emph{-N: hist -l -N 3} hace lo mismo. Esto también tiene la ventaja de ajustarse a las convenciones POSIX para opciones y argumentos.
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 \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:
\begin{lstlisting}[language=bash]
$ 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 \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:
\begin{itemize}
\item{Sin argumentos, \emph{hist} carga el editor con el comando más reciente.}
\item{Con un argumento numérico, \emph{hist} carga el editor con el comando con ese número.}
\item{Con un argumento de cadena, \emph{hist} carga el comando más reciente empezando por esa cadena.}
\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 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
$ vi lastcommands # Editar lastcommands
$ . lastcommands # Ejecuta los comandos que contiene
\end{lstlisting}
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 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 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
\end{lstlisting}
pero necesitabas ejecutar \emph{eqn}, puedes volver a hacerlo escribiendo \texttt{hist -s tbl=eqn}. (También podrías usar el alias, \texttt{r tbl=eqn}.) Este comando se ejecutaría entonces:
\begin{lstlisting}[language=bash]
eqn ch2.tr | troff -ms -Tps > ch2.ps
\end{lstlisting}
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 \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 \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 \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 \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 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.