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. Shell environment variables
12.1.6. La secuencia de procesamiento de la línea de órdenes
12.1.7. Programas útiles para los archivos de órdenes
12.2. Scripting in interpreted languages
12.2.1. Debugging interpreted language codes
12.2.2. GUI program with the shell script
12.2.3. Custom actions for GUI filer
12.2.4. Locura de pequeños archivos de órdenes en Perl
12.3. Coding in compiled languages
12.3.1. C
12.3.2. Programa sencillo en C (gcc)
12.3.3. Flex — una mejora de Lex
12.3.4. Bison — una mejora de Yacc
12.4. Herramientas de análisis estático de memoria
12.5. Depuración
12.5.1. Fundamentos de gdb
12.5.2. Depurando un paquete Debian
12.5.3. Obteniendo trazas
12.5.4. Órdenes avanzadas de gdb
12.5.5. Comprobar las dependencias de las bibliotecas
12.5.6. Dynamic call tracing tools
12.5.7. Errores de depuración X
12.5.8. Herramientas de detección de fugas de memoria
12.5.9. Desemsamblado de binarios
12.6. Build tools
12.6.1. Make
12.6.2. Autotools
12.6.2.1. Compilando e instalando un programa
12.6.2.2. Desistalando programas
12.6.3. Meson
12.7. Web
12.8. La traducción de código fuente
12.9. 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.

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.

Please consider to use version control system tools. See Sección 10.5, “Git”.

[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
 ... 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« (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 [ 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».



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>

    • Metacharacters: | ; & ( )

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


When you wish to automate a task on Debian, you should script it with an interpreted language first. The guide line for the choice of the interpreted language is:

  • Use dash, if the task is a simple one which combines CLI programs with a shell program.

  • Use python3, if the task isn't a simple one and you are writing it from scratch.

  • Use perl, tcl, ruby, ... if there is an existing code using one of these languages on Debian which needs to be touched up to do the task.

If the resulting code is too slow, you can rewrite only the critical portion for the execution speed in a compiled language and call it from the interpreted language.

The shell script can be improved to create an attractive GUI program. The trick is to use one of so-called dialog programs instead of dull interaction using echo and read commands.


Here is an example of GUI program to demonstrate how easy it is just with a shell script.

This script uses zenity to select a file (default /etc/motd) and display it.

GUI launcher for this script can be created following 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

This kind of approach to GUI program with the shell script is useful only for simple choice cases. If you are to write any program with complexities, please consider writing it on more capable platform.


Here, Sección 12.3.3, “Flex — una mejora de Lex” and Sección 12.3.4, “Bison — una mejora de Yacc” are included to indicate how compiler-like program can be written in C language by compiling higher level description into C language.

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)

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

Lint like tools can help automatic static code analysis.

Indent like tools can help human code reviews by reformatting source codes consistently.

Ctags like tools can help human code reviews by generating an index (or tag) file of names found in source codes.

[Sugerencia] Sugerencia

Configuring your favorite editor (emacs or vim) to use asynchronous lint engine plugins helps your code writing. These plugins are getting very powerful by taking advantage of Language Server Protocol. Since they are moving fast, using their upstream code instead of Debian package may be a good option.


Debug is important part of programming activities. Knowing how to debug programs makes you a good Debian user who can produce meaningful bug reports.


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

Good tutorial of gdb can be found:

  • info gdb

  • “Debugging with GDB” in /usr/share/doc/gdb-doc/html/gdb/index.html

  • tutorial on the web

Here is a simple example of using gdb(1) on a "program" compiled with the "-g" option to produce debugging information.

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

Since all installed binaries should be stripped on the Debian system by default, most debugging symbols are removed in the normal package. In order to debug Debian packages with gdb(1), *-dbgsym packages need to be installed (e.g. coreutils-dbgsym in the case of coreutils). The source packages generate *-dbgsym packages automatically along with normal binary packages and those debug packages are placed separately in debian-debug archive. Please refer to articles on Debian Wiki for more information.

If a package to be debugged does not provide its *-dbgsym package, you need to install it after rebuilding it by the following.

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

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.

The backtrace can be obtained by gdb(1) using one of the following approaches:

For infinite loop or frozen keyboard situation, you can force to crash the program by pressing Ctrl-\ or Ctrl-C or executing “kill -ABRT PID”. (See Sección 9.4.12, “Matando un proceso”)

[Sugerencia] 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

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.

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

Autotools is a suite of programming tools designed to assist in making source code packages portable to many Unix-like systems.

  • Autoconf is a tool to produce a shell script "configure" from "configure.ac".

    • "configure" is used later to produce "Makefile" from "Makefile.in" template.

  • Automake is a tool to produce "Makefile.in" from "Makefile.am".

  • Libtool is a shell script to address the software portability problem when compiling shared libraries from source code.

The software build system has been evolving:

  • Autotools on the top of Make has been the de facto standard for the portable build infrastructure since 1990s. This is extremely slow.

  • CMake initially released in 2000 improved speed significantly but was still build on the top of inherently slow Make.

  • Ninja initially released in 2012 is meant to replace Make for the further improved build speed but is also designed to have its input files generated by a higher-level build system.

  • Meson initially released in 2013 is the new popular and fast higher-level build system which uses Ninja as its backend.

See documents found at "The Meson Build system" and "The Ninja build system".

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.