Capítulo 12. Programación

# Capítulo 12. Programación

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.

Las referencia en línea está disponible escribiendo «`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 considera que cumple con DFSG.

Por favor, considera la posibilidad de utilizar las herramientas del sistema de control de versiones. Ver Sección 10.5, “Git”.

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

| Atención
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
Los ejemplos de código para crear «La canción de 99 botellas de Cerveza« le aportará buenas ideas para prácticamente cualquier lenguaje de programación.

## 12.1. Los archivos de órdenes

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

    #!/bin/sh
     ... command lines

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« (https://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.

### 12.1.1. Compatibilidad del intérprete de órdenes POSIX

Muchos scripts en el sistema se pueden ejecutar por cualquier shell POSIX (ver Tabla 1.13, “Relación de intérpretes de órdenes”).

- El shell POSIX no interactivo por defecto "`/usr/bin/sh`" es un enlace simbólico que apunta a `/usr/bin/dash` y lo utiliza muchos programas del sistema.

- El shell POSIX interactivo predeterminado es `/usr/bin/bash`.

Evite escribir archivos de órdenes con particularidades de bash o zs para hacerlo portable entre intérpretes de órdenes POSIX. Puede comprobarlo utilizando checkbashisms(1).

Tabla 12.1. Relación de particularidades de bash

Bien: POSIX | Mal: bashism
--- | ---
`if [ "$foo" = "$bar" ] ; then …` | `if [ "$foo" == "$bar" ] ; then …`
`diff -u file.c.orig file.c` | `diff -u file.c{.orig,}`
`mkdir /foobar /foobaz` | `mkdir /foo{bar,baz}`
`funcname() { … }` | `function funcname() { … }`
formato octal: «`\377`» | formato hexadecimal: «`\xff`»

La orden «`echo`» debe utilizarse con cuidado ya que su implementación cambia entre la orden interna y la externa.

- Evite utilizar cualquier opción excepto «`-n`».

- Evite utilizar secuencias de escape en una cadena ya que su tratamiento varia.

| Nota
Ya que la opción «`-n`» no pertenece realmente a la sintaxis POSIXm se acepta normalmente.

| Sugerencia
Utilice la orden «`printf`» en vez de la orden «`echo`» si necesita incluir secuencias de caracteres en las cadenas de caracteres de salida.

### 12.1.2. Parámetros del intérprete de órdenes

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

Tabla 12.2. Relación de los parámetros de intérprete de órdenes

parámetro del intérprete de órdenes | valor
--- | ---
`$0` | nombre del archivo de órdenes
`$1` | primer parámetro del archivo de órdenes
`$9` | noveno parámetro del archivo de órdenes
`$#` | parámetro posicionado en el número
`"$*"` | `"$1 $2 $3 $4 … "`
`"$@"` | `"$1" "$2" "$3" "$4" …`
`$?` | estado de finalización de la orden más reciente
`$$` | PID de este archivo de órdenes
`$!` | PID del trabajo en segundo plano que se ha iniciado más recientemente

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

Tabla 12.3. Relación de expansiones de parámetros del intérprete de órdenes

forma de expresión del parámetro | valor si `var` esta activado | valor si `var` no está asignado
--- | --- | ---
`${var:-string}` | «`$var`» | «`string`»
`${var:+string}` | «`string`» | «`null`»
`${var:=string}` | «`$var`» | «`string`» (y ejecuta «`var=string`»)
`${var:?string}` | «`$var`» | echo «`string`» a stderr (y finalizar con error)

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 únicamente si existe

Tabla 12.4. Relación de las sustituciones clave de parámetros del intérprete de órdenes

formulario de sustitución del parámetro | resultado
--- | ---
`${var%suffix}` | elimina patrón del sufijo más pequeño
`${var%%suffix}` | elimina el patrón del sufijo más largo
`${var#prefix}` | elimina el patrón del prefijo más pequeño
`${var##prefix}` | elimina el patrón del prefijo más largo

### 12.1.3. Condiciones del intérprete de órdenes

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

- Éxito: 0 («Verdadero«)

- Error: no 0 («Falso«)

| 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
«`[`» es el equivalente a la orden `test`, la cual determina la expresión condicional de sus parámetros hasta«`]`».

