Capítulo 12. Programación

Tabla de contenidos

12.1. Los archivos de órdenes
12.1.1. Compatibilidad del intérprete de órdenes POSIX
12.1.2. Parámetros del intérprete de órdenes
12.1.3. Condiciones del intérprete de órdenes
12.1.4. Bucles del intérprete de órdenes
12.1.5. La secuencia de procesamiento de la línea de órdenes
12.1.6. Programas útiles para los archivos de órdenes
12.1.7. Archivo de órdenes dialog
12.1.8. Ejemplo de archivo de órdenes con zenity
12.2. Make
12.3. C
12.3.1. Programa sencillo en C (gcc)
12.4. Depuración
12.4.1. Fundamentos de gdb
12.4.2. Depurando un paquete Debian
12.4.3. Obteniendo trazas
12.4.4. Órdenes avanzadas de gdb
12.4.5. Errores de depuración X
12.4.6. Comprobar las dependencias de las bibliotecas
12.4.7. Herramientas de detección de fugas de memoria
12.4.8. Herramientas de análisis estático de memoria
12.4.9. Desemsamblado de binarios
12.5. Flex — una mejora de Lex
12.6. Bison — una mejora de Yacc
12.7. Autoconf
12.7.1. Compilando e instalando un programa
12.7.2. Desistalando programas
12.8. Locura de pequeños archivos de órdenes en Perl
12.9. Web
12.10. La traducción de código fuente
12.11. Haciendo un paquete Debian

Algunos consejos para quién quiera aprender a programar en el sistema Debian para trazar el código fuente. Aquí están los paquetes más importantes y los paquetes de documentación más importantes para la programación.

Tabla 12.1. Relación de paquetes que ayudan a la programación

paquete popularidad tamaño documentación
autoconf V:38, I:269 1868 «info autoconf» proporcionado con autoconf-doc
automake V:37, I:265 1784 «info automake» proporcionado con automake1.10-doc
bash V:826, I:999 6462 «info bash» proporcionado con bash-doc
bison V:11, I:109 2253 «info bison» proporcionado con bison-doc
cpp V:389, I:790 42 «info cpp» proporcionado con cpp-doc
ddd V:0, I:12 3929 «info ddd» proporcionado por ddd-doc
exuberant-ctags V:7, I:42 333 exuberant-ctags(1)
flex V:10, I:98 1225 «info flex» proporcionado por flex-doc
gawk V:443, I:535 2412 «info gawk» proporcionado por gawk-doc
gcc V:173, I:598 45 «info gcc» proporcionado por gcc-doc
gdb V:17, I:124 8989 «info gdb» proporcionado por gdb-doc
gettext V:52, I:345 6594 «info gettext» proporcionado por gettext-doc
gfortran V:8, I:79 16 «info gfortran» proporcionado por gfortran-doc (Fortran 95)
fpc I:4 120 fpc(1) y html por fp-docs (Pascal)
glade V:1, I:9 2306 proporciona ayuda por medio del menú (Constructor UI)
libc6 V:937, I:999 12333 «info libc» proporcionado por glibc-doc y glibc-doc-reference
make V:169, I:604 1296 «info make» proporcionado por make-doc
xutils-dev V:1, I:14 1466 imake(1), xmkmf(1), etc.
mawk V:342, I:998 183 mawk(1)
perl V:618, I:994 575 perl(1) y páginas html proporcionadas por perl-doc y perl-doc-html
python V:578, I:986 68 python(1) y páginas html proporcionado por python-doc
tcl V:30, I:442 22 tcl(3) y páginas de manual detalladas proporcionadas por tcl-doc
tk V:31, I:433 22 tk(3) y páginas de manual detalladas proporcionados por tk-doc
ruby V:173, I:341 37 ruby(1) y la referencia interactiva proporcionada por ri
vim V:119, I:395 2799 ayuda(F1) del menú proporacionado por vim-doc
susv2 I:0 16 cumple «La Especificación Única de UNIX v2«
susv3 I:0 16 cumple «La Especificación Única de UNIX v3«

Las referencia en línea está disponible escribiendo by typing «man nombre» tras instalar los paquetes manpages y manpages-dev. La referencia en línea para las herramientas GNU están disponibles escribiendo «info nombre_de_programa» después de instalar los paquetes correspondientes de documentación. Pude necesitar incluir los repositorios contrib y non-free además del repositorio main ya que una parte de la documentación GFDL no se cosidera que cumple con DFSG.

