Comandos de la consola GNU/Linux (Debian 10: Bash)

Un comando es una orden que interpreta el intérprete de comandos y que sirve para interaccionar con el sistema operativo. Hay órdenes para realizar todo, gestionar archivos, ejecutar aplicaciones, administrar servicios de red, explorar internet, diagnosticar tu computador, etc.
Un comando está formado por el nombre del comando, una o varias opciones que modifican el comportamiento del comando y uno o varios argumentos que indican la ruta o archivo con el que el comando va a trabajar. Las opciones tienen un formato corto, una letra precedida por un guión y un formato largo, una palabra que indica la opción precedida por dos guiones. Aunque depende del programador que realizó el comando, algo más o menos estándar es que la opción -h imprima la ayuda del comando. Esa misma opción tiene un formato largo –help. Como ya he comentado, aunque existen prácticas comunes en cuanto a las opciones asociadas a la palabra en inglés que identifica la opción (h para la ayuda, v para sacar información de los pasos que está haciendo, etc.), cada comando puede seguir sus propias reglas.

Antes de empezar a ver ejemplos tres cosas que debes tener en cuenta:

  1. Los intérpretes de comandos en linux son sensibles a las mayúsculas por lo tanto ls es un comando distinto a LS. Por lo general, los nombres de comandos todos en minúsculas. Lo mismo para las opciones, generalmente, no es lo mismo -p que -P, aunque esto depende del creador del comando y, aunque recomendable, no está tan estandarizado.
  2. El tabulador autocompleta nombres de comandos, de directorios y de archivos. Aquí reside gran parte de la potencia de la consola y de su alta productividad, acostúmbrate a utilizar el tabulador. Generalmente la configuración por defecto está habilitada, si no, hay que habilitarla. Si quieres usar el comando mkdir, teclea mk y pulsa tabulador, si hay más de un comando que empieza por mk no hará nada, pulsa otra vez el tabulador y te sugerirá todos los comandos que empiezan por mk, sigue tecleando y cuando no sea ambiguo, si pulsas tabulador te lo completará.
  3. No hace falta «estudiarte» los comandos, poco a poco, los que más uses se te irán quedando, es buena idea imprimirte una hoja de comandos (por ejemplo, esta, esta otra, o esta) al principio para ir mirando los más habituales. En breve no te hará falta

Vamos a ver un ejemplo antes de seguir. El comando ls lista los directorios y archivos que hay dentro de un determinado directorio. En el gif de abajo, la primera vez que ejecutamos el comando ls, no ponemos ninguna opción ni argumento. Esto hace que ls coja las opciones y argumentos habilitadas por defecto, con lo cual, nos saca un listado de nombres con un código de colores (los azules son directorios) y del directorio donde se ejecuta ls.

Si queremos mas información podemos usar la opción -l, que te lista los archivos y directorios con mucha más información (que veremos en una futura entrada) del directorio en el cual ejecutamos el comando.
Si queremos listar los archivos y directorios, debemos indicárselo al comando ls, eso es lo que hacemos en las dos últimas ejecuciones, indicándole que liste el directorio padre de donde estoy actualmente (se indica con los dos puntos ..) por lo que lista el directorio del usuario alumno, y que liste el directorio ejemplo (que solo tiene una carpeta llamada uclm).

En ambos casos le agrego la opción -l para que liste los detalles de cada directorio o archivo que encuentre.

Pero ¿cómo puedo saber qué opciones y argumentos acepta un comando?, bueno, hay generalmente dos formas de ver qué opciones y argumentos contempla un comando (aparte de buscarlo en google) sin salir de dentro del terminal.

  1. Las opciones de ayuda del propio comando (los mas habituales –help o -h)
  2. Usar el comando de ayuda en linea man. El comando man toma como argumento de entrada cualquier comando y te muestra la ayuda si está disponible en el computador

Instalación del simulador NS3

Instrucciones actualizadas a la versión 3.36 (mayo 2022)

La forma mas simple de instalación del simulador NS3 pasa por bajarse el paquete completo de la web de versiones del simulador y descomprimirla en el directorio de trabajo. El tutorial de instalación completo puede consultarse en la wiki de instalación. En mi sistema Debian Buster, tras bajarme el archivo ns-allinone-3.36.tar.bz2 se descomprime:

$ tar -xf ns-allinone-3.36.tar.bz2
$ ls
ns-allinone-3.36 ns-allinone-3.36.tar.bz2
$ cd ns-allinone-3.36/
ns-allinone-3.36$ ls
bake build.py constants.py netanim-3.108 ns-3.36 pybindgen-0.22.1 README util.py

Atendiendo al sistema operativo donde estés trabajando, necesitas instalar una serie de dependencias y librerías que ns3 utiliza para los diferentes módulos. Hay dependencias que no necesitas instalar si el módulo que depende de esas librerías no lo vas a emplear. Si estás empezando, instala todas las dependencias que se indican en el wiki de instalación para tu sistema operativo. También te indican para qué sirve cada dependencia, mi recomendación es que, como ya he dicho, si estás empezando, las instales todas. En mi caso, las dependencias para Debian Buster vienen especificadas en su sección correspondiente usando la herramienta apt-get.
Una vez instaladas las dependencias existen varias alternativas para la instalación. Nosotros vamos a utilizar el script ns3, dentro del directorio ns-3.36. Este script tiene una funcionalidad parecida al antiguo sistema de compilación y configuración waf. Ese sistema, a partir de la versión 3.36 ha sido cambiado por Cmake. En el directorio donde hemos descomprimido el archivo ns-allinone-3.36.tar.bz2, , dentro de la carpeta ns-3.36, encontramos el archivo ns3. Lo ejecutamos para compilar el simulador:

./ns3 configure --enable-test --enable-examples

Se configura el simulador y al final te informa de qué módulos se compilarán. Las opciones habilitan los test y los ejemplos respectivamente, una opción que, si estás empezando, te servirán de guía en tus simulaciones. En mi caso, la información final es:

Modules configured to be built:
antenna aodv applications
bridge buildings config-store
core csma csma-layout
dsdv dsr energy
fd-net-device flow-monitor internet
internet-apps lr-wpan lte
mesh mobility netanim
network nix-vector-routing olsr
point-to-point point-to-point-layout propagation
sixlowpan spectrum stats
tap-bridge test topology-read
traffic-control uan virtual-net-device
wave wifi wimax

Modules that cannot be built:
brite click mpi
openflow visualizer

-- Configuring done
-- Generating done



Si algún módulo te interesa y no está en la lista, analiza la salida del comando por que posiblemente, el script ns3 no haya encontrado algo que necesita para compilar ese módulo o no lo tiene habilitado por defecto. Mas adelante veremos las opciones para habilitar distintos módulos.
Para compilar el simulador:

./ns3 build

Si todo ha ido bien, de nuevo, debería informarse de los módulos compilados:



Como último paso, comprobamos que todos los test pasan satisfactoriamente:

ns-allinone-3.36$cd ns-3.36
ns-allinone-3.36/ns-3.36$./test.py
..
..
657 of 660 tests passed (657 passed, 3 skipped, 0 failed, 0 crashed, 0 valgrind errors)
List of SKIPped tests:
ns3-tcp-cwnd (requires NSC)
ns3-tcp-interoperability (requires NSC)
nsc-tcp-loss (requires NSC)

y vemos que hemos pasado todos los test excepto tres relacionados con tcp que requieren de Network Simulation Cradle (NSC). Deberemos habilitar esa dependencia (y compilar todo) para pasar esos test.

De esta forma, ya tendríamos el simulador listo para trabajar y poder empezar a simular nuestros escenarios.

El sistema de log de NS3

Un buen entorno de logging te permite depurar y entender qué está pasando en tu simulación, así como entender cómo está estructurado el simulador NS3 y sus diferentes módulos.
El sistema de logging de NS3 se usa mediante variables de entorno y mediante el propio código de tu simulación si quieres habilitar logging en tu propia simulación.

Se establecen siete niveles de log proporcionando de menos a mas información:

  1. NS_LOG_ERROR: mensajes de error
  2. NS_LOG_WARN: mensajes de aviso
  3. NS_LOG_DEBUG: mensajes específicos de depuración
  4. NS_LOG_INFO: mensajes de información genéricos
  5. NS_LOG_FUNCTION: mensajes de llamadas a funciones para la trazabilidad de llamadas
  6. NS_LOG_LOGIC: mensajes de log con el flujo lógico dentro de cada función
  7. NS_LOGIC_ALL: todos los mensajes

Adicionalmente hay un nivel incondicional que imprime la salida con independencia de los niveles de log activos o no. Este es NS_LOG_UNCOND
¿Cómo visualizamos la información de log en ns3?, bien, vamos a comenzar con nuestro ejemplo IoT básico donde, precisamente, uno de los problemas es que no generábamos ningún tipo de información acerca de la simulación.
Efectivamente si lo ejecutamos, habiendo colocado previamente el archivo basic-iot-sensors.cc en el directorio scratch:

$./waf --run basic-iot-sensors
Waf: Entering directory `/ns-allinone-3.30.1/ns-3.30.1/build'
Waf: Leaving directory `/ns-allinone-3.30.1/ns-3.30.1/build'
Build commands will be stored in build/compile_commands.json
'build' finished successfully (2.047s)

Vemos que no sale ningún tipo de información útil acerca de la simulación salvo que se ha compilado y ejecutado sin errores.
Vamos a estudiar la información que nos genera el módulo de YansWifiPhy, para ello:

$ export NS_LOG=YansWifiPhy
felix@homer:~/tools/ns-allinone-3.30.1/ns-3.30.1$ ./waf --run basic-iot-sensors
Waf: Entering directory `/ns-allinone-3.30.1/ns-3.30.1/build'
Waf: Leaving directory `//ns-allinone-3.30.1/ns-3.30.1/build'
Build commands will be stored in build/compile_commands.json
'build' finished successfully (1.701s)
+0.000000000s -1 YansWifiPhy:YansWifiPhy(0x5641614960f0)
+0.000000000s -1 YansWifiPhy:SetChannel(0x5641614960f0, 0x564161490400)
+0.000000000s -1 YansWifiPhy:YansWifiPhy(0x56416153d640)
+0.000000000s -1 YansWifiPhy:SetChannel(0x56416153d640, 0x564161490400)
+0.000000000s -1 YansWifiPhy:YansWifiPhy(0x564161541e90)
...

vemos que usamos la variable de entorno NS_LOG para fijar el módulo en el que estamos interesados. Si ponemos NS_LOG a un nombre de un módulo que no existe se imprimirá un listado de todos los módulos que NS3 tiene implementados. El nivel de log por defecto en la mayoría de los módulos será todos, podemos especificarlo también a la hora de definir el módulo. Por ejemplo vamos a definir el nivel info para el módulo UdpClient:

$ export NS_LOG=UdpClient=level_info
$ ./waf --run basic-iot-sensors
Waf: Entering directory `/ns-allinone-3.30.1/ns-3.30.1/build'
Waf: Leaving directory `/ns-allinone-3.30.1/ns-3.30.1/build'
Build commands will be stored in build/compile_commands.json
'build' finished successfully (1.480s)
TraceDelay TX 32 bytes to 10.1.1.1 Uid: 0 Time: 2
TraceDelay TX 32 bytes to 10.1.1.1 Uid: 1 Time: 2
TraceDelay TX 32 bytes to 10.1.1.1 Uid: 2 Time: 2
TraceDelay TX 32 bytes to 10.1.1.1 Uid: 33 Time: 2.5
....

Vemos que ahora sale la información de las aplicaciones UDP instaladas en los nodos IoT enviando información. Substituye level_info por level_all en el primer comando para que veas como sale mucha más información.
Si algún módulo no se usa en tú simulación y pones NS_LOG a ese módulo no saldrá ninguna información adicional.
Si quieres indicar que el nombre de la función que genera el mensaje también se imprima, puedes hacer un OR con prefix_fund. En bash necesitarás comillas:

$export 'NS_LOG=UdpClient=level_all|prefix_func'

Para habilitar varios módulos, puedes encadenar usando : varios módulos.

$ export 'NS_LOG=UdpClient:UdpServer'

Vamos a crear un módulo para nuestra simulación y a sacar nuestro mensaje de log. Para ello, edita el archivo basic-iot-sensors.cc y añade estas dos líneas, por ejemplo, justo debajo de donde se inicia la función main:

int main (int argc, char *argv[]){
NS_LOG_COMPONENT_DEFINE ("IotEjemplo");
NS_LOG_INFO ("Creando la simulación");

Aunque ya estaba incluido en dicho archivo, si lo utilizas en tu simulación acuerdate incluir los archivos de cabezera de log («ns3/log.h»).
En la primera función definimos el módulo IotEjemplo y en la segunda sacamos nuestro primer mensaje. Si ahora queremos ver esa información:

$export 'NS_LOG=IotEjemplo'
$ ./waf --run basic-iot-sensors
Waf: Entering directory `/ns-allinone-3.30.1/ns-3.30.1/build'
[2876/2963] Compiling scratch/basic-iot-sensors.cc
[2921/2963] Linking build/scratch/basic-iot-sensors
Waf: Leaving directory `/ns-allinone-3.30.1/ns-3.30.1/build'
Build commands will be stored in build/compile_commands.json
'build' finished successfully (6.339s)
IotEjemplo:main(): [INFO ] Creando la simulación

Donde, como podemos ver, se muestra nuestro mensaje.

Es buena idea usar el mecanismo de log en cualquier simulación de ns3 pero se hace imprescindible si aspiras a crear un nuevo módulo para el simulador destinado a ser usado por la comunidad.