Algunas expresiones condicionales que es importante 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 [ conditional_expression ]; then
     if_success_run_this_command
    else
     if_not_success_run_this_command
    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`».

Tabla 12.5. Relación de operadores para comparar archivos en la expresión condicional

ecuación | condición que devuelve un verdadero lógico
--- | ---
`-e file` | archivo existe
`-d file` | archivo existe y es un directorio
`-f file` | archivo existe y es un archivo normal
`-w file` | archivo existe y se puede modificar
`-x file` | archivo existe y es ejecutable
`file1 -nt file2` | archivo es más nuevo quearchivo2 (respecto de la modificación)
`file1 -ot file2` | archivo1 es más viejo que archivo2 (modificación)
`file1 -ef file2` | archivo1 y archivo2 están en el mismo dispositivo y tienen el mismo número de inodo

Tabla 12.6. Relación de operadores de comparación de cadenas en expresiones condicionales

ecuación | condición que devuelve un verdadero lógico
--- | ---
`-z str` | la longitud de str es cero
`-n str` | la longitud de str no es cero
`str1 = str2` | str1 y str2 son iguales
`str1 != str2` | str1 y str2 no son iguales
`str1 < str2` | str1 está antes que str2 (depende de la configuración regional)
`str1 > str2` | str1 está después de la str2 (depende de la configuración local)

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

### 12.1.4. Bucles del intérprete de órdenes

Existen diferentes bucles en el intérprete de órdenes POSIX.

- «`for x in foo1 foo2 … ; do comand0 ; done`» asigna secuencialmente elementos de la relación «`foo1 foo2 …`» a la variable «`x`» y ejecuta «`comando`».

- «`while condition ; do command ; done`» repite «`command`» mientras «`condition`» sea verdadero.

- «`until condition ; do command ; done`» repite «`command`» mientras «`condition`» no sea verdadero.

- «`break`» permite salir del bucle.

- «`continue`» permite continuar con la próxima iteración del bucle.

| Sugerencia
La iteración sobre números como la del lenguaje C puede realizarse con la utilización de seq(1) como un generador de «`foo1 foo2 …`».

| Sugerencia
Ver Sección 9.4.9, “Repetición de una orden sobre archivos”.

### 12.1.5. Variables del entorno de shell

Algunas variables del entorno populares para el símbolo del sistema del shell normal pueden no estar disponibles en el entorno de ejecución de su script.

- Para "`$USER`", usar "`$(id -un)`"

- Para "`$UID`", usa "`$(id -u)`"

- Para "`$HOME`", utiliza "`$(getent passwd "$(id -u)"|cut -d ":" -f 6)`" (esto también funciona en Sección 4.5.2, “La actual gestión centralizada de sistemas”)

### 12.1.6. La secuencia de procesamiento de la línea de órdenes

El shell procesa un script aproximadamente como la siguiente secuencia.

- El intérprete de órdenes lee una 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: `space tab newline`

  - 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: `si entonces elif else fi para in while a menos que se haga caso 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

  - «`~user`» → 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`»

  - «`` command ``» → la salida de «`command`»

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

  - `*` → cualquier carácter

  - `?` → un carácter

  - `[…]` → 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.

### 12.1.7. Programas útiles para los archivos de órdenes

Para hacer los archivos de órdenes tan portables como sea posible entre sistemas Debian, es una buena idea limitar las utilidades a aquellos que son proporcionados por los paquetes esenciales.

- «`aptitude search ~E`» relación de paquetes esenciales.

- «`dpkg -L package_name | grep '/man/man.*/'`» relación de páginas del manual de órdenes del paquete `package_name`.

Tabla 12.7. Relación de paquetes que contienen pequeñas utilidades para los archivos de órdenes

paquete | popularidad | tamaño | descripción
--- | --- | --- | ---
`dash` | V:928, I:998 | 207 | Shell compatible con POSIX pequeño y rápido para `sh`
`coreutils` | V:910, I:1000 | 17994 | Utilidades fundamentales GNU
`grep` | V:779, I:1000 | 1297 | GNU `grep`, `egrep` y `fgrep`
`sed` | V:762, I:1000 | 987 | GNU `sed`
`mawk` | V:485, I:998 | 295 | pequeño y rápido `awk`
`debianutils` | V:936, I:997 | 225 | utilidades varias específicas de Debian
`bsdutils` | V:445, I:1000 | 338 | utilidades básicas de BSD-Lite 4.4
`bsdextrautils` | V:754, I:863 | 382 | Herramientas adicionales de 4.4BSD-Lite
`moreutils` | V:18, I:39 | 232 | utilidades adicionales de Unix

| Sugerencia
Aunque `moreutils` puede no existir fuera de Debian, proporciona algunos pequeños programas interesantes. El más notable es sponge(8), que es muy útil cuando desea sobrescribir el archivo original.

Ver un ejemplo en Sección 1.6, “Operaciones de texto al estilo de Unix”.

## 12.2. Programación en lenguajes interpretados

Tabla 12.8. Lista de paquetes relacionados con el intérprete

paquete | popularidad | tamaño | documentación
--- | --- | --- | ---
`dash` | V:928, I:998 | 207 | sh: shell pequeño y rápido compatible con POSIX para `sh`
`bash` | V:893, I:1000 | 7309 | sh: "`info bash`" proporcionado por el paquete `bash-doc`
`mawk` | V:485, I:998 | 295 | AWK: pequeño y rápido `awk`
`gawk` | V:250, I:301 | 3289 | AWK: "`info gawk`" proporcionado por `gawk-doc`
`perl` | V:673, I:992 | 836 | Perl: perl(1) y páginas html proporcionadas por `perl-doc` y `perl-doc-html`
`libterm-readline-gnu-perl` | V:2, I:27 | 439 | Extensión de Perl para la biblioteca GNU ReadLine/History Library: perlsh(1)
`libreply-perl` | V:0.01, I:0.10 | 171 | REPL para Perl: reply(1)
`libdevel-repl-perl` | V:0.03, I:0.57 | 237 | REPL para Perl: re.pl(1)
`python3` | V:717, I:974 | 80 | Python: python3(1) y páginas html proporcionadas por `python3-doc`
`tcl` | V:23, I:176 | 20 | Tcl: tcl(3) páginas de manual detalladas proporcionadas por `tcl-doc`
`tk` | V:17, I:169 | 20 | Tk: tk(3) y páginas detalladas del manual proporcionadas por `tk-doc`
`ruby` | V:71, I:157 | 32 | Ruby: ruby(1), erb(1), irb(1), rdoc(1), ri(1)

Cuando deseas automatizar una tarea en Debian, deberías programarla primero con un lenguaje interpretado. La línea guía para la elección del lenguaje interpretado es:

- Utiliza`dash`, si la tarea es sencilla y combina programas CLI con un programa shell.

- Utiliza `python3`, si la tarea no es sencilla y la estás escribiendo desde cero.

- Usa `perl`, `tcl`, `ruby`, ... si hay un código existente usando uno de estos lenguajes en Debian que necesita ser retocado para hacer la tarea.

Si el código resultante es demasiado lento, puede reescribir sólo la parte crítica para la velocidad de ejecución en un lenguaje compilado y llamarlo desde el lenguaje interpretado.

### 12.2.1. Depuración de los códigos del lenguaje interpretado

La mayoría de los intérpretes ofrecen funciones básicas de comprobación sintáctica y rastreo de código.

- “dash -n script.sh” - Comprobación de sintaxis de un script de Shell

- “dash -x script.sh” - Trazar un script de Shell

- "python -m py_compile script.py" - Comprobación sintáctica de un script Python

- "python -mtrace --trace script.py" - Rastrear un script de Python

- "perl -I ../libpath -c script.pl" - Comprobación sintáctica de un script Perl

- “perl -d:Trace script.pl” - Trazar un script de Perl

Para probar el código para `dash`, prueba Sección 9.1.4, “Readline wrapper” que se acomoda a un entorno interactivo tipo `bash`.

Para probar código para `perl`, prueba el entorno REPL para Perl que acomoda Python-like REPL (=READ + EVAL + PRINT + LOOP) entorno para Perl.

### 12.2.2. Programa GUI con el script de shell

El script de shell se puede mejorar para crear un programa GUI atractivo. El truco es usar uno de los llamados programas de diálogo en lugar de una interacción ligera usando los comandos`echo` y `read`.

Tabla 12.9. Lista de programas de diálogo

paquete | popularidad | tamaño | descripción
--- | --- | --- | ---
`x11-utils` | V:222, I:551 | 651 | xmessage(1): muestra un mensaje o realiza un pregunta en una ventana(X)
`whiptail` | V:303, I:997 | 61 | muestra cuadros de diálogo de fácil uso para los archivos de órdenes (newt)
`dialog` | V:8, I:77 | 520 | muestra cuadros de diálogo de fácil uso para los archivos de órdenes (ncurses)
`zenity` | V:74, I:338 | 193 | mostrar cuadros de diálogo gráficos a partir de scripts de shell (GTK)
`ssft` | V:0.01, I:0.16 | 80 | Herramienta de interfaz de archivo de órdenes (cubierto con zenity, kdialog y dialog con gettext)
`gettext` | V:51, I:216 | 20468 | «`/usr/bin/gettext.sh`»: traduce un mensajes

Aquí hay un ejemplo del programa GUI para demostrar lo fácil que es sólo con un script de shell.

Este script usa `zenity` para seleccionar un archivo (predeterminado `/etc/motd`) y mostrarlo.

El lanzador GUI para este script se puede crear siguiendo Sección 9.4.10, “Iniciar un programa desde el interfaz gráfico de usuario”.

    #!/bin/sh -e
    # Copyright (C) 2021 Osamu Aoki <osamu@debian.org>, Public Domain
    # vim:set sw=2 sts=2 et:
    DATA_FILE=$(zenity --file-selection --filename="/etc/motd" --title="Select a file to check") || \
      ( echo "E: File selection error" >&2 ; exit 1 )
    # Check size of archive
    if ( file -ib "$DATA_FILE" | grep -qe '^text/' ) ; then
      zenity --info --title="Check file: $DATA_FILE" --width 640  --height 400 \
        --text="$(head -n 20 "$DATA_FILE")"
    else
      zenity --info --title="Check file: $DATA_FILE" --width 640  --height 400 \
        --text="The data is MIME=$(file -ib "$DATA_FILE")"
    fi

Este tipo de aproximación al programa GUI con el shell script es útil sólo para casos de elección simple. Si va a escribir cualquier programa con complejidades, por favor considera escribirlo en una plataforma más capaz.

### 12.2.3. Acciones personalizadas para el archivador GUI

Los programas archivadores GUI pueden ampliarse para realizar algunas acciones populares en archivos seleccionados utilizando paquetes de extensión adicionales. También pueden realizar acciones personalizadas muy específicas añadiendo sus scripts específicos.

- Para GNOME, ver NautilusScriptsHowto.

- Para KDE, ver Creación de menús de servicio Dolphin.

- Para Xfce, ver Thunar - Acciones personalizadas y https://help.ubuntu.com/community/ThunarCustomActions.

- Para LXDE, ver Acciones personalizadas.

### 12.2.4. Locura de pequeños archivos de órdenes en Perl

Para procesar los datos, `sh` necesita generar subprocesos que ejecuten `cut`, `grep`, `sed`, etc., es lento. Por otro lado, `perl` tiene capacidades internas para procesar datos, y es rápido. Así que muchos scripts de mantenimiento del sistema en Debian usan `perl`.

Pensemos en seguir un fragmento de la secuencia de comandos AWK de una sola línea y sus equivalentes en Perl.

    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.

- Trucos de ejecución de Perl mediante las opciones de la línea de comandos: perlrun(1)

- Variables especiales de Perl: perlvar(1)

Esta flexibilidad es el punto fuerte de Perl. Al mismo tiempo, esto nos permite crear códigos crípticos y enredados. Así que ten cuidado.

## 12.3. Codificación en lenguajes compilados

Tabla 12.10. Lista de paquetes relacionados con el compilador

paquete | popularidad | tamaño | descripción
--- | --- | --- | ---
`gcc` | V:155, I:564 | 36 | Compilador de GNU C
`libc6-dev` | V:269, I:584 | 12861 | Biblioteca C de GNU: Bibliotecas de desarrollo y archivos de cabecera
`g++` | V:57, I:531 | 13 | Compilador GNU C++
`libstdc++-16-dev` | V:0.7, I:4.3 | 24382 | GNU Standard C++ Library v3 (archivos de desarrollo)
`cpp` | V:332, I:719 | 18 | Preprocesador GNU C
`gettext` | V:51, I:216 | 20468 | Utilidades de internacionalización GNU
`glade` | V:0.7, I:2.7 | 1613 | Desarrollador de interfaces de usuario GTK
`valac` | V:0.2, I:3.2 | 533 | Lenguaje similar a C# para el sistema GObject
`flex` | V:7, I:68 | 1247 | LEX-compatible generador analizador de léxico rápido
`bison` | V:7, I:73 | 3122 | YACC-compatible generador de analizador
`susv2` | I:0.03 | 16 | cumple «La Especificación Única de UNIX v2«
`susv3` | I:0.06 | 16 | cumple «La Especificación Única de UNIX v3«
`susv4` | I:0.04 | 16 | buscar "Las especificaciones únicas de UNIX v4"
`golang` | I:22 | 12 | Compilador del lenguaje de programación Go
`rustc` | V:5, I:20 | 13061 | Lenguaje de programación de sistemas Rust
`gfortran` | V:4, I:50 | 15 | Compilador de GNU Fortran 95
`fpc` | I:2.3 | 101 | Pascal libre

Aquí, Sección 12.3.3, “Flex — una mejora de Lex” y Sección 12.3.4, “Bison — una mejora de Yacc” se incluyen para indicar cómo se puede escribir un programa similar a un compilador en lenguaje C compilando una descripción de nivel superior en lenguaje C.

### 12.3.1. C

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 conjunto 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)

### 12.3.2. Programa sencillo en C (gcc)

Un ejemplo simple " `example.c` " se puede compilar con una biblioteca " `libm` " en un ejecutable " `run_example` " de la siguiente manera.

    $ cat > example.c << EOF
    #include <stdio.h>
    #include <math.h>
    #include <string.h>

    int main(int argc, char **argv, char **envp){
            double x;
            char y[11];
            x=sqrt(argc+7.5);
            strncpy(y, argv[0], 10); /* prevent buffer overflow */
            y[10] = '\0'; /* fill to make sure string ends with '\0' */
            printf("%5i, %5.3f, %10s, %10s\n", argc, x, y, argv[1]);
            return 0;
    }
    EOF
    $ gcc -Wall -g -o run_example example.c -lm
    $ ./run_example
            1, 2.915, ./run_exam,     (null)
    $ ./run_example 1234567890qwerty
            2, 3.082, ./run_exam, 1234567890qwerty

Aquí, se necesita «`-lm`» para enlazar la biblioteca «`/usr/lib/libm.so`» del paquete `libc6` para utilizar la función sqrt(3). La biblioteca real está ubicada en «`/lib/`» con el nombre de archivo «`libm.so.6`», el cual es un enlace simbólico a «`libm-2.7.so`».

Mire el último elemento de la salida. Tiene incluso más de 10 caracteres a pesar de tener «`%10s`».

La utilización de operaciones de punteros sin comprobar los límites, como ocurre con sprintf(3) y strcpy(3), no se utilizan para evitar el desbordamiento del buffer que puede provocar problemas desconocidos. En su lugar se utilizan snprintf(3) y strncpy(3).

### 12.3.3. Flex — una mejora de Lex

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

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

Se pueden encontrar muchos ejemplos sencillos en "`/usr/share/doc/flex/examples/`". [7]

### 12.3.4. Bison — una mejora de Yacc

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

Tabla 12.11. Relación de analizadores sintácticos LALR compatibles con Yacc

paquete | popularidad | tamaño | descripción
--- | --- | --- | ---
`bison` | V:7, I:73 | 3122 | Analizador sintáctico GNU LALR
`byacc` | V:0.1, I:3.0 | 263 | Analizador sintáctico LALR Berkeley
`btyacc` | V:0.01, I:0.06 | 247 | analizador sintáctico hacia atrás basado en `byacc`

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.

He aquí un ejemplo para crear un sencillo programa de calculadora de terminal.

Vamos a crear `example.y`:

    /* calculator source for bison */
    %{
    #include <stdio.h>
    extern int yylex(void);
    extern int yyerror(char *);
    %}

    /* declare tokens */
    %token NUMBER
    %token OP_ADD OP_SUB OP_MUL OP_RGT OP_LFT OP_EQU

    %%
    calc:
     | calc exp OP_EQU    { printf("Y: RESULT = %d\n", $2); }
     ;

    exp: factor
     | exp OP_ADD factor  { $$ = $1 + $3; }
     | exp OP_SUB factor  { $$ = $1 - $3; }
     ;

    factor: term
     | factor OP_MUL term { $$ = $1 * $3; }
     ;

    term: NUMBER
     | OP_LFT exp OP_RGT  { $$ = $2; }
      ;
    %%

    int main(int argc, char **argv)
    {
      yyparse();
    }

    int yyerror(char *s)
    {
      fprintf(stderr, "error: '%s'\n", s);
    }

Vamos a crear `example.l`:

    /* calculator source for flex */
    %{
    #include "example.tab.h"
    %}

    %%
    [0-9]+ { printf("L: NUMBER = %s\n", yytext); yylval = atoi(yytext); return NUMBER; }
    "+"    { printf("L: OP_ADD\n"); return OP_ADD; }
    "-"    { printf("L: OP_SUB\n"); return OP_SUB; }
    "*"    { printf("L: OP_MUL\n"); return OP_MUL; }
    "("    { printf("L: OP_LFT\n"); return OP_LFT; }
    ")"    { printf("L: OP_RGT\n"); return OP_RGT; }
    "="    { printf("L: OP_EQU\n"); return OP_EQU; }
    "exit" { printf("L: exit\n");   return YYEOF; } /* YYEOF = 0 */
    .      { /* ignore all other */ }
    %%

A continuación, ejecute lo siguiente desde el símbolo del sistema para probar esto:

    $ bison -d example.y
    $ flex example.l
    $ gcc -lfl example.tab.c lex.yy.c -o example
    $ ./example
    1 + 2 * ( 3 + 1 ) =
    L: NUMBER = 1
    L: OP_ADD
    L: NUMBER = 2
    L: OP_MUL
    L: OP_LFT
    L: NUMBER = 3
    L: OP_ADD
    L: NUMBER = 1
    L: OP_RGT
    L: OP_EQU
    Y: RESULT = 9

    exit
    L: exit

## 12.4. Herramientas de análisis estático de memoria

Lint herramientas similares pueden ayudar a análisis de código estático automático.

Indent como herramientas pueden ayudar a las revisiones humanas de código reformateando los códigos fuente de forma coherente.

Ctags como herramientas pueden ayudar a las revisiones humanas de código mediante la generación de un archivo de índice (o etiqueta) de los nombres que se encuentran en los códigos fuente.

| Sugerencia
Configurar tu editor favorito (`emacs` o `vim`) para usar plugins asíncronos del motor lint ayuda a tu escritura de código. Estos plugins se están volviendo muy potentes aprovechando Protocolo de servidor de idiomas. Dado que se están moviendo rápidamente, usar su código upstream en lugar del paquete Debian puede ser una buena opción.

Tabla 12.12. Relación de las herramientas para el análisis de código estático

paquete | popularidad | tamaño | descripción
--- | --- | --- | ---
`vim-ale` | I:0.80 | 2833 | Motor asíncrono Lint para Vim 8 y NeoVim
`vim-syntastic` | I:2.0 | 1379 | Trucos de comprobación sintáctica para vim
`elpa-flycheck` | V:0.1, I:1.7 | 1130 | moderna comprobación sintáctica sobre la marcha para Emacs
`elpa-relint` | I:0.06 | 150 | Buscador de errores regexp de Emacs Lisp
`cppcheck-gui` | V:0.1, I:1.0 | 7697 | herramienta para el análisis de código C/C++ (GUI)
`shellcheck` | V:3, I:16 | 22860 | herramienta útil para scripts de shell
`pyflakes3` | V:1, I:12 | 20 | Verificado pasivo de programas Python 3
`pylint` | V:3, I:17 | 2093 | comprobador de código estático Python
`perl` | V:673, I:992 | 836 | intérprete con comprobador de código estático interno: `B::Lint`(3perl)
`rubocop` | V:0.1, I:1.1 | 4192 | Analizador de código estático Ruby
`clang-tidy` | V:2, I:10 | 21 | Herramienta de verificación de formato de regla C++ basada en Clang
`splint` | V:0.06, I:0.92 | 2325 | herramienta para la comprobación estática de errores de programación en C
`flawfinder` | V:0.07, I:0.49 | 187 | herramienta que examina código fuente en C/C++ para encontrar debilidades de seguridad
`black` | V:2, I:13 | 10057 | Formateador de código Python agresivo
`perltidy` | V:0.4, I:3.1 | 3086 | Indentador y reformateador de scripts de Perl
`indent` | V:0.8, I:5.1 | 438 | Programa de formateo del código fuente en lenguaje C
`astyle` | V:0.2, I:2.7 | 770 | Indentador de código fuente para C, C++, Objective-C, C# y Java
`bcpp` | V:0.02, I:0.26 | 114 | Embellecer C(++)
`xmlindent` | V:0.05, I:0.79 | 52 | reformateador del flujo XML
`global` | V:0.2, I:1.6 | 1923 | Herramientas de búsqueda y exploración de código fuente
`exuberant-ctags` | V:2, I:13 | 341 | Crea un índice de archivo de etiquetas de definiciones del código fuente
`universal-ctags` | V:2, I:10 | 4238 | Crea un índice de archivo de etiquetas de definiciones del código fuente

## 12.5. Depuración

La depuración es una parte importante de las actividades de programación. Saber cómo depurar programas lo convierte en un buen usuario de Debian que puede producir informes de errores significativos.

Tabla 12.13. Lista de paquetes de la depuración

paquete | popularidad | tamaño | documentación
--- | --- | --- | ---
`gdb` | V:88, I:161 | 12453 | «`info gdb`» proporcionado por `gdb-doc`
`ddd` | V:0.7, I:5.2 | 4210 | «`info ddd`» proporcionado por `ddd-doc`

### 12.5.1. Fundamentos de gdb

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

Instalamos `gdb` y otros programas relevantes como se muestra.

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

Se puede encontrar un buen tutorial de `gdb`:

- “`info gdb`”

- “Depuración con GDB” en `/usr/share/doc/gdb-doc/html/gdb/index.html`

- “tutorial en la web”

Aquí hay un ejemplo simple del uso de gdb(1) en un "`programa`" compilado con la opción "`-g`" para generar información de depuración.

    $ gdb program
    (gdb) b 1                # set break point at line 1
    (gdb) run args           # run program with args
    (gdb) next               # next line
    ...
    (gdb) step               # step forward
    ...
    (gdb) p parm             # print parm
    ...
    (gdb) p parm=12          # set value to 12
    ...
    (gdb) quit

| 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.

### 12.5.2. Depurando un paquete Debian

Dado que todos los archivos binarios instalados deben eliminarse en el sistema Debian de forma predeterminada, la mayoría de los símbolos de depuración se eliminan en el paquete normal. Para depurar paquetes Debian con gdb(1), se deben instalar paquetes `*-dbgsym` (p. ej., `coreutils-dbgsym` en el caso de `coreutils`). Los paquetes fuente generan automáticamente paquetes `*-dbgsym` junto con paquetes binarios normales y esos paquetes de depuración se colocan por separado en el archivo debian-debug. Consulte los artículos en Debian Wiki para obtener más información.

Si un paquete que se va a depurar no proporciona su paquete `*-dbgsym`, debe instalarlo después de reconstruirlo de la siguiente manera.

    $ 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ñadiéndole «`+debug1`» o añadiéndole «`~pre1`» como se muestra.

    $ dch -i

Compila o instala los paquetes con los símbolos de depuración de la siguiente manera.

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

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

### 12.5.3. Obteniendo trazas

Cuando encuentre un programas que no funciona, es una buena idea al informar del error añadir información sobre las trazas de su ejecución.

El backtrace se puede obtener mediante gdb(1) usando uno de los siguientes enfoques:

- Enfoque de los errores en GDB:

  - Ejecuta el programa desde GDB.

  - Bloquea el programa.

  - Escriba "`bt`" en el indicador de GDB.

- Primer enfoque de los errores:

  - Actualiza el archivo “/etc/security/limits.conf” para incluir lo siguiente:

        * soft core unlimited

  - Escribe "`ulimit -c ilimitado`" en el indicador de shell.

  - Ejecuta el programa desde este indicador de shell.

  - Bloquea el programa para generar un archivo core dump.

  - Cargar el archivo core dump a GDB como "`gdb gdb ./program_binary core`" .

  - Escriba "`bt`" en el indicador de GDB.

Para un bucle infinito o una situación de teclado congelado, puede forzar el bloqueo del programa pulsando `Ctrl-\` o `Ctrl-C` o ejecutando “`kill -ABRT PID`”. (Ver Sección 9.4.12, “Matando un proceso”)

| Sugerencia

Frecuentemente encontrará en primeras líneas «`malloc()`» o «`g_malloc()`». Cuando esto ocurre disminuyen las posibilidades de que las trazas sean útiles. La forma más fácil de encontrar alguna información útil es asignado a la variable de entorno «`$MALLOC_CHECK_`» el valor de 2 (malloc(3)). Puede hacer esto a la vez que se ejecuta `gdb` como se muestra.

     $ MALLOC_CHECK_=2 gdb hello

### 12.5.4. Órdenes avanzadas de gdb

Tabla 12.14. Relación de órdenes avanzadas gdb

orden | descripción de la funcionalidad de la orden
--- | ---
`(gdb) thread apply all bt` | recogen trazas de todos los hilos para programas multihilo
`(gdb) bt full` | recoge los parámetros de la pila de las llamadas de función
`(gdb) thread apply all bt full` | recoge trazas y parámetros como una combinación de las opciones anteriores
`(gdb) thread apply all bt full 10` | recoge trazas y parámetros de las 10 llamadas más recientes para eliminar información no relevante
`(gdb) set logging on` | escribe la salida del registro de `gdb` a un archivo (por defecto «`gdb.txt`»)

### 12.5.5. Comprobar las dependencias de las bibliotecas

Utilice como se muestra ldd(1) para determinar las bibliotecas de las que depende un programa.

    $ ldd /usr/bin/ls
            librt.so.1 => /lib/librt.so.1 (0x4001e000)
            libc.so.6 => /lib/libc.so.6 (0x40030000)
            libpthread.so.0 => /lib/libpthread.so.0 (0x40153000)
            /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)

Para que ls(1) funcione en un entorno `chroot` las bibliotecas siguientes deben estar disponibles en dicho entorno.

Consulte Sección 9.4.6, “Trazando la actividad de un programa”.

### 12.5.6. Herramientas de rastreo dinámico de llamadas

Hay varias herramientas de rastreo dinámico de llamadas disponibles en Debian. Consulta Sección 9.4, “Monitoreando, controlando e iniciando lo que hacer los programas”.

### 12.5.7. Errores de depuración X

Si el programa GNOME `preview1` ha recibido un error de las X se puede ver el mensaje como se muestra.

    The program 'preview1' received an X Window System error.

En este caso, puede intentar ejecutar el programa con «`--sync`», y poner un punto de ruptura en la función «`gdk_x_error`» con el fin de obtener trazas.

### 12.5.8. Herramientas de detección de fugas de memoria

Existen varias herramientas de detección de fugas de memoria en Debian.

Tabla 12.15. Relación de herramientas de detección de fugas de memoria

paquete | popularidad | tamaño | descripción
--- | --- | --- | ---
`libc6-dev` | V:269, I:584 | 12861 | mtrace(1): funcionalidad de depuración de malloc en glibc
`valgrind` | V:4, I:31 | 89318 | depurador y analizador de memoria
`electric-fence` | V:0.2, I:2.3 | 69 | depurador malloc(3)
`libdmalloc5` | V:0.01, I:0.61 | 373 | biblioteca de depuración de la asignación de memoria
`duma` | V:0.00, I:0.06 | 297 | biblioteca para detectar desbordamientos y subdesbordamientos de búfer en programas C y C++
`leaktracer` | V:0.01, I:0.33 | 56 | programas C++ para trazar fugas de memoria

### 12.5.9. Desemsamblado de binarios

Usted puede desemsamblar código binario con objdump(1) como se muestra.

    $  objdump -m i386 -b binary -D /usr/lib/grub/x86_64-pc/stage1

| Nota
gdb(1) puede ser utilizado para desemsamblar el código de forma interactiva.

## 12.6. Herramientas de construcción

Tabla 12.16. Lista de paquetes de herramientas de compilación

paquete | popularidad | tamaño | documentación
--- | --- | --- | ---
`make` | V:150, I:566 | 1762 | «`info make`» proporcionado por `make-doc`
`autoconf` | V:29, I:200 | 2244 | «`info autoconf`» proporcionado con `autoconf-doc`
`automake` | V:28, I:199 | 1932 | «`info automake`» proporcionado con `automake1.10-doc`
`libtool` | V:24, I:183 | 1245 | "`info libtool`" proporcionado por `libtool-doc`
`cmake` | V:21, I:123 | 59735 | cmake(1) sistema make multiplataforma de código abierto
`ninja-build` | V:9, I:55 | 456 | ninja(1) pequeño sistema de construcción más cercano en espíritu a Make
`meson` | V:6, I:29 | 4278 | meson(1) sistema de compilación de alta productividad sobre `ninja`
`xutils-dev` | V:0.9, I:7.0 | 1495 | imake(1), xmkmf(1), etc.

### 12.6.1. Make

Make es una utilidad para mantener grupos de programas. 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 sintaxis del archivo de reglas es la que se muestra.

    target: [ prerequisites ... ]
     [TAB]  command1
     [TAB]  -command2 # ignore errors
     [TAB]  @command3 # suppress echoing

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ínea 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.

Tabla 12.17. Relación de variables automáticas de make

variable automática | valor
--- | ---
`$@` | objetivo
`$<` | primer prerrequisitos
`$?` | todos los prerrequisitos nuevos
`$^` | todos los prerequisitos
`$*` | «`%`» encaja la raíz en el patrón del objetivo

Tabla 12.18. Relación de expansiones de variables de make

expansión variable | descripción
--- | ---
`foo1 := bar` | expansión por única vez
`foo2 = bar` | expansión recursiva
`foo3 += bar` | anexar

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

### 12.6.2. Autotools (Autoherramientas) (herramientas de automatización)

Autotools es un conjunto de herramientas de programación diseñadas para ayudar a que los paquetes de código fuente sean portables a muchos sistemas Unix-like.

- Autoconf es una herramienta para generar scripts de shell "`configure`" desde "`configure.ac`".

  - "`configure`" se usa más adelante para producir "`Makefile`" a partir de la plantilla "`Makefile.in`".

- Automake es una herramienta para producir "`Makefile.in`" a partir de "`Makefile.am`".

- Libtool es un script de shell para abordar el problema de la portabilidad del software al compilar bibliotecas compartidas a partir del código fuente.

#### 12.6.2.1. Compilando e instalando un programa

| Aviso
Cuando compile programas y los instale no sobreescriba los archivos del sistema.

Debian no modifica los archivos en «`/usr/local/`» o «`/opt`». Así que si compila un programa desde el código fuente, instalarlo en «`/usr/local/`» para que no interfiera con Debian.

    $ cd src
    $ ./configure --prefix=/usr/local
    $ make # this compiles program
    $ sudo make install # this installs the files in the system

#### 12.6.2.2. Desinstalando programas

Si se tiene el código original, se utiliza autoconf(1)/automake(1) y se recuerda como se configuró, ejecute lo siguiente para realizar la desinstalación del programa.

    $ ./configure all-of-the-options-you-gave-it
    $ sudo make uninstall

Otra manera, si está totalmente seguro de que la instalación solo únicamente archivos en «`/usr/local/`» y no hay nada importante allí, puede borrar todo su contenido como se muestra.

    # find /usr/local -type f -print0 | xargs -0 rm -f

Si no está seguro de dónde se instalaron los archivos, puede considerar usar checkinstall(8) del paquete `checkinstall`, que dará una ruta de desinstalación clara. Ahora admite la creación de paquetes Debian con la opción "`-D`".

### 12.6.3. Meson

El sistema de creación del software ha ido evolucionando:

- Autotools en la parte superior de Make ha sido el estándar de facto para la infraestructura de compilación portátil desde 1990. Esto es extremadamente lento.

- CMake lanzado inicialmente en el 2000 mejoró la velocidad significativamente pero fue construido originalmente sobre el inherentemente lento Make. (Ahora Ninja puede ser tu backend).

- Ninja, lanzado inicialmente en 2012, está destinado a sustituir a Make para mejorar aún más la velocidad de la compilación y está diseñado para que tus archivos sean generados por un sistema de compilación de nivel superior.

- Meson lanzado inicialmente en 2013 es el nuevo, popular y rápido sistema de compilación de nivel superior que utiliza Ninja como backend.

Consulta los documentos que se encuentran en "El sistema de construcción Meson" y "El sistema de construcción Ninja".

## 12.7. Web

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 envía la cadena URL con los parámetros codificados desde el navegador al servidor web.

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

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

  - «`https://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, ver Interfaz de Pasarela Común (Common Gateway Interface), La Fundación de Software Apache (The Apache Software Foundation) y JavaScript.

