Shell scripting/es

From GRASS-Wiki
Jump to navigation Jump to search

¿Qué es esto?

Esta página contiene información acerca de cómo hacer un script para la línea de comandos (shell) para GRASS GIS.


La shell o intérprete de comandos para los sistemas operativos Unix o similares a Unix, es esencialmente un intérprete o procesador de comandos, es una interfaz basada en texto a través de la cual se pueden pasar instrucciones al sistema operativo de la computadora. Uno o más comandos pueden ser escritos en un script (normalmente en un archivo de texto) lo que, puede ser leido y ejecutado por la shell. La shell más usada probablemente es la bash.

El hacer un script (scripting) es el acto de diseñar, escribir, probar, eliminar bugs, y mantener una serie de comandos que realizan una función específica, ya sea sencilla o compleja.


<!Note, content below transfered here from the page GRASS and Shell.>

Haciendo un script para GRASS

Es bastante sencillo escribir un trabajo de GRASS como un script de Shell que lanza GRASS, hace la operación y limpia los archivos temporales.

Normalmente, es conveniente automatizar los trabajos repetitivos. GRASS puede ser controlado a través de scripts del usuario para facilitar el trabajo diario. ¿Cómo empezar?, el usar la línea de comandos de algún modo es como hacer scripts pero sin guardarlos - así que puedes escribir tu primer script guardando los comandos ejecutados en un archivo de texto (usa tu editor preferido, y de preferencia guarda el archivo en formato ASCII).

Nota importante: si no conoces sobre programación en la shell, y consideras aprenderlo, mejor echa un vistazo a Python (ej. GRASS and Python)...


Un primer script de shell de GRASS

Los comentarios deben empezar con el caracter '#'. La primer línea indica qué intérprete de shell se va a utilizar, aquí es "sh" , que está en el directorio /bi/.

Un ejemplo sencillo, a correr dentro de una sesión de GRASS:

#!/bin/sh
# mi primer script,
# copyright, año, Autor

# mostrar la configuración actual de la región
g.region -p

# salir con estatus 0 que significa "ok":
exit 0

Guarda este archivo como "myscript.sh" y correlo dentro de GRASS GIS desde la línea de comandos:

sh myscript.sh

Debe mostrar la configuración de la región actual, finalizar y regresar a la línea de comandos.


Para buscar errores en la shell (debugin), correr:

sh -x myscript.sh

Se mostrará cada línea lo cual ayuda a identificar errores.


Example 1 (simple): d.rast.region

Script para determinar la computational region/es a un mapa ráster ($1 es el parámetro para dar al script, aquí el nombre del mapa):

#!/bin/sh
# Autor: yo, hoy; copyright: GPL >= 2
# Propósito: script para determinar la región computacional a un mapa ráster
# Uso: d.rast.region rastermap

g.region rast=$1
d.erase
d.rast $1
exit 0

Usar la script en la localización "Nort Carolina" de GRASS 6:

d.mon x0
sh d.rast.region elev_state_500m
sh d.rast.region lsat7_2002_40

Ejemplo 2 (mejorado): d.rast.region

En este ejemplo, se asigna el primer parámetro ($1) dado al script (nombre del mapa) para una nueva variable que es más fácil para entender en el script. De nuevo, el script establece la región computacional a un mapa ráster, pero dice qué sucede:


#!/bin/sh
# Autor: yo, hoy; copyright: GPL >= 2
# Purprósito: script para establecer la región computacional a un mapa ráster
# Uso: d.rast.region rastermap

# ser cuidadoso de no dejar espacios en blanco en la siguiente línea:
map=$1
g.message message="Estableciendo la región computacional al mapa <$map>"
g.region rast=$map
d.erase
d.rast $map
exit 0

Usando el script en la localización "North Carolina": ver el ejemplo 1.

Ejemplo 3 (mejorado de nuevo): d.rast.region

Aquí se introduce la variable $0 que contiene el nombre del programa también como una prueba para mostrar el mapa especificado:

#!/bin/sh
# Autor: yo, hoy; copyright: GPL >= 2
# Propósito: script para definir la región computacional un mapa ráster
# Uso: d.rast.region rastermap