[Aviso] Aviso

No use«test» como nombre de un archivo ejecutable. «test» es una orden interna del intérprete de órdenes.

[Atención] Atención

Usted puede instalar programas de software directametne compilado de la fuente en «/usr/local» o «/opt» para evitar la colisión con los programas del sistema.

[Sugerencia] Sugerencia

Los ejemplos de código para crear «La canción de 99 botellas de Cerveza« le aportará buenas ideas para pácticamente cualquier lenguaje de programación.

Un archivo de órdenes es un archivo de texto co el bit de ejecución activado y contiene órdenes con el formato siguiente.

#!/bin/sh
 ... líneas de órdenes

La primera línea determina cuál es el intérprete de órdenes que se encarga de leer y ejecutar el contenido del archivo.

La lectura de archivos de órdenes es la mejor manera de entender como funciona un sistema tipo Unix. Aquí, doy algunos apuntes para la programación de archivos de órdenes. Consulte «Errores con el intérprete de órdenes« (http://www.greenend.org.uk/rjk/2001/04/shell.html) para aprender los errores más comunes.

A diferencia del uso interactivo del intérprete de órdenes (consulte Sección 1.5, “Órdenes simples para el intérprete de órdenes” y Sección 1.6, “Operaciones de texto al estilo de Unix”) en los archivos de órdenes se usan generalmente parámetros, condiciones y bucles.

Frecuentemente son utilizados por el intérprete de órdenes parámetros especiales


Lasexpansiones de parámetros fundamentales que debe recordar son las que se muestran.


Aquí, el símbolo «:» en todos estos operadores es realmente opcional.

  • con «:» el operador = comprueba que existe y no es null

  • sin «:» el operador = comprueba unicamente si existe


Cada comando devuelve un estado de salida que puede usarse para expresioneos condicionales.

  • Éxito: 0 («Verdadero«)

  • Error: no 0 («Falso«)

[Nota] Nota

En el contexto del intérprete de órdenes «0« es equivalente a «verdadero«, mientras que en contexto de una condición en C «0« significa «falso«.

[Nota] Nota

«[» es el equivalente a la orden test, la cual detemina la expresión condicional de sus parámetros hasta«]».

Algunas expresiones condicionales que es importate recordar son las que se muestran.

  • «<orden> && <si_éxito_ejecuta_esta_orden_además> || true»

  • «<orden> || <si_no_tiene_éxito_ejecuta_esta_orden_además> || true»

  • Un pequeño archivo de órdenes de varias líneas como se muestra

if [ <expresión_condicional> ]; then
 <si_éxito_ejecuta_esta_órden>
else
 <si_no_éxito_ejecuta_esta_órden>
fi

Aquí se añade «|| true» para asegurarnos de que el archivo de órdenes no finaliza en esta línea si el intérprete de órdenes se llama con la bandera «-e».



Los operadores aritméticos de comparación de enteros en la expresión original son «-eq», «-ne», «-lt», «-le», «-gt» y «-ge».

El intérprete de órdenes ejecuta un archivo de órdenes siguiendo la secuencia que se muestra:

  • el intérprete de órdenes lee la línea

  • El intérprete de órdenes agrupa como un único elemento la parte de la línea incluida entre «…« o '…'.

  • el intérprete de órdenes divide el resto de la línea en elementos como se muestra.

    • Espacios en blanco: <espacio> <tabulador> <nueva línea>

    • Metacaracteres: < > | ; & ( )

  • El intérprete de órdenes comprueba si cada elemento es una palabra reservada para adaptar su comportamiento si no esta incluida entre «…« o '…'.

    • palabras reservadas: if then elif else fi for in while unless do done case esac

  • el intérprete de órdenes expande los alias si no están incluidos entre «…« o '…'

  • El intérprete de órdenes expande las tilde si no están incluidas entre «…« o '…'.

    • «~» → el directorio home del usuario actual

    • «~<usuario>» → el directorio home de <usuario>

  • el intérprete de órdenes expande los parámetros a sus valores si no están incluidos entre '…'

    • parámetro: «$PARAMETER» o «${PARAMETER}»

  • el intérprete de órdenes expande la sustitución de órdenes si no está incluida entre '…'

    • «$( comando )» → la salida de «comando»

    • «` comando `» → la salida de «comando»

  • el intérprete de órdenes expande las rutas de nombres que encajan con nombres de archivos si no están incluidas entre «…« o '…'

    • * → cualesquier caracteres

    • ? → un caracter

    • […] → cualquiera de los caracteres en «»

  • el intérprete de órdenes busca las órdenes como se muestra y los ejecuta

    • definición de lafunción

    • orden interna

    • archivo ejecutable en «$PATH»

  • el intérprete de órdenes va a la siguiente línea y repite este proceso de nuevo desde el inicio de la secuencia

Las comillas simples no tienen efecto dentro de comillas dobles.

Si ejecuta «set -x» en el intérprete de órdenes o lo llama con la opción «-x» hace que se impriman todas las órdenes ejecutadas. Esto puede ser muy útil para la depuración.

Aquí esta un archivo de órdenes simple que crea una imágen ISO con datos redundantes RS02 mediante dvdisaster(1).

#!/bin/sh -e
# gmkrs02 : Copyright (C) 2007 Osamu Aoki <osamu@debian.org>, Public Domain
#set -x
error_exit()
{
  echo "$1" >&2
  exit 1
}
# Initialize variables
DATA_ISO="$HOME/Desktop/iso-$$.img"
LABEL=$(date +%Y%m%d-%H%M%S-%Z)
if [ $# != 0 ] && [ -d "$1" ]; then
  DATA_SRC="$1"
else
  # Select directory for creating ISO image from folder on desktop
  DATA_SRC=$(zenity --file-selection --directory  \
    --title="Select the directory tree root to create ISO image") \
    || error_exit "Exit on directory selection"
fi
# Check size of archive
xterm -T "Check size $DATA_SRC" -e du -s $DATA_SRC/*
SIZE=$(($(du -s $DATA_SRC | awk '{print $1}')/1024))
if [ $SIZE -le 520 ] ; then
  zenity --info --title="Dvdisaster RS02" --width 640  --height 400 \
    --text="The data size is good for CD backup:\\n $SIZE MB"
elif [ $SIZE -le 3500 ]; then
  zenity --info --title="Dvdisaster RS02" --width 640  --height 400 \
    --text="The data size is good for DVD backup :\\n $SIZE MB"
else
  zenity --info --title="Dvdisaster RS02" --width 640  --height 400 \
    --text="The data size is too big to backup : $SIZE MB"
  error_exit "The data size is too big to backup :\\n $SIZE MB"
fi
# only xterm is sure to have working -e option
# Create raw ISO image
rm -f "$DATA_ISO" || true
xterm -T "genisoimage $DATA_ISO" \
  -e genisoimage -r -J -V "$LABEL" -o "$DATA_ISO" "$DATA_SRC"
# Create RS02 supplemental redundancy
xterm -T "dvdisaster $DATA_ISO" -e  dvdisaster -i "$DATA_ISO" -mRS02 -c
zenity --info --title="Dvdisaster RS02" --width 640  --height 400 \
  --text="ISO/RS02 data ($SIZE MB) \\n created at: $DATA_ISO"
# EOF

Puede que quiera crear un lanzador en el escritorio con una orden parecida a «/usr/local/bin/gmkrs02 %d».

Make es una utilidad para mantener grupos de programas. is a utility to maintain groups of programs. La ejecución de make(1) consiste en, la lectura del archivo de reglas «Makefile» por parte de make y la actualización de un objetivo si los archivos que son necesarios han sido modificados desde la última vez o si el objetivo no existe. La ejecución de estas actualizaciones pueden suceder de concurrentemente.

La sintáxis del archivo de reglas es la que se muestra.

objetivo: [ prerequisitos ... ]
 [TAB]  orden1
 [TAB]  -orden2 # ignora los errores
 [TAB]  @orden3 # no imprime la salida

Aquí «[TAB]» es un código TAB. Cada línea es interpretada por el intérprete de órdenes después de la sustitución de las variables. Utilice «\» al final de la líena para continuar el archivo de órdenes. Utilice «$$» para incluir «$» par los valores del entorno para el archivo de órdenes.

Las reglas implícitas y los prerequisitos para un objetivos pueden ser escrito, por ejemplo, como se muestra.

%.o: %.c header.h

Aquí, el objetivo contiene el carácter «%» (únicamente un carácter). El carácter %» encaja con cualquier cadena no vacía que corresponda a los nombres de archivo del objetivo real. Así mismo el prerrequisito utiliza «%» para mostrar como se relaciones sus nombres con los nombres del objetivo real.



Ejecute «make -p -f/dev/null»para ver las reglas internas automática.

Puede configurar su entorno para la compilación de programas escritos en el lenguaje de programación C como se muestra.

# apt-get install glibc-doc manpages-dev libc6-dev gcc build-essential

El paquete libc6-dev, a saber, la biblioteca GNU C, aporta la biblioteca estándar de C que es un conujnto de archivos de cabecera y rutinas de biblioteca utilizadas por el lenguaje de programación C.

Consulte las referencias siguientes sobre C.

  • «info libc» (referencia de las funciones de la biblioteca de C)

  • gcc(1) y «info gcc»

  • nombre_de_cada_función_de_la_biblioteca_de_C(3)

  • Kernighan & Ritchie, «The C Programming Language«, 2nd edición (Prentice Hall)

La depuración es una de las actividades más importantes de la programación. Conocer como depurar un programa le convierte en un usuario de Debian mejor que puede aportar informes de error relevantes.

El principal depurador en Debian es gdb(1) el cual permite inspeccionar un programa mientras se ejecuta.

Instalemo gdb y otros programas relevantes com se muestra.

# apt-get install gdb gdb-doc build-essential devscripts

Puede encontrar un buen tutorial de gdb en «info gdb» y mucha más información a través de Internet. Aquí hay un ejemplo sencillo de la utilización de gdb(1) en un «programa» que ha sido compilado para producir información de depuración con la opción «-g».

$ gdb programa
(gdb) b 1                # pone un punto de ruptura en la línea 1
(gdb) run args           # ejecuta el programa con args
(gdb) next               # siguiente línea
...
(gdb) step               # paso hacia adelante
...
(gdb) p parm             # imprime el valor de parm
...
(gdb) p parm=12          # le asigna el valor de 12
...
(gdb) quit
[Sugerencia] Sugerencia

Existen abreviaturas para la mayor parte de las órdenes de gdb(1). La expansión del tabulador funciona de la misma manera que en el intérprete de órdenes.

Por omisión, en un paquete normal, los binarios del sistema Debian deben estar limpios por lo que la mayor parte de los símbolos del sistema son eliminados. Para depurar un paquete Debian con gdb(1), se necesita la instalación de su paquete correspondiente *-dbg o *-dbgsym (p. ej. libc6-dbg en el caso de la libc6 o coreutils-dbgsym en el caso de coreutils).

Los paquetes más antiguos tienen su paquete *-dbg correspondiente. Este se encuentra en el área principal del archivo Debian junto con el propio paquete. Los paquetes más nuevos pueden generar de forma automática cuando se construyen paquetes *-dbgsym y estos están separados en el archivo debian-debug. Para más información al respecto consulte los artículos de la Wiki de Debian.

Si el paquete que se quiere depurar no ofrece ni su versión *-dbg ni su versión *-dbgsym, necesita instalarlo después de construirlo como se muestra.

$ mkdir /path/new ; cd /path/new
$ sudo apt-get update
$ sudo apt-get dist-upgrade
$ sudo apt-get install fakeroot devscripts build-essential
$ apt-get source package_name
$ cd package_name*
$ sudo apt-get build-dep ./

Si lo necesita corrija los errores.

Cuando recompile la publicación de un paquete ya existente elija una que no exista en Debian, p. ej. añadiendole «+debug1» o añadiendole «~pre1» como se muestra.

$ dch -i

Para compilar e instalar paquetes con la depuración de símbolos activada realice las siguientes operaciones:

$ export DEB_BUILD_OPTIONS="nostrip noopt"
$ debuild
$ cd ..
$ sudo debi package_name*.changes

Necesita comprobar que los archivos de órdenes del paquete y utlizar «CFLAGS=-g -Wall» para la compilación de binarios.

Flex es un generador rápido de analizadores léxicos compatible con Lex.

Puede encontrar un tutuorial de flex(1) en «info flex».

Necesita que proporcione su propio «main()» y «yywrap()». De otra manera su programa flex se parecerá a este al compilarlo sin la biblioteca. Esto es debido a que «yywrap» es una macro y «%option main» se combierte implicitamente en «%option noyywrap».

%option main
%%
.|\n    ECHO ;
%%

También puede compilar con la opción de enlazado «-lfl» al final de su línea de órdenes cc(1) (como AT&T-Lex con «-ll»). En ese caso no es necesaria la opción «%option».

Los paquetes que proporcionan un mejor y compatible Yacc son el analizador sintáctico LR o el analizador sintáctico LALR de Debian.


Puede encontrar un tutorial de bison(1) en «info bison».

Puede que sea necesario que proporcione su propio «main()» y «yyerror()». El método «main()» invoca «yyparse()» el cual invoca «yylex()», que normalmente se crea con Flex.

%%

%%

Autoconf es una herramienta para la producción de automática de archivos de órdenes que configura de forma automática los paquetes de código fuente y los adapat a diferentes sistemas tipo Unix utilizando el sistema de construcción GNU completo.

Autoconf(1) crea el archivo de órdenes de configuración «configure». «Configure» crea de forma automática un archivo «Makefile» personalizado utilizando la plantilla «Makefile.in».

A pesar de que cualquier archivo de órdenes AWK puede ser reeescrito de forma automática en Perl utilizando a2p(1), los archivos de órdenes de una línea AWK se convierten mejor a archivos de órdenes de una sola línea en Perl de forma manual.

Pensemos en el siguiente fragmento de archivo de órdenes de AWK.

awk '($2==«1957«) { print $3 }' |

Esto es equivalente a cualquiera de las siguientes líneas.

perl -ne '@f=split; if ($f[1] eq «1957«) { print «$f[2]\n«}' |
perl -ne 'if ((@f=split)[1] eq «1957«) { print «$f[2]\n«}' |
perl -ne '@f=split; print $f[2] if ( $f[1]==1957 )' |
perl -lane 'print $F[2] if $F[1] eq «1957«' |
perl -lane 'print$F[2]if$F[1]eq+1957' |

El último es retorcido. Utiliza algunas de las funcionalidades avanzadas de Perl.

  • El espacio en blanco es opcional.

  • La conversión entre números y cadenas se realiza de forma automática.

Consulte perlrun(1) sobre las opciones de la línea de órdenes. Puede encotrar más archivos de órdenes en Perl retorcidos en Perl Golf y pueden ser muy interesantes.

Se pueden crear páginas web dinámicas básicas como se muestra.

  • Las consultas se presentan al navegador del usuario utilizando formularios HTML.

  • Rellenando y pulsado sobre las entradas del formulario se envia la cadena URL con los parámetros codificados desde el navegador al servidor web.

    • «http://www.foo.dom/cgi-bin/program.pl?VAR1=VAL1&VAR2=VAL2&VAR3=VAL3»

    • «http://www.foo.dom/cgi-bin/program.py?VAR1=VAL1&VAR2=VAL2&VAR3=VAL3»

    • «http://www.foo.dom/program.php?VAR1=VAL1&VAR2=VAL2&VAR3=VAL3»

  • «%nn» en la URL se sustituye por el carácter hexadecimal que tiene el valor nn.

  • Las variables de entorno se asignan como: «QUERY_STRING=«VAR1=VAL1 VAR2=VAL2 VAR3=VAL3«».

  • Un programa CGI (independientemente de su extensión «programa.*») en un servidor web se ejecuta a si mimo con la variable de entorno «$QUERY_STRING».

  • La salida de un programa CGI se envía al servidor web y se representa como una página web dinámica.

Por seguridad es mejor no realizar de forma manual o de otras formas la gestión de análisis de los parámetros CGI. Existen módulos para ello en Perl y Python. PHP tiene dicha funcionalidad. Cuando se necesita almacenar información del usuario, se utilizan las cookies HTTP cookies. Cuando se necesita procesar información en el lado del cliente, normalmente se utiliza Javascript.

Para mayor información, consulteInterfaz de Pasarela Común (Common Gateway Interface), La Fundación de Software Apache (The Apache Software Foundation) y JavaScript.

Buscar «CGI tutorial« en Google, escribiendo la URL codificada http://www.google.com/search?hl=en&ie=UTF-8&q=CGI+tutorial directamente en la barra de direcciones del navegador, es una buena manera de ver en acción un archivo de órdenes en el servidor G¡de Google.

Existen aplicaciones para convertir código fuente de un lenguaje a otro.


Si quiere hacer un paquete Debian, lea lo siguiente.

Existen paquetes que ayudan al empaquetado como debmake, dh-make, dh-make-perl, etc.