Buscar "tutorial CGI" en Google escribiendo la URL codificada https://www.google.com/search?hl=en&ie=UTF-8&q=CGI+tutorial directamente en la dirección del navegador es una buena forma de ver el script CGI en acción en el servidor de Google.

## 12.8. La traducción de código fuente

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

Tabla 12.19. Relación de herramientas de traducción de código fuente

paquete | popularidad | tamaño | palabra clave | descripción
--- | --- | --- | --- | ---
`perl` | V:673, I:992 | 836 | AWK→PERL | convertir código fuente de AWK a PERL: a2p(1)
`f2c` | V:0.1, I:2.0 | 443 | FORTRAN→C | convierte código fuente de FORTRAN 77 a C/C++: f2c(1)
`intel2gas` | V:0.02, I:0.19 | 178 | intel→gas | convierte de NASM (formato Intel) a GAS (Ensamblador GNU)

## 12.9. Haciendo un paquete Debian

Si quiere hacer un paquete Debian, lea lo siguiente.

- Capítulo 2, Gestión de paquetes Debian para comprender los fundamentos del sistema de paquetes

- Sección 2.7.13, “Portar un paquete a un sistema estable” para comprender lo fundamental del proceso de portabilidad

- Sección 9.11.4, “Sistemas chroot” para comprender los fundamentos de la técnica de chroot

- debuild(1), y sbuild(1)

- Sección 12.5.2, “Depurando un paquete Debian” para la recompilación con la finalidad de la depuración

- Guía de Mantenedores Debian (Guide for Debian Maintainers) (el paquete `debmake-doc`)

- Referencia para desarrolladores Debian (el paquete `developers-reference`)

- Manual Directrices de Debian (en el paquete `debian-policy`)

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

[7] Es posible que se necesiten algunos ajustes para que funcionen con el sistema actual.

Capítulo 11. Conversión de datos |  | Apéndice A. Apéndice