if [ $# -lt 1 ] ; then
   echo "Parámetro no definido. Uso"
   echo "   $0 rastermap"
   exit 1
fi

map=$1
g.message message="Definiendo la región computacional al mapa <$map>"
g.region rast=$map
d.erase
d.rast $map
exit 0


Para ver cómo funciona, es interesante usar el comprobador de errores de la shell (shell debugging):

d.mon x0
sh -x d.rast.region elev_state_500m

Ejemplo 4: manipulación de parámetros

Asume que quiere crear un script de shell para GRASS que tenga dos parámetro (coordenadas x y y) para calcular la cuenca relacionada con este punto de salida (r.water.outlet). En la shell, las variable $1 $2 y demás son parámetros que se pasan al script. Así, si se tiene un script llamado basin.sh y escribe


sh basin.sh -23.3 -47.7

La variable $1 será -23.3 y $2 será -47.6. En su script basin.sh puede usar la línea

r.water.outlet drainage="your_map" basin="basin_map" easting=$2 northing=$1

De la misma manera, se puede pasar un tercer parámetro para el nombre del mapa base, etc.

Sin embargo, es altamente recomendable usar g.parser para la manipulación de los parámetros. Es más fácil y se crea una interfaz gráfica de manera automática, incluso,¡los mensajes estándar aparecerán ya traducidos! Se puede clonar a partir de scripts ya existentes, vea aquí algunos ejemplo.


Usando la salida de los módulos de GRASS en el script

Algunas veces necesita usar la salida de un módulo para el siguiente paso en un script. La mayoría de los módulos de GRASS que producen una salida numérica ofrecen una bandera "-g" para facilitar el parseado de los resultados. Junto con la función "eval" de la shell se puede reducir el esfuerzo de usar la salida en el siguiente paso. El truco es que el signo de igual es considerado para asignar una variable en la shell:

  # Ejemplo en el conjunto de datos North Carolina
  inmap=elevation
  outmap=some_result

Ejemplo para salida nomrnal de módulo:

  g.region rast=$inmap
  r.info -r $inmap
  min=55.57879
  max=156.3299

Usando esto en un script:

  eval `r.info -r $inmap`
  r.mapcalc "$outmap = float($inmap) / $max"

Verificar:

  r.info -r $outmap
  min=0.355522472489405
  max=0.999999772928615

Mejores prácticas en la programación shell

Hay muchos libros sobre el tema, y el tema estará sujeto a preferencias personales, pero aquí hay algunos tips. Para parches enviados a GRASS, por favor siga las guías de código definidas en los archivos SUBMITTING en el directorio principal del código fuente.

  • trate de alcanzar 50% de comentarios, iniciando con el caracter # (ver arriba). De esta manera entenderá el script años después-
  • añada un comentario inicial de qué es lo que hace el script
  • estudie los scrips existentes, por ejemplo estos


Manejo de errores:

Un módulo que termina en un error fatal regresará un estatus no cero y salida (non-zero exit status), así que puede usar el comando con if, ||, &&, etc., o probar el valor de $?.

Insertando coordenadas en un módulo ráster a partir de un mapa vectorial de puntos

Algunos módulos ráster tienen la opción coordinates=, pero no tienen la opción para seleccionarlas a partir de un mapa vectorial de puntos. El siguiente ejemplo se refiere al módulo r.viewshed.

Primero, debe tener un mapa vectorial con las coordenadas en la tabla de atributos; si no es así, añádalas con v.db.addcolumn y v.to.db.

Ejemplo 1: r.viewshed - seleccionando un solo punto a partir de un mapa vectorial

#!/bin/bash
# Autor: Marco Curreli
# Uso: sh myviewshed.sh cat
# "cat" es la categoría del punto del mapa vectorial

VECT=myvector

ARG=1
E_ERR_ARG=65
if [ $# -ne "$ARG" ]
### Verifica el número de argumentos ###
then
  echo "Usage: $0 cat"
  exit $E_ERR_ARG
fi

# coordenadas del punto
COR=$(v.db.select -c map=$VECT columns=x,y separator=, where="cat = $1")

r.viewshed --verbose -c in=dtm out=visib_$1 coordinate=$COR obs_elev=2.75 memory=3000 stream_dir=tmp

Ejemplo 2: r.viewshed - procesamiento en bloque para seleccionar puntos de un mapa vectorial

#!/bin/bash
# Autor: Marco Curreli
# Uso: sh myviewshed_batch.sh cat1,cat2[,cat3,...] [cat3..catN]
# "cat" es la categoría del punto del mapa vectorial
# ejemplo: to selecting cats 1 3 5 6 7
# sh myviewshed_batch.sh 1,3 5..7

VECT=myvector

CAT1=$(
for index in $(eval echo {$1})
do
echo -n "$index "
done

echo
)

CAT2=$(
for index in $(eval echo {$2})
do
echo -n "$index "
done

echo
)

ARG=1
E_ERR_ARG=65
if [ $# -lt "$ARG" ]
then
  echo "Uso: $0 cat1,cat2[,cat3,...] [cat3..catN]
       se debe especificar al menos un argumento"
  exit $E_ERR_ARG
fi

# a trabajar con uno o dos argumentos
if [[ -n $2 ]]
then
CATS=$(echo $CAT1 $CAT2)
else
CATS=$(echo $CAT1)
fi

echo categories: $CATS

# lista de categorías con sus coordenadas
for i in $CATS
do
v.db.select -c map=$VECT columns=cat,x,y separator=,  where="cat = $i" >> ${VECT}_coord.csv
done

PTI=$(echo $(cat ${VECT}_coord.csv))


for p in $PTI
do
   set -- $p

#coordenadas
CORD=$( echo $p | gawk -F "," '{print $2","$3}')

#categoría
CAT=$( echo $p | gawk -F "," '{print $1}')

r.viewshed --verbose --overwrite in=dtm out=visib_$CAT coordinate=$CORD obs_elev=2.75 memory=1500 stream_dir=tmp

done

rm ${VECT}_coord.csv