%***********************************************************************
%
%       Spanish Translation by:  José Manuel Puerta Peña,
%                                a920226@ZIPI.FI.UPM.ES
%
%       Revisado (cballard)      Jun 19, 1997
%
%***********************************************************************
\chapter{Comandos divertidos}\label{funny-chapter}
\newcommand{\var}[1]{#1}

Bueno, la mayoría de la gente que tiene que ver con los comandos de
UNIX expuestos en este capítulo no estarán de acuerdo con este título.
``¡Que diablos! Se me ha enseñado que el interfaz del \linux\ es muy
estándar, y ahora tenemos un grupo de comandos, cada uno trabajando de
una manera completamente diferente.  Nunca recordaré todas esas
opciones, ¿y dice que son {\em divertidos}\/?''  Sí, Vd. ha visto un
ejemplo del humor de los \var{hackers}\footnote{N.T.: La palabra
  Hacker en este contexto se refiere a una persona con profundos
  conocimientos de informática.}.  Además, mírelo desde el lado
positivo: no hay comandos del MS-DOS equivalentes a éstos.  Si los
necesita, tiene que adquirirlos por separado, y nunca sabrá como será
su interfaz.  Aquí hay un útil ---y económico--- valor añadido,
¡¡así que disfrútelo!!.

El conjunto de comandos explicados en este capítulo cubre
\cmdnm{find}, que permite al usuario buscar grupos de ficheros
especificados dentro del árbol de directorios; \cmdnm{tar}, útil para
empaquetar algún archivo para ser enviado o sólo salvado; \cmdnm{dd},
el multicopista de bajo nivel; y \cmdnm{sort}, el cual \ldots sí,
clasifica ficheros.  Una última condición: estos comandos no están
bajo ningún concepto estandarizados, y si bien podríamos encontrar un
núcleo de opciones comunes en todos los sistemas $*$IX, las versiones
(de GNU) que se explican más abajo, y Vd.\ puede encontrar en su
sistema \linux, usualmente poseen muchas más capacidades.  Por tanto,
si Vd.\ planea usar otros sistemas operativos UNIX, por favor, no
olvide comprobar la página del manual del sistema en cuestión para
aprender las quizás no tan pequeñas diferencias.

\section{\cmdnm{find}, el buscador de ficheros}

\subsection{Generalidades}

Entre los diversos comandos vistos hasta aquí, había algunos que
permitían al usuario bajar recursivamente el árbol del directorio para
llevar a cabo alguna acción: los ejemplos canónicos son \cmdln{ls -R}
y \cmdln{rm -R}.  Bien. \cmdnm{find} es {\em el\/} comando recursivo.
Cada vez que piense ``Bueno, tengo que hacer tal cosa con todos esos
ficheros en mi propia partición'', haría mejor en pensar en usar
\cmdnm{find}.  En cierto sentido el hecho que \cmdnm{find} encuentre
ficheros es solo un efecto secundario: su ocupación real es evaluar.

La estructura básica del comando es como sigue:

\begin{command}
{\tt find}\impttindex{find} {\em ruta} [\ldots] {\em expresión} [\ldots]
\end{command}

Esto es al menos en la versión de GNU; otras versiones no permiten
especificar más que una ruta, y además es muy infrecuente la necesidad
de hacer tal cosa.  La explicación burda de la sintaxis del comando es
bastante simple: Vd.\ indica desde dónde quiere empezar la búsqueda
(la parte de la {\em ruta}; con el \cmdnm{find} de GNU puede omitir
esto y será tomado por defecto el directorio en uso~\file{.}), y que
clase de búsqueda quiere realizar (la parte de la {\em expresión}).

El comportamiento estándar del comando es un poco engañoso, por lo que
más vale tenerlo en cuenta.  Supongamos que en su directorio principal
de usuario existe un directorio llamado \file{basura}, el cual
contiene un fichero \file{foobar}.  Vd.\ felizmente escribe
\cmdln{find .\ -name foobar}(lo que como puede adivinar busca ficheros
llamados \file{foobar}), y obtiene \ldots nada más que otra vez el
prompt.  El problema reside en el hecho de que \cmdnm{find} es por
defecto un comando silencioso; sólo devuelve 0 si la búsqueda fue
completada (con o sin haber encontrado algo) o un valor distinto de
cero si hubiera habido algún problema.  Esto no ocurre con la versión
que Vd. puede encontrar en el \linux, pero de todas maneras es útil
recordarlo.

\subsection{Expresiones}

La parte de la {\em expresión} puede ser dividida en cuatro grupos
diferentes de palabras clave: {\em opciones}, {\em tests}, {\em
  acciones}, y {\em operadores}.  Cada uno de ellos puede devolver un
valor verdadero/falso, junto con un efecto secundario.  La diferencia
entre los grupos se muestra a continuación.

\begin{description}
\item [opciones] afecta a la función general de \cmdnm{find}, más que
  al procesamiento de un solo fichero.  Un ejemplo es \cmdln{-follow},
  el cual instruye a \cmdnm{find} para seguir enlaces simbólicos en
  vez de sólo presentar el nodo-i.  Siempre devuelven verdadero.
\item [tests] son verdaderos tests (por ejemplo, \cmdln{-empty}
  comprueba si el fichero está vacío), y puede devolver verdadero o
  falso.
\item [acciones] tienen también un efecto secundario sobre el nombre
  del fichero considerado.  Pueden asimismo devolver verdadero o
  falso.
\item [operadores] no devuelven realmente un valor (convencionalmente
  pueden ser considerados como verdaderos), y se usan para construir
  expresiones sintéticas.  Un ejemplo es \cmdln{-or}, el cual hace la
  OR lógica de las dos subexpresiones a su lado.  Note que cuando se
  yuxtaponen expresiones, está involucrada una \cmdln{-and}.
\end{description}

Debe advertir que \cmdnm{find} depende del intérprete de comandos para
tener la línea de comandos analizada sintácticamente: esto significa
que todas las palabras clave deben ser introducidas entre espacios en
blanco y además, que hay un montón de caracteres bonitos que deberán
precederse de escape, si no serían destrozados por el propio
intérprete de comandos.  Cada vía de escape (barra invertida, simples
y dobles comillas) está bien; en los ejemplos las palabras clave de un
solo carácter se señalizarán en general mediante con una barra
invertida, porque es la manera más simple (al menos en mi opinión.
¡Y soy yo quien está escribiendo estas notas!).

\subsection{Opciones}

Aquí está la lista de todas las opciones conocidas de la versión GNU
de \cmdnm{find}.  Recuerde que siempre devuelven verdadero.

\begin{description}
\item {\sf -daystart} mide el tiempo transcurrido no desde hace 24
  horas si no desde la última medianoche.  Un auténtico hacker
  probablemente no entenderá la utilidad de tal opción, pero un
  trabajador que programa de ocho a cinco si lo apreciará.
\item {\sf -depth} procesa el contenido de cada directorio antes que
  el directorio en si.  A decir verdad, no conozco muchos usos de
  esto, aparte de una emulación del comando \cmdln{rm -F} (por
  supuesto Vd.\ no puede borrar un directorio antes de que todos sus
  ficheros sean borrados también \ldots
\item {\sf -follow} respeta (es decir, sigue) los enlaces simbólicos.
  Implica la opción \cmdln{-noleaf}; ver abajo.
\item {\sf -noleaf} desactiva una optimización que dice ``Un
  directorio contiene dos subdirectorios menos que su \var{cuenta de
    enlaces rígidos}\footnote {N.T. \var{hard link count}}''.  Si el
  mundo fuera perfecto, todos los directorios serían referenciados por
  cada uno de sus subdirectorios (a causa de la opción {\tt ..}), como
  {\tt .}  dentro de sí mismo, y por su nombre ``real'' desde su
  directorio padre.
  
  Esto significa que cada directorio debe ser referenciado al menos
  dos veces (una por sí mismo, otra por su directorio padre) y
  cualquier referencia adicional es por subdirectorios.  En la
  práctica, sin embargo, los enlaces simbólicos y los sistemas de
  fichero distribuidos\footnote{Los sistemas de fichero distribuidos
    permiten a los ficheros mostrarse como si fueran locales a una
    máquina cuando realmente están situados en algún otro lugar.}
  pueden alterar esto.  Esta opción hace que \cmdnm{find} funcione
  ligeramente más despacio, pero debe dar los resultados esperados.
\item {\sf -maxdepth {\it niveles\/}}, {\sf -mindepth {\it
      niveles\/}}, donde {\it niveles} es un entero no negativo.
  Indican respectivamente que a lo sumo o que al menos {\it niveles\/}
  de directorios deberían explorarse.  Un par de ejemplos son
  obligados: \cmdln{-maxdepth 0} indica que el comando debería
  realizarse sólo sobre los argumentos de la línea de comandos, es
  decir, sin bajar recursivamente el árbol de directorios;
  \cmdln{-mindepth 1} inhibe el procesamiento del comando para los
  argumentos en la línea de comandos, pero se consideran todos los
  otros ficheros debajo.
\item {\sf -version} imprime la versión en uso del programa.
\item {\sf -xdev}, el cual es un nombre engañoso, instruye a
  \cmdnm{find} para {\bf no} \var{cruzarse de
    dispositivo}\footnote{N.T.: \var{to cross device}}, es decir, no
  cambiarse de sistema de ficheros.  Es muy útil cuando se tiene que
  buscar algo en el sistema de ficheros raíz; en muchas máquinas es
  una partición algo pequeña, pero, sino, ¡un \cmdln{find /} buscaría
  en la estructura entera!  Podemos así evitar los sistemas de archivo
  que no son promisorios.
\end{description}

\subsection{Test}

Los dos primeros test son muy simples de comprender: \cmdln{-false}
siempre devuelve falso, mientras que \cmdln{-true} siempre devuelve
verdadero.  Otros test que no necesitan la especificación de un valor
son \cmdln{-empty}, el cual devuelve verdadero si el fichero está
vacío, y el par \cmdln{-nouser}/\cmdln{-nogroup}, los cuales devuelven
verdadero en el caso que ninguna entrada en \file{/etc/passwd} o
\file{/etc/group} cuadre con el identificador de usuario/grupo del
propietario del fichero.  Veamos un problema común en los sistemas
multiusuario: se borra un usuario, pero los ficheros pertenecientes a
él permanecen en la parte más extraña de los sistemas de ficheros, y
debido a las leyes de Murphy ocupan mucho espacio.  El par de test que
hemos visto en último lugar nos permitirá encontrar esos archivos.

Por supuesto, es posible buscar un usuario o grupo específico.  Los
test son \cmdln{-uid {\sl nn}} y \cmdln{-gid {\sl nn}}.
Desafortunadamente no es posible dar directamente el nombre del
usuario, sino que es necesario usar el identificador numérico, {\em
  nn}.

Además está permitido usar las formas \cmdln{$+$nn}, que significa
``un valor estrictamente más grande que {\em nn\/}'', y \cmdln{$-$nn},
que significa ``un valor estrictamente más pequeño que {\em nn\/}''.
Esto es bastante estúpido en el caso de \var{identificadores de
  usuario}\footnote{N.T.: \var{UIDs}}, pero se volverá práctico con
otros test.

Otra opción útil es \cmdln{-type c}, la cual devuelve verdadero si el
fichero es del tipo especial de {\bf c}arácter.  Los mnemónicos para
las posibles selecciones son las mismas letras que se encuentran en
\cmdnm{ls}; entonces, tenemos {\bf b}loque cuando el fichero es uno
especial de bloque; {\bf d}irectorio; {\bf p}ipes para \var{tuberías
  designadas}\footnote{N.T.: \var{named pipes}}; {\bf l}ink para
enlaces simbólicos, y {\bf s}ockets\var{sockets}\footnote{N.T.:
  \var{enchufe}}.  Los ficheros regulares se indican con {\bf f}ile.
Un test relacionado es \cmdln{-xtype}, que es similar a \cmdln{-type}
excepto en el caso de enlaces simbólicos.  Si se ha proporcionado la
opción \cmdln{-follow}, se examina el enlace, en lugar del fichero al
que se apunta.  El test \cmdln{-fstype {\em type\/}} no tiene nada que
ver; en este caso, lo que se examina es el tipo del sistema de
ficheros.  Creo que la información se consigue del fichero
\file{/etc/mtab}, el único que presenta los sistemas de ficheros
montados; estoy seguro que los tipos nfs, tmp, msdos y ext2 están
entre los reconocidos.

Los test \cmdln{-inum {\em nn\/}} y \cmdln{-links {\em nn\/}} examinan
si el fichero tiene número de nodo-i {\em nn\/}, o {\em nn\/} enlaces,
mientras que \cmdln{-size{\em nn\/}} es verdadero si el fichero tiene
{\em nn\/} bloques de 512~bytes asignados.  (Bueno, no precisamente;
para ficheros disgregados los bloques no asignados también se
cuentan).  Como hoy en día el resultado de \cmdln{ls -s} no siempre se
mide en trozos de 512~bytes (\linux, por ejemplo, usa 1~kbyte como la
unidad), es posible adicionar a {\em nn} el caracter \cmdln{b}, el
cual significa contar en bytes, o \cmdln{k}, contar en kilobytes.

Los bits de permiso son examinados a través del test \cmdln{-perm {\em
    mode\/}}.  Si el {\em modo\/} no está antecedido por un signo,
entonces los bits de permiso del fichero deben cuadrar exactamente con
ellos.  Un \cmdln{-} al principio significa que todos los bits de
permiso deben ser puestos a uno, pero no hace suposiciones sobre los
otros; un \cmdln{+} al principio se satisface sólo si cualquiera de
los bits está a uno.  ¡Ups! Olvidé decir que el modo se escribe en
octal o simbólicamente, como se usa en \cmdnm{chmod}.

El próximo grupo de test está relacionado con el tiempo que hace que
se ha utilizado un fichero por última vez.  Esto viene bien cuando un
usuario ha llenado su espacio, ya que usualmente hay muchos ficheros
que no usaba desde hace años, y cuyo significado ha olvidado.  El
problema es localizarlos, y \cmdnm{find} es la única esperanza a la
vista.  \cmdln{-atime {\em nn\/}} es verdadero si la última vez que se
accedió al fichero fue hace {\em nn} días; \cmdln{-ctime {\em nn\/}}
si el estado del fichero fue cambiado por última vez hace {\em nn\/}
días ---por ejemplo, con un \cmdnm{chmod}--- y \cmdln{-mtime {\em
    nn\/}} si el fichero fue modificado por última vez hace {\em nn\/}
días.  Algunas veces Vd.\ necesita una \var{marca de tiempo}
\footnote{N.T.: \var{timestamp}} más precisa; el test \cmdln{-newer
  {\em archivo\/}} se satisface si el fichero considerado ha sido
modificado más tarde que el {\em archivo\/}.  Por lo tanto, Vd.\ sólo
tiene que usar \cmdnm{touch} con la fecha deseada, y ya está.  El
\cmdnm{find} de GNU añade los test \cmdln{-anewer} y \cmdln{-cnewer}
los cuales se comportan de una manera similar; y los test
\cmdln{-amin}, \cmdln{-cmin} y \cmdln{-mmin} que cuentan el tiempo en
minutos en vez de períodos de 24 horas.

Por último pero no menos importante, el test que yo uso más a menudo.
\cmdln{-name {\em patrón\/}} es verdadero si el nombre del fichero
concuerda exactamente con {\em patrón\/}, el cual es más o menos el
único que se usaría en un \cmdnm{ls} estándar.  (¿Por qué `más o
menos'? Porque, por supuesto, Vd.\ tiene que recordar que todos los
parámetros son procesados por el intérprete de comandos, y esos
encantadores metacaracteres sufren una expansión.  Así, un test como
\cmdln{-name foo*} no devolverá lo que Vd.\ desea, y Vd.\ debería
escribir cualquiera de los dos \cmdln{-name foo\*} o \cmdln{-name \dq
  foo*\dq}.  Este es probablemente uno de los más comunes errores
cometidos por usuarios descuidados, así que escríbalo en letras
GRANDES en su pantalla.  Otro problema es que, como con \cmdnm{ls}, no
se reconocen los puntos al principio del nombre del archivo.  Para
hacer frente a esto, puede usar el test \cmdln{-path {\em patrón\/}}
el cual no se preocupa acerca de los puntos y barras inclinadas cuando
compara la ruta del fichero considerado con {\em patrón}.

\subsection{Acciones}

Hemos dicho que las acciones son aquellas que realmente hacen algo.
Bueno, \cmdln{-prune} más bien {\em no\/} hace nada, es decir, al
descender el árbol de directorios (a menos que se le agregue
\cmdln{-depth}).  Se la encuentra usualmente junto con
\cmdln{-fstype}, para elegir entre varios sistemas de ficheros a
aquellos que deberían examinarse.

Las otras acciones pueden ser divididas en dos amplias categorías;

\begin{description}
  
\item Acciones que {\em imprimen\/} algo. La más obvia de estas ---y
  en realidad, la acción por defecto de \cmdnm{find}-- es
  \cmdln{-print} que imprime el nombre del(os) fichero(s) que
  concuerde(n) con las otras condiciones en la línea de comandos, y
  devuelve verdadero.  Una variante sencilla de \cmdln{-print} es
  \cmdln{-fprint {\em archivo\/}}, en la cual se usa {\em archivo\/}
  en vez de la salida estándar; otra es \cmdln{-ls} lista el fichero
  en uso en el mismo formato que \cmdln{ls -dils}; \cmdln{-printf{\em
      formato\/}} se comporta más o menos como la función de C
  \cmdnm{printf()}, para que se pueda especificar que formato debería
  tener la salida, y \cmdln{-fprintf {\em archivo formato\/}} hace lo
  mismo, pero escribiéndolo en {\em archivo}.  Estas acciones también
  devuelven verdadero.
  
\item Acciones que {\em ejecutan\/} algo. Su sintaxis es un poco
  extraña y su uso está muy extendido, por lo que, por favor,
  considérelas.
  
  \cmdln{-exec {\em comando\/} \char`\\;} ejecuta el comando, y la
  acción devuelve verdadero si el estado retornado por el comando es
  0, lo que significa que la ejecución fue correcta.  La razón para el
  \cmdln{\char`\\;} es bastante lógica: \cmdnm{find} no sabe donde
  termina el comando, y el truco de poner la acción ejecutable al
  final del comando no es aplicable.  Bueno, la mejor manera para
  señalar el final del comando es usar el caracter que usa el
  intérprete de comandos para este fin, que es \cmdln{;}, pero, por
  supuesto, un punto y coma solo en la línea de comandos sería
  "comido" por el intérprete de comandos y nunca llegaría a
  \cmdnm{find}, así que tienen que ser precedidos de escape.  La
  segunda cosa a recordar es como especificar el nombre del fichero en
  uso dentro del {\em comando}, ya que probablemente Vd.\ hizo todo el
  esfuerzo al construir la expresión para hacer algo, y no sólo para
  ver la hora.  Esto se hace por medio de la cadena de caracteres
  \cmdln{\{\}}.  Algunas versiones antiguas de \cmdnm{find} requieren
  que coloque las llaves entre espacios en blanco ---no muy práctico
  si Vd.\ necesita, por ejemplo, la ruta entera y no sólo el nombre
  del fichero--- pero con el \cmdnm{find} de GNU podría ser cualquier
  lugar de la cadena de caracteres que compone el {\em comando}.  (¿Y
  no debería estar precedido de escape o entrecomillado?, seguramente
  se estará preguntando.  Asombrosamente, yo nunca tuve que hacer esto
  ni bajo \cmdnm{tcsh} ni bajo \cmdnm{bash} (\cmdnm{sh} no considera
  \verb-{- y \verb-}- como carácteres especiales, así que no es ni
  mucho menos un problema).  Mi idea es que los intérpretes de
  comandos ``saben'' que \verb-{}- no es una opción que tenga sentido,
  por tanto no intentan expandirlas, afortunadamente para \cmdnm{find}
  que puede obtenerla intacta.
  
  \cmdln{-ok {\em comando\/} \char`\\;} se comporta como
  \cmdln{-exec}, con la diferencia que para cada fichero seleccionado
  se pregunta al usuario que confirme el comando; si la respuesta
  empieza por {\tt y} o {\tt Y}, se ejecuta, de otra manera no, y la
  acción devuelve falso.

\end{description}

\subsection{Operadores}

Hay una cierta cantidad de operadores; aquí hay una lista, en orden de
prioridad decreciente.

\begin{description}

\item[{\sf $\backslash$( {\em expr\/} $\backslash$)}]%
~\vspace{-\itemsep}\vspace{-\itemsep}
\item[~] Fuerza el orden de prioridad.  Los paréntesis deben, por
        supuesto, estar entre comillas, ya que también son muy
        significativos para el intérprete de comandos.

\item[{\sf ! {\em expr\/}}]%
~\vspace{-\itemsep}\vspace{-\itemsep}
\item[{\sf -not {\em expr\/}}]%
~\vspace{-\itemsep}\vspace{-\itemsep}
\item[~] Cambia el verdadero valor de la expresión, esto es, si {\em
        expr\/} es verdadera, se vuelve falsa.  El signo de
        exclamación no tiene que ser precedido de escape, porque
        está seguido por un espacio en blanco.

\item[{\sf {\em expr1 expr2} }]%
~\vspace{-\itemsep}\vspace{-\itemsep}
\item[{\sf {\em expr1\/} -a {\em expr2\/}}]%
~\vspace{-\itemsep}\vspace{-\itemsep}
\item[{\sf {\em expr1\/} -and {\em expr2\/}}]%
~\vspace{-\itemsep}\vspace{-\itemsep}
\item[~] Todas corresponden con la operación lógica AND.  El caso
        más común es el primero, en el cual está implícita.  {\em
        expr2\/} no se evalua, si {\em expr1\/} es falsa.

\item[{\sf {\em expr1\/} -o {\em expr2\/}}]%
~\vspace{-\itemsep}\vspace{-\itemsep}
\item[{\sf {\em expr1\/} -or {\em expr2\/}}]%
~\vspace{-\itemsep}\vspace{-\itemsep}
\item[~] corresponden a la operación lógica OR.  {\em expr2\/} no
        es evaluada, si {\em expr1\/} es verdadera.

\item[{\sf {\em expr1\/}, {\em expr2\/}}]%
~\vspace{-\itemsep}\vspace{-\itemsep}
\item[~] es la declaración de lista; ambas {\em expr1\/} y {\em
        expr2\/} se evaluan (junto con todos los efectos secundarios,
        ¡por supuesto!), y el valor final de la expresión es el de
        {\em expr2\/}.

\end{description}

\subsection{Ejemplos}

Sí, \cmdnm{find} tiene demasiadas opciones, lo se. Pero, hay un montón
de casos preparados que valen la pena recordar, porque son usados muy
a menudo.  Veamos algunos de ellos.

\begin{verbatim}
$ find . -name foo\* -print
\end{verbatim}
% $ para equilibrar el font-lock-mode de emacs

encuentra todos los nombres de fichero que empiezan con \file{foo}.
Si la cadena de caracteres está incluida en el nombre, probablemente
tiene más sentido escribir algo como \cmdln{\char`\"*foo*\char`\"}, en
vez de \cmdln{\*foo\*}.

\begin{verbatim}
$ find /usr/include -xtype f -exec grep foobar \
           /dev/null {} \;
\end{verbatim}
% $ para equilibrar el font-lock-mode de emacs

Es un \cmdnm{grep} ejecutado recursivamente que empieza del directorio
\file{/usr/include}.  En este caso, estamos interesados tanto en
ficheros regulares como en enlaces simbólicos que apuntan a ficheros
regulares, por tanto el test \cmdln{-xtype}.  Muchas veces es más
simple evitar especificarlo, especialmente si estamos bastante seguros
cuales ficheros binarios no contienen la cadena de caracteres deseada.
(¿Y por qué el \file{/dev/null} en el comando?  Es un truco para
forzar al \cmdnm{grep} a escribir el fichero del nombre donde se ha
encontrado un emparejamiento.  El comando \cmdnm{grep} se aplica a
cada fichero con una invocación diferente, y, por tanto no cree que
sea necesario mostrar a la salida el nombre del fichero.  Pero ahora
hay {\em dos\/} ficheros, esto es: ¡el activo y \file{/dev/null}!
Otra posibilidad podría ser \var{redirigir la salida}\footnote{N.T.:
  \var{to pipe}} del comando a \cmdnm{xargs} y dejarle llevar a cabo
el \cmdnm{grep}.  Yo lo intenté, e hice pedazos completamente mi
sistema de ficheros (junto con estas notas que estoy intentando
recuperar a mano {\tt :-(} ).

\begin{verbatim}
$ find /  -atime +1 -fstype ext2 -name core \
              -exec rm {} \;
\end{verbatim}
% $ para equilibrar el font-lock-mode de emacs
Es un trabajo clásico para la tabla de tareas preplaneadas.  Borra
todos los ficheros llamados \file{core} en el sistema de ficheros del
tipo ext2 al cual no se ha accedido en las últimas 24 horas.  Es
posible que alguien quiera usar los \var{ficheros de imagen de
  memoria}\footnote{N.T.: \var{core file}} para realizar un volcado
post mortem, pero nadie podría recordar lo que estuvo haciendo después
de 24 horas\ldots

\begin{verbatim}
$ find /home -xdev -size +500k -ls > piggies
\end{verbatim}
% $ para equilibrar el font-lock-mode de emacs
Es útil para ver quién tiene esos archivos que atascan el sistema de
ficheros.  Note el uso de \cmdln{-xdev}; como sólo estamos interesados
en un sistema de ficheros, no es necesario descender otro sistema de
ficheros montado bajo \file{/home}.

\subsection{Una última palabra}

Tenga en mente que \cmdnm{find} es un comando que consume mucho
tiempo, ya que tiene que acceder a cada uno de los nodos-i del sistema
para realizar su operación.  Por lo tanto, es sabio combinar cuantas
operaciones sean posibles en una única invocación de \cmdnm{find},
especialmente en las tareas de `mantenimiento interno' que usualmente
se administran mediante un trabajo de la tabla de tareas planificadas.
Un ejemplo informativo es el siguiente: supongamos que queremos borrar
los ficheros que acaban en \file{.BAK} y cambiar la protección de
todos los directorios a 771 y todos los ficheros que acaban en
\file{.sh} a 755.  Y quizás temgamos montado el sistema de ficheros
NFS en un enlace telefónico, y no querramos examinar los ficheros ahí.
(¿Por qué escribir tres comandos diferentes?  La manera más efectiva
para realizar la tarea es ésta:

\begin{verbatim}
$ find . \( -fstype nfs -prune \) -o \
         \( -type d       -a -exec chmod 771 {} \; \) -o \
         \( -name "*.BAK" -a -exec /bin/rm {}   \; \) -o \
         \( -name "*.sh"  -a -exec chmod 755 {} \; \) 
\end{verbatim}
% $ para equilibrar el font-lock-mode de emacs
Parece feo (¡y con mucho abuso de barras invertidas!), pero mirándolo
fijamente revela que la lógica subyacente es bastante sencilla.
Recuerde: lo que se hace es una evaluación verdadero/falso; el comando
introducido es sólo un efecto secundario.  Pero esto significa que se
ejecuta sólo si \cmdnm{find} puede evaluar la parte ejecutable de la
expresión, esto es sólo si la parte izquierda de la subexpresión se
evalúa como verdadera.  Así, si por ejemplo el fichero considerado en
el momento es un directorio entonces el primer ejecutable se evalúa y
el permiso del nodo-i se cambia a 771; de otra manera olvida todo y
pasa a la siguiente subexpresión.  Probablemente, es más fácil verlo
en la práctica que escribirlo; pero después de un momento, llegará a
ser una cosa natural para Vd.

\section{\cmdnm{tar}, el archivador en cinta}

\subsection{Introducción}

\subsection{Opciones principales}

\subsection{Modificadores}

\subsection{Ejemplos}

\section{\cmdnm{dd}, el duplicador de datos}

La leyenda dice que allá lejos en las nieblas del tiempo, cuando el
primer UNIX fue creado, sus desarrolladores necesitaron un comando de
bajo nivel para copiar datos entre dispositivos.  Como tenían prisa,
decidieron tomar prestada la sintaxis usada en las máquinas IBM-360, y
desarrollar más tarde un interfaz consistente con la de los otros
comandos.  El tiempo pasó, y todos se acostumbraron tanto con la
manera extraña de usar \cmdnm{dd} que ya ha quedado así.  No se si es
verdad, pero es una bonita historia para contar.

\subsection{Opciones}

A decir verdad, \cmdnm{dd} no es totalmente distinto de los otros
comandos de UNIX: es en realidad un {\bf filtro}, esto es, lee por
defecto de la entrada estándar y escribe en la salida estándar.  Por
tanto, si Vd.\ escribe sólo \cmdnm{dd}, la terminal se queda quieta,
esperando una entrada, y un \key{Ctrl-C} es la única cosa con sentido
a teclear (para cortarlo).

La sintaxis del comando es como sigue:

\vspace{1ex}
\begin{command}
  {\tt dd}\impttindex{dd} [if={\sl archivo\_entrada}] [of={\sl
    archivo\_salida}] [ibs={\sl cant\_bytes}] [obs={\sl cant\_bytes}]
    [bs={\sl cant\_bytes}] [cbs={\sl cant\_bytes}] [skip={\sl
    cant\_bloques}]\\
\hspace{.5in} [seek={\sl cant\_bloques}] [count={\sl cant\_bloques}]
    [conv=\{ascii, ebcdic, ibm, block, unblock,\\
\hspace{.5in} lcase,
    ucase, swab, noerror, notrunc, sync\}]
\end{command}

Todas las opciones son de la forma {\em opción$=$valor}.  No se
permite ningún espacio ni antes ni después del signo de igual; esto
solía ser molesto, porque el intérprete de comandos no expandía un
nombre de fichero en esta situación, pero la versión de \cmdnm{bash}
presente en Linux es bastante inteligente, así que Vd.\ no tiene que
preocuparse por eso.  Es también importante recordar que todos los
valores numerables ({\tt cant\_bytes} y {\tt cant\_bloques} citados
arriba) pueden ser seguidos por un multiplicador.  Las opciones
posibles son {\bf b} para bloque, el cual multiplica por 512, {\bf k}
para kilobytes (1024), {\bf w} para palabra (2), y {\tt x}{\bf m} que
multiplica por {\bf m}.

El significado de las opciones se explica a continuación.

\begin{description}
  
\item {\sf if={\em archivo\_entrada\/}} y {\sf of={\em
      archivo\_salida\/}} instruye a \cmdnm{dd} a respectivamente leer
  de {\em archivo\_entrada\/} y escribir a {\em archivo\_salida\/}.
  En el último caso, el fichero de salida es truncado al valor dado
  por \cmdln{seek}, o si la palabra clave no está presente, a 0 (esto
  es, borrado), antes de realizar la operación.  Mire también la
  opción \cmdln{notrunc}.
  
\item {\sf ibs={\em nn\/}} y {\sf obs={\em nn\/}} especifican cuantos
  bytes deben ser leídos o escritos a la vez.  Creo que por defecto es
  1~bloque, esto es, 512~bytes, pero no estoy muy seguro de ello:
  desde luego funciona de esa manera con \var{ficheros
    planos}\footnote{N.T.: \var{plain files}}.  Estos parámetros son
  muy importantes cuando se usa dispositivos especiales como entrada o
  salida; por ejemplo, leer de la red debería establecer \cmdln{ibs} a
  10~kbyte, mientras que una \var{disquetera} \footnote{N.T.:
    \var{floppy}} de 3.5\dq de alta densidad tiene como tamaño natural
  de bloque 18~kbyte.  Fallar al establecer estos valores podría
  repercutir no sólo a largo plazo al llevar a cabo el comando, sino
  inclusive en errores de expiración de plazo, así que tenga cuidado.
  
\item {\sf bs={\em nn\/}} tanto lee y escribe {\em nn\/} bytes a la
  vez.  Este no hace caso a las palabras clave \cmdln{ibs} y
  \cmdln{obs}.
  
\item {\sf cbs={\em nn\/}} establece el buffer de conversión a {\em
    nn\/} bytes.  Este buffer se usa cuando se traduce de ASCII a
  EBCDIC, o desde un dispositivo no ablocado a uno
  ablocado\footnote{N. del T.: ablocado se refiere a la característica
    de agrupamiento en bloques de los datos en el dispositivo.}.  Por
  ejemplo, los ficheros creados bajo VMS tienen a menudo un tamaño de
  bloque de 512, así que se tiene que poner \cmdln{cbs} a 1b cuando se
  lee una cinta externa de VMS.  ¡Espero que Vd.\ no tenga que
  entretenerse en estas cosas!
  
\item {\sf skip={\em nbl\/}} y {\sf seek={\em nbl\/}} le dicen al
  programa que omita {\em nbl\/} bloques respectivamente al final de
  la entrada y al principio de la salida.  Por supuesto, el último
  caso tiene sentido si se da la conversión \cmdln{notrunc} (ver
  abajo).  Cada tamaño de bloque es el valor de \cmdln{ibs}
  (\cmdln{obs}).  Cuidado: si no establece el \cmdln{ibs} y escribe
  \cmdln{skip=1b} Vd.\ está realmente omitiendo 512$\times$512 bytes,
  esto es 256KB\@.  No es precisamente lo que Vd.\ quería, ¿no?
  
\item {\sf count={\em nbl\/}} pretende copiar sólo {\em nbl\/} bloques
  de la entrada, cada uno de los tamaños dados por \cmdln{ibs}.  Esta
  opción, junto con la previa, se vuelve útil si, por ejemplo, Vd.\ 
  tiene un fichero corrupto y quiere recuperar cuanto sea posible de
  él.  Vd.\ debe omitir la parte ilegible y copiar lo que resta.
  
\item {\sf conv={\em conversión\/},[{\em conversión\/}\ldots]}
  transforma el fichero de la manera que se especifica en sus
  argumentos.  Transformaciones posibles son \cmdln{ascii}, que
  convierte de EBCDIC a ASCII; \cmdln{ebcdic} y \cmdln{ibm}, las
  cuales realizan una conversión inversa (¡sí, no existe una única
  conversión de EBCDIC a ASCII\@! La primera es la estándar, pero la
  segunda funciona mejor cuando se imprimen ficheros en una impresora
  IBM); \cmdln{block}, la cual rellena registros terminados en nueva
  línea del tamaño de \cmdln{cbs}, reemplazando los cambios de línea
  con espacios finales; \cmdln{unblock}, que realiza lo contrario
  (elimina espacios finales, y los reemplaza con cambios de línea);
  \cmdln{lcase} y \cmdln{ucase}, para convertir a minúsculas y
  mayúsculas, respectivamente; \cmdln{swab}, que intercambia cada par
  de bytes de entrada (por ejemplo, para usar un fichero que contiene
  enteros de tipo short escritos en una máquina 680x0 en una máquina
  basada en Intel se necesita dicha conversión); \cmdln{noerror}, para
  continuar procesando aún después de encontrar errores; \cmdln{sync},
  que rellena los bloques de entrada del tamaño de \cmdln{ibs} con
  caracteres NUL finales.
\end{description}

\subsection{Ejemplos}

El ejemplo canónico es con el único que Vd.\ probablemente ha chocado
hasta ahora, cuando intentó crear el primer disco de \linux: como
escribir a un disco sin un sistema de ficheros MS-DOS. La solución es
simple:

\begin{verbatim}
$ dd if=disk.img of=/dev/fd0 obs=18k count=80
\end{verbatim}
% $ para equilibrar el font-lock-mode de emacs
Decidí no usar \cmdln{ibs} porque no se cual es el mejor tamaño de
bloque para un disco duro, pero en este caso no habría hecho ningún
perjuicio si en vez de \cmdln{obs} usara sencillamente el \cmdln{bs}
---inclusive podría haber sido un poquito más rápido.  Observe la
explicación del número de sectores a escribir (18~kbyte es lo que
ocupa un sector, así que \cmdln{count} se pone a 80) y el uso del
nombre de bajo nivel del dispositivo de la disquetera.

Otra aplicación útil de \cmdnm{dd} está relacionada con la copia de
seguridad de la red.  Supongamos que estamos en una máquina {\sl alfa}
y que en la máquina {\sl beta} está la unidad de cinta
\file{/dev/rst0} con un fichero \cmdnm{tar} que estamos interesados en
obtener.  Tenemos los mismos privilegios en ambas máquinas, pero no
hay espacio en {\sl beta} para \var{volcar} \footnote{N.T.:
  \var{dump}} el fichero \cmdnm{tar}.  En este caso, podríamos
escribir
\begin{verbatim}
$ rsh beta 'dd if=/dev/rst0 ibs=8k obs=20k' | tar xvBf - 
\end{verbatim}
% $ para equilibrar el font-lock-mode de emacs
para hacer en un solo paso la operación completa.  En este caso, hemos
usado las facilidades de \cmdnm{rsh} para realizar la lectura de la
cinta.  Los tamaños de entrada y salida están establecidos a los
valores por defecto por estas operaciones, esto es 8~kbyte para la
lectura de la cinta y 20~kbyte para la escritura en ethernet; desde el
punto de vista de la otra cara del \cmdnm{tar}, hay el mismo flujo de
bytes el cual podría ser obtenido de la cinta, excepto el hecho de que
llega de una manera bastante errática, y la opción B es necesaria.

¡Ah! Casi lo olvidaba: No creo para nada que \cmdnm{dd} sea un
acrónimo de ``data duplicator'', pero al menos es una manera divertida
de recordar su significado\ldots

\section{\cmdnm{sort}, el clasificador de datos}

\subsection{Introducción}

\subsection{Opciones}

\subsection{Ejemplos}
% Local Variables:
% mode: latex
% TeX-master: "guide"
% End:
