sábado, septiembre 30, 2017

Mañana no se celebra un referéndum en Cataluña

Aunque se depositen papeles en unos contenedores y se pueda contar, lo que se va a intentar escenificar mañana en Cataluña es un golpe de estado orquestrado por unos separatistas xenófobos. Por los siguientes motivos:

  • Una serie de ciudadanos españoles que se creen que por el hecho de haber nacido en una parte de España llamada Cataluña los hace especiales.
  • Dejar sin derechos a la inmensa mayoría de los españoles, porque ellos creen que sólo los que votan a favor de ese referéndum tienen derechos políticos. Como muestra, las sesiones del Parlamento de Cataluña, del 6 y 7 de Septiembre, donde incluso se saltaron el propio Estatuto de Autonomía y toda la reglamentación de la cámara.
  • Desobedecer todas las leyes que no le convegan y los tribunales encargados de aplicarlas - ahora, bien que se amparan en dichas leyes y tribunales cuando les ha convenido -
  • Vender como democracia la simple votación, cuando si hay algo que tiene una democracia es el respeto a la ley y la protección de aquellos que piesan diferente. La prueba de que España es una democracia es que hasta permitos partidos que se quieren cargar esa misma democracia.
  • Usar la lengua catalana para levantar barreras entre personas: Para establecer quien es de aquí y quien es de fuera
  • Han robado los datos personales de los ciudadanos que viven en Cataluña, saltándose múltiples leyes de protección de datos que están, entre otras cosas, para limitar el abuso por las administraciones públicas. Han subido esos datos a diversos servidores fuera de España y que con un poco de mala suerte, puede dar lugar a una fuga de datos cuyas consecuencias podrían ser catastróficas para esos ciudadanos.
  • Llevan mintiendo sobre todo el proceso meses.
  • Las garantías de todo este golpe de estado son las que tienen cualquier suceso de este tipo: La arbitrariedad que deseen los que están al mando del mismo.

Esta lista se puede resumir perfectamente en una frase: saltarse la ley de infinidad de maneras con el objetivo de privar de derechos a una gran parte de la ciudadanía española.

Y faltaría por hablar, de lo que ha traído en el último siglo el nacionalismo en Europa: Desde las Guerras Mundiales al desastre de Yugolasvia

Por lo tanto mañana hablar de resultados, participación o datos es seguirles el juego a los golpistas. Lo único que se debe hablar es del cumplimiento de la ley. Y de la comparecencia ante los tribunales de aquellos que se la han saltado a la torera.

martes, septiembre 19, 2017

Tutorial de uso de funciones en Bash

Una de las funcionalidades que tiene la shell Bash es la posibilidad de usar funciones las cuales no son más que una agrupación de comandos con un nombre, que se ejecutará cuando se utilize dicho nombre para involcarlas. Esto permite construir librerías de funciones que realizen operaciones que interesan.

Definición de funciones

En Bash se pueden declarar funciones de varias maneras:

#!/bin/bash

function func1(){
    echo "Function 1"
}
func2(){
    echo "Function 2"
}
# Debe haber un espacio entre el nombre
# y la llave
function func3 {
    echo "Function 3"
}

La manera más portable - y la que recoge POSIX - es la segunda, definir el cuerpo de la función usando los paréntesis.

A la hora de definir los bloques de comandos que forman el cuerpo de la función se puede hacer usando las llaves { ... body ... } o los paréntesis (... body ...). La diferencia es que en el segundo caso la función se ejecutará en una subshell. Si se usa la versión 4 de bash se puede ver con en este ejemplo el comportamiento de cada manera definir la función: Si se hacen dos ejecuciones del mismo: La llamada a func1 siempre devolverá el mismo PID que corresponde con el del shell desde donde se está llamando, mientras que en el segundo caso variará, ya que el comando se ejecuta en otra subshell.

#!/bin/bash
function func1() {
    /bin/echo "FUNC1 $BASHPID"
}
function func2() (
    /bin/echo "FUNC2 $BASHPID"
)
func1
func2

La salida de ejecutar un script con ese contenido usando source es la siguiente:.

$ source script.sh
func 1 31238
func 2 31329
$ source script.sh 
func 1 31238
func 2 31338

Se ve como func1 tiene el mismo PID (el del shell desde donde se ejecuta el source), mientras que cambia el de la subshell. Recordar que pare que bash defina la variable $BASHPID debe ser la versión cuatro.

Alcance de variables

Una cosa particular de las funciones es que las variables que se definan en ellas, tienen alcance global por defecto del script que se está ejecutando, a menos que explicitamente se les añada el modificador local. Por ejemplo, el siguiente script la llamada a func1 asignará un valor a TEMPFUNCVAR1 que se verá tras la ejecución, cosa que no pasará con TEMPFUNCVAR2 de la segunfa función.

#!/bin/bash
func1() {
    echo "Func 1"
    FUNCVAR1="You can see me"
}
func2() {
    echo "Func 2"
    local FUNCVAR2="You can't see me"
}

func1
echo "FUNCVAR1=$FUNCVAR1"
func2
echo "FUNCVAR2=$FUNCVAR2"

Si se ejecuta el script anterior, se ve que la variable que ha sido declarada con local no muestra el contenido tras ejecutar la función:

$ script.sh
Func 1
FUNCVAR1=You can see me
Func 2
FUNCVAR2=

Parámetros de la función

Cuando se llama a una función con parámetros, estos pasan a ocupar los parámetros posicionales de la shell:

  • $* se expande a todos los parámetros posiciones ($1,$2,...), con la particularidad que sigue unas reglas de expansión si está entre dobles comillas.
  • $@ Exactamente igual que el anterior, pero los parámetros se expanden cada uno a una palabra distinta.
  • $# Es el número de parámetros de la función.
  • $1,$2,...$9 son los 9 primeros parámetros de la función. Si se necesitan más, estos se numera con ayuda de las llaves, es decir ${10}, ${11}, etc
  • .

El siguiente ejemplo de código coge todo los parámetros que se le pasa a la función, imprime el número de parámetros y luego cada parámetro en una línea distinta, con usando el comando interno shift para desplazar la lista de parámetros a la izquierda al irlos consumiendo.

#!/bin/bash
func1() {
    echo "Number of parameters: $#"
    while [ ! -z "$1" ]; do
        echo "$1"
        shift
    done
}
func1 You can see five parameters
func1 two parameters
func1

Al ejecutar el script anterior la salida es la siguiente:

$ ./script.sh
Number of parameters: 5
You
can
see
five
parameters
Number of parameters: 2
two
parameters
Number of parameters: 0

Si aprovechamos la expansión del parámetro $@ la anterior función tb se puede implementar de la siguiente manera. La ejecución de este script da el mismo resultado que el anterior:

#!/bin/bash
func1() {
    echo "Number of parameters: $#"
    for param in $@;do
        echo "$param"
    done
}
func1 You can see five parameters
func1 two parameters
func1

Valores de retorno de la función

El valor de retorno de la función se devuelve por defecto en la variable $?. Las reglas que definen el valor que tomará dicha variable a la salida de la función son las siguientes:

  • Si no existe ninguna llamada a return, el valor de retorno de la función será el valor del último comando que se ha ejecutado.
  • Si se usa return sin argumento numérico, ocurre igual que en caso anterior, el valor de retorno es el de último comando ejecutado.
  • Si se usa un valor numérico, ese es el valor de retorno de la función.

Hacer notar los siguientes dos puntos:

  • Por convención en Unix, los comandos suelen devolver un valor de cero en caso de que la ejecución del mismo haya tenido éxito.
  • El mecanismo de retorno de valores de ejecución de Bash nada más que permite valores numéricos. Para devolver cadenas, hay que usar otras construcciones.

Veamos un ejemplo de todo lo anterior

#!/bin/bash
RANDOM_NAME="/tmp/$(cat /dev/urandom | LC_ALL="C" tr -dc 'a-zA-Z0-9' | fold -w 16 | head -n 1)"
func1() {
    cp -f  "$RANDOM_NAME" "$RANDOM_NAME_1" 2> /dev/null
}
func2() {
    cp -f  "$RANDOM_NAME" "$RANDOM_NAME_1" 2> /dev/null
    return
}
func3() {
    return 10
}
func1
echo $?
func2
echo $?
func3
echo $?

El script anterior va a generar un nombre aleatorio y se definen tres funciones:

  • func1 va a realizar una operación que va a fallar, copiar un fichero que no existe. Como es el último comando que se ejecuta en la función, su valor de retorno será lo que devuelva la función a través de $?.
  • func2 Utiliza un return sin parámetros, en este caso el valor de retorno será el del comando anterior, que vuelve a ser el cp que falla y es lo que retorna.
  • func3 Por último, la función en este caso, retorna directamente el valor 10.

Resumen

Este es un tutorial muy básico sobre el uso de funciones en bash que permite empezar a usar las mismas en nuestros scripts. He dejado algunos puntos sin tocar, para los que tengáis curiosidad, se puede consultar el manual de bash y el enlace sobre shell scripting de la sección referencia. Para una próxima entrada me gustaría tratar de:

  • Como definir las funciones con una sola línea.
  • Como devolver cadenas desde una función.
  • Cuál es la mejor manera de agrupar funciones para usarlas como una librería.
  • Redirección de la salida de una función

Referencias

sábado, septiembre 16, 2017

Tutorial de arrays - vectores - en Bash

Bash es un shell - intérprete de órdenes de consola , interfaz clásica en modo texto - que fue desarrollado bajo el paraguas del proyecto GNU. Es compatible con Bourne Shell, la interfaz de comandos que traía la versión 7 de Unix. Además, tiene muchas mejoras y extensiones. Una de ellas es la posibilidad de usar arrays.

Un array puede declararse de cuatro maneras diferentes en Bash. La manera más sencilla es la siguiente, se muestra las órdenes y la salida de los echo:

$ my_array=("cadena 1" "cadena 2" "cadena 3")
$ echo ${my_array[@]}
cadena 1 cadena 2 cadena 3
$ echo ${!my_array[@]}
0 1 2
$ echo ${my_array[1]}
cadena 2
$ echo ${my_array[10]}

$ echo ${my_array} 
cadena 1
$ echo ${#my_array[@]}
3
$ declare -p my_array
declare -a my_array='([0]="cadena 1" [1]="cadena 2" [2]="cadena 3")'

Del ejemplo anterior se pueden ver los siguientes puntos sobre la sintaxis que usa Bash para gestionar los arrays:

  • La construcción ${nombreArray[@]} devuelve el array completo.
  • Para obtener la longitud del array se usa ${#nombreArray[@]}.
  • Se accede a cualquier elemento del array con ${nombreArray[indice]}, donde indice es un entero mayor o igual a cero. Si el elemento que se pide no existe, no se devuelve nada.
  • La construcción ${!nombreArray[@]} devuelve un array con los índices de cada elemento. Bash permite que el índice de cada elemento no sea correlativo ni tenga que empezar en 0.
  • Por último con ayuda de declare -p nombreArray pueden verse los atributos del array.

Otra manera de declarar una variable con un subíndice determinado, se crea autmáticamente un array. En el siguiente ejemplo creará un array llamado my_array donde el elemento número 11 tendrá el valor Número 11

$ my_array[10]="Número 11"
$ my_array[11]="Número 12"
$ echo ${my_array[@]}
Número 10 Número 11
$ echo ${!my_array[@]}
10 11
$ declare -p my_array
declare -a my_array='([10]="Número 10" [11]="Número 11")'

Otra manera de declarar un array es hacerlo explícitamente con declare y añadir elementos:

$ declare -a my_array
$ my_array[0]="Cero"

Un array puede ser borrado usando el comando unset nombreArray o unset nombreArray[@].

$ my_array=(1 2 3 4 5)
$ echo ${my_array[@]}
1 2 3 4 5
$ unset my_array
$ echo echo ${my_array[@]}} # Sólo salto de línea

$ my_array=(1 2 3 4 5)
$ echo ${my_array[@]}
1 2 3 4 5
$ unset my_array[@]
$ echo  ${my_array[@]} # Sólo salto de línea

Por último, hacere referencia a las dobles comillas. Como se ha visto a lo largo de los ejemplos anteriores, se usa ${nombreArray[@]} para referirse a todos los elementos del array. También se puede usar el asterisco (*) en vez del símbolo at (@): ${nombreArray[*]}. El comportamiento es el mismo execepto cuando se emplea dentro de comillas dobles. Si se usa el asterisco (*) , la expansión se realizará a una sóla palabra separada por el primer caracter del IFS - internal field separator. Mientras que si se usa el símbolo at (@), expande a varias palabras:

$ my_array=(1 2 3 4 5)
$ echo ${my_array[@]}
1 2 3 4 5
$ echo ${my_array[*]}
1 2 3 4 5
$ echo "${my_array[@]}"
1 2 3 4 5
$ echo "${my_array[*]}"
1 2 3 4 5
$ IFS=";"
$ echo "${my_array[@]}"
1 2 3 4 5
$ echo "${my_array[*]}" 
1;2;3;4;5

Un pequeño ejemplo de lo anterior es este shell script de ejemplo con todo lo anterior

#!/bin/bash
# Declarar el array
cities=("Menzoberrazan" "Waterdeep" "Neverwinter" "Baldur's Gate")

# Imprime cada elemento
for city in "${cities[@]}"; do
    echo "$city"
done
# Imprime los índices
for index in "${!cities[@]}"; do
    echo "$index ${cities[$index]}"
done
# Imprime el tamaño
echo "Longitud array: ${#cities[@]}"

Referencias

viernes, septiembre 15, 2017

BlueBorne: Vulnerabilidades en la pila bluetooth de varios sistemas

Bluetooth es un pila de protocolos de comunicaciones de corto alcance que utiliza ondas de radio como medio físico para transmitir información. Esta pila de protocolos está implementada en millones de dispositivos de todo tipo: teléfonos, ordenadores, sensores, tables, ... Esta semana se ha hecho público un conjunto de ataques contra la implementación bluetooth de diversos sistemas operativos que se agrupan bajo el nombre de BlueBorne. Los autores de esta investigación han sido Ben Seri y Gregory Vishnepolsky que trabaja para Armis

Lo más interesante de los ataques descritos es la posibilidad de realizarlos sin necesidad de tener pareados dos dispositivos bluetooth o de que éstos estén en modo de descubrimiento. De estos ataques, tres pueden considerarse críticos puesto que permiten la ejecución de código controlado por el atacante:

  • CVE-2017-1000251 Es un desbordamiento de pila (buffer overflow) clásico en la pila bluetooh the Linux, BlueZ, que permite ejecutar código de manera remota.
  • CVE-2017-0781 Este bug permite ejecutar código de manera remota en cualquier hardware que utilice Android como sistema operativo. Aunque Android deriva de Linux, usa una pila bluetooth propia desarrollada por Google.
  • CVE-2017-0782 Igual que el anterior, otro bug que permite la ejecución remota de código.

Aunque existen varias pruebas de concepto, dada la naturaleza de las vulnerabilidades más graves, sería posible programar un gusano que las aprovechara y que pudiese ir extendiendose de un dispositivo con conectividad bluetooth a otro. Además, el código de la pila se suele ejecutar con privilegios elevados, así que un ataque podría usarse para robar información. Y haciendo algo tan sencillo como poner un dispositivo malicioso en el rango de alcance de los dispositivos bluetooth que se quieran atacar.

Aunque los fallos han sido notificados a los diferentes fabricantes y mantenedores, existiendo parches para los sistemas, el problema vendrá de aquellos dispositivos para los cuales no se hacen actualizaciones o fabricantes que tardan mucho en sacarlas.

Referencias

jueves, septiembre 14, 2017

Cosas curiosas de Tesla

Hace unos días leía una curiosa noticia en Ars Tecnica: Tesla había aumentado el rango de ciertos vehículos de su modelo 60D de manera temporal y sin coste para que pudiesen salir de la zona del huracan Irma en el Estado de Florida. ¿Por qué?. Porque en realidad esos vehículos venían equipados con baterías de 75 kwh pero por software están capadas a 60 kwh. Previo pago de la correspondiente licencia (2000 dólares), Tesla te desbloquea esa capacidad. Es probable, que , una vez pasado el hurancán, una nueva actualización de software deje de nuevo las bataría cargar hasta los 60 Kwh.

Este es un modelo de negocio del que oí hablar por primera vez hace años en el mundo de los mainframes de IBM: El hardware que te ponía IBM era el mismo pero en función de lo que se pagara de licencia, se podía aprovechar a completo o solo una parte de él. Probablemente, veamos este modelo de negocio, tan común por otra parte en el mundo de la TI extenderse.

Pero quizás, lo que más me llama la atención es el grado de monitorización que puede tener Tesla sobre los coches que ha vendido. Por una parte, es bueno que llamen a casa para poder mandar información de diagnóstico sobre el estado general del coche y permita avisar a sus usuarios. Por otra parte, imaginad la cantidad de información que puede recoger Tesla de la conducción de sus coches. Una auténtica mina. Y desde mi punto de vista, al menos en EEUU, el tablero del coche es un lugar donde se puede mostrar publicidad. Y si hay algo que las grandes tecnológicas nos han enseñado estos últimos años, es que su auténtico valor añadido está en los datos que recoje y procesa. Se avecinan tiempos muy interesantes para temas de privacidad.

miércoles, septiembre 13, 2017

Robo de datos en Equifax

Equifax es una empresa americana que recaba información sobre los hábitos de pagos de deudas y facturas de individuos, elaborando un perfil que permite conocer el comportamiento crediticio de los mismos, lo que en EEUU se llama credit score - calificación crediticia -. Las entidades que prestan dinero utilizan esta calificación para saber la probabilidad que tiene una persona de pagar sus deudas y, por tanto, para saber si le conceden un crédito.

Estados Unidos es un país donde las redes de seguridad que tiene el Estado para sus ciudadanos no se encuentran tan desarrolladas como en Europa. Esto hace, según algunos economistas, como Raghuram Rajan, el crédito en Estados Unidos viene a jugar el papel de parte del Estado de Bienestar europeo. Estas calificaciones de crédito algo básico en el sistema financierop americano, dada la importancia que tiene el crédito.

La semana pasada se publíco la noticia que Equifax había sufrido un robo de datos que afecta a unos 143 millones de ciudanos americanos. Entre los datos que robaron de la compañía están números de la seguridad social, fechas de nacimiento, nombres de las personas, direcciones e incluso números de permisos de conducir, información que es extremadamente sensible en un sistema como el americano.

El uso de estos datos por parte de criminales de todo tipo puede dar lugar a fraudes o suplantación de identidades, siendo esto último lo más grave, ya que estos datos pueden usarse para obtener receta médicas, abrir cuentas corrientes, usar los números del carnet de conducir para saltarse las normas de tráfico y cargar a otro las multas, etc.

¿Y dónde se ha producido el fallo de seguridad?. Parece ser que uno de los servicios web de Equifax usaba Apache Struts, un framework usado para crear aplicaciones web usando java. Parece ser que el ataque se realizó el pasado mes de julio aprovechando un problema de seguridad desconocido por los desarrolladors - zero day -. Este software es usado en multitud de productos, lo cual ha obligado a diversos fabricantes de software a repasar sus programas. Por ejemplo Cisco ha publicado un boletín de seguridad de los productos afectados por este fallo. Los desarrolladores de Struts han publicado una carta hablando del este robo de datos.

Por otra parte si es posible hacer software más seguro contra fallos. Se ve todos los días funcionando programas en sistemas de misión crítica como aviónica o sistemas que tienen que estar certificados por diversar autoridades para poder usarse en el entorno crítico para el cual han sido diseñados. Ahora, se puede imaginar el dinero y tiempo que costaría hacer un simple servidor web siguiendo los criterios que se utilizan en otras industrias y teniendo en cuenta que el mundo de internet, muchas veces no importa llegar con un producto completo y pulido, sino con un producto que de una funcionalidad atractiva al usuario y poder alcanzar la suficiente masa crítica que permita a la empresa sobrevivir: La seguridad, muchas veces, puede pasar a un segundo plano, a pesar que cada vez hay más normativa que obliga a cumplir una serie de estándares.

El caso de Equifax con Apache Strut tiene otro punto de vista que hay que estudiar: Cuando en un producto se integra software de terceros, siempre hay que estar atentos al desarrollo y mantenimiento del mismo, especialmente en todo lo relacionado con la seguridad y si ese software manipulará directamente contenido que llegue de los usuarios, que por definición, no se puede confiar en él. Han existido multitud de problemas en programas que usaban librerías desactualizas o mal mantenidas.

lunes, septiembre 11, 2017

Publicar en Instagram desde cualquier navegador

Si accedes a Instagram desde un PC normal con cualquier navegador, no se pueden subir fotografías. La única manera que Instagram permite subir contenido desde un PC es similar que se está usando un navegador móvil, ya que hace un tiempo se incluyó esa funcionalidad.

¿Y cómo se hace eso?. Pues es bastante sencillo, puesto que la mayoría de los navegadores permiten el cambio del User-agent que envían en las peticiones HTTP.Hay que decirle al navagador que mande un User-Agent que se corresponda con un navegador móvil.

Por ejemplo, para el caso de Safari en Mac, es necesario activar el menú de desarrollador. Se despliega el menú de Desarrollo y se pulsa en agente de usuario, despegando el menú. Si se selecciona cualquiera de las versiones que se ejecutan bajo iOS, se podrá acceder a la funcionalidad de subir fotografías desde el ordenador. Hay que tener en cuenta que esta configuración es por pestaña. A continuación, una captura de pantalla donde se ve como configurar el User-Agent en Safari.

Aunque se puede cambiar de manera manual, en el caso de Firefox, lo mejor es usar algún tipo de extensión que se encargue de la gestión del mismo, ya que si no, es necesario tocar la configuracion en about:config. Por ejemplo, User Agent Switcher, pero es necesario configurarlo con un UserAgent más moderno.

En el caso de Google Chrome es relativamente sencillo hacerlo, aunque es más invasivo que en caso de Safari. Para ello, se despliegan las herramientas de desarrollador (cmd + opt + i en Mac) y se activa el "device tool bar" con cmd + shift + m, o pulsando en el icono de las herramientas desarrolladores (el icono que está azul arriba a la izquierda, en la siguiente captura de pantalla)

viernes, septiembre 08, 2017

Linux en sistemas de armas: Destructores clase Zumwalt de la US Navy

Los barcos de la clase Zumwalt son destructores lanzamisiles con capacidades de ataque a tierra, lucha antisubmarina y antiaérea. Con caracterítiscas stealth y con multitud de sistemas automáticos integrados en TSCEI - Total Ship Computing Environment Infrastructure -, buscan ser más baratos de operar y con menos tripulación que barcos de tamaño y misiones similares. Sim embargo, dada las tecnologías implicadas, los costes de desarrollo se dispararon dejando la clase sólo una serie de tres barcos.

La particularidad es que el TSCEI está implementado en 16 contenedores fabricados por Raytheon llamados electronic modular enclosures usando componentes COTS. Estos contenedores protegen a la electrónica que va alojada en su interior de vibraciones, golpes e interferencias del exterior. La misión de estas granjas de servidores es controlar todo el barco: sensores, armamentos, motores, rumbo, gestión de daños, tuberías,... . Los servidores instalados en estos contenedores son en su mayoría blades de IBM ejecutando Redhat Linux.

Los diferentes módulos se comunicacan entre si usando protocolos IP, con adaptadores especiales llamados DAP - que también usa Linux - en aquellos equipos que no tengan conectividad IP nativa.

La presentación de datos se realiza en consolas que utilzan procesadores Intel y que ejecutan un sistema de virtualización - LynxSecure - encima del cual se ejecutan varias instancias de Linux.

Referencias

jueves, septiembre 07, 2017

Linux en sistemas de armas: SCOMBA de la Armada Española

SCOMBA (Sistema de COMbate de los Buques la Armada) es un sistema de combate desarrollado por Navantia para los buques de la Armada Española con la intención de ofrecer un sistema base común al que se le añaden módulos que hacen de interfaz con los diferentes sistemas del buque. Ofrece un hardware estándar y una capa de presentación común en todos los sistemas del buque, adaptándolo luego a las misiones del mismo.

Una de las decisiones en el desarrollo de sistema de combate fue usar componentes COTS, es decir, usar elementos que ya existen en el mercado sin necesidad de hacer desarrollos específicos para el sistema de misión que ate a un solo proveedor de hardware y cuya evolución suele ser más lentas. En este caso SCOMBA usa ordenadores x86 y como sistema operativo usa Redhat Linux encima del cual se ejecuta un middleware que permite aislar los servicios del sistema del resto de la plataforma.

Referencias

domingo, septiembre 03, 2017

Evitar la reutilización de procesos en MacOS X

A pesar de llevar más de diez años usando MacOS X, hay una cosa que no he descubierto hasta hace un par de días: Como ejecutar nuevos procesos de la misma aplicación. Si, cuando pulsas en el icono de la aplicación (por ejemplo, Terminal.app), si está ejecutándose, no crea una nueva, sino que reutilia la instancia anterior. Lo que no sabía es que con el comando open y las opciones -a y -n se lanza un proceso nuevo. Si además, queremos que este proceso no nos abra las ventanas viejas que pueda tener almacenadas, se usa -F.

Por ejemplo, si lanzamos desde el Dock una instancia de Safari y queremos querer otra nueva:

$ open -n -F -a "Safari.app"

Lo curioso es que esta sencilla orden me permite volver a usar los escritorios virtuales como lo hacía hace más de diez años en Linux usando fvwm, donde en cada uno de los escritorios ponía los procesos que me interesaban, especialmente xterm. En mi caso, lo que más me interesa es colocar en los escritorios ventanas del Terminal.app o del Safari.app. Pero claro, el sistema trata a todas las ventanas de un mismo proceso como una entidad única, con lo cual, si movía una venta a otro escritorio, me movía todas las del proceso. Sabiendo que con open puedo ejecutar nuevos procesos, mi problema queda solucionado y puedo volver a usar el sistema de escritorios virtuales como a mi me gusta.