En los últimos tiempos estoy vendiendo mi alma al diablo y he empezado a usar Python. Personalmente prefiero Perl, Python me parece un lenguaje más anárquico y desorganizado. Sin embargo, Python está de moda en Bioinformática y muchos de los módulos más actualizados se están escribiendo en este lenguaje.
Hoy voy a hablar del problema que me he encontrado para encontrar un módulo que procese las opciones de línea de comandos que normalmente introducimos en los scripts, por ej.: ./script.py -i archivo1 -o archivo2 Estas opciones suelen ser archivos de entrada, salida, o simplemente parámetros que cambian la ejecución del programa. También sirve para pedir ayuda sobre como usar el script: ./script.py -h
En Perl existe el módulo Getopt::Long para procesar dichos parámetros de línea de comando de una forma sencilla y robusta.
En Python el módulo equivalente es getopt. A continuación se muestra un ejemplo de uso. Sin embargo este módulo no contempla la posibilidad de procesar múltiples opciones para un mismo argumento, por ejemplo, varios archivos de entrada.
Para solucionar este problema de Python de procesar argumentos de línea de comandos con múltiples opciones he creado mi propio código, puesto que me parece fundamental para cualquier script bioinformático. En el siguiente ejemplo se pueden definir listas para guardar múltiples opciones para un único argumento (ej. varios archivos). El código es provisional y le faltarían muchas opciones que sí tiene el módulo getopt, sin embargo, ofrece una solución al problema y espero ir mejorándolo con el tiempo.
Hoy voy a hablar del problema que me he encontrado para encontrar un módulo que procese las opciones de línea de comandos que normalmente introducimos en los scripts, por ej.: ./script.py -i archivo1 -o archivo2 Estas opciones suelen ser archivos de entrada, salida, o simplemente parámetros que cambian la ejecución del programa. También sirve para pedir ayuda sobre como usar el script: ./script.py -h
En Perl existe el módulo Getopt::Long para procesar dichos parámetros de línea de comando de una forma sencilla y robusta.
En Python el módulo equivalente es getopt. A continuación se muestra un ejemplo de uso. Sin embargo este módulo no contempla la posibilidad de procesar múltiples opciones para un mismo argumento, por ejemplo, varios archivos de entrada.
#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
Script que usa el módulo 'getopt' para parsear los argumentos y opciones de línea de comandos
"""
import sys, re, os, copy
# Importar el módulo 'getopt'
import getopt
# Imprimir en pantalla el script y sus argumentos y opciones
print 'ARGV:', " ".join(sys.argv[0:]),"\n"
# Información de ayuda de uso del script
def help() :
"""Ayuda sobre opciones del script en línea de comandos"""
print "usage:",sys.argv[0], "[options]\n"
print " -h this message\n"
print " -i input file/s\n"
print " -o output file\n"
# Definir los argumentos obligatorios (:) y opcionales, en sus formas abreviada y completa
try:
options, args = getopt.getopt(sys.argv[1:], "hi:o:", ["help", "input", "output"])
except getopt.GetoptError as err:
# Imprimir ayuda y salir si hay algún error o argumento incorrecto
print str(err)
help()
sys.exit(2)
output = None
verbose = False
# Definir el tipo de las variables que guardarán las opciones
INP_input = ''
INP_output = ''
# Asignar las opciones a cada argumento
for _opt, _arg in options:
if _opt in ("-i", "--input"):
INP_input = _arg
elif _opt in ("-o", "--output"):
INP_output = _arg
elif _opt in ("-h", "--help"):
help()
sys.exit()
else:
assert False, "unhandled option"
# Imprimir en pantalla todo lo anotado
print "Script:",sys.argv[0],"\n"
print "Argumentos y opciones:\n",
for _opt,_arg in options :
print " -"+_opt+": "+_arg
Para solucionar este problema de Python de procesar argumentos de línea de comandos con múltiples opciones he creado mi propio código, puesto que me parece fundamental para cualquier script bioinformático. En el siguiente ejemplo se pueden definir listas para guardar múltiples opciones para un único argumento (ej. varios archivos). El código es provisional y le faltarían muchas opciones que sí tiene el módulo getopt, sin embargo, ofrece una solución al problema y espero ir mejorándolo con el tiempo.
#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
Script que parsea los argumentos y opciones de línea de comandos
permitiendo usar listas para guardar argumentos con múltiples opciones
"""
import sys, re, os, copy
from types import *
# Imprimir en pantalla el script y sus argumentos y opciones
print 'ARGV:', " ".join(sys.argv[0:]),"\n"
# Información de ayuda de uso del script
def help() :
"""Ayuda sobre opciones del script en línea de comandos"""
print "usage:",sys.argv[0], "[options]\n"
print " -h this message\n"
print " -i input file/s\n"
print " -o output file\n"
exit()
# Definir el tipo de las variables que guardarán las opciones
INP_input = []
INP_output = ''
# Asignar a cada argumento una de las anteriores variables
options = {'h': 'help', 'help': 'help', 'i': 'INP_input', 'input': 'INP_input', 'o': 'INP_output', 'output': 'INP_output'}
argv_var = str()
# Leer los argumentos y opciones
for _argv in sys.argv[1:] :
# Leer los argumentos que comienzan con guión
if re.match("^-", _argv) :
for _opt,_var in options.iteritems() :
if re.compile("^-%s$" % (_opt)).match(_argv) :
argv_var = copy.deepcopy(_var)
if type(vars()[argv_var]) is FunctionType :
vars()[argv_var]()
break
# Anotar las opciones de cada argumento
else :
if argv_var is not None :
if type(vars()[argv_var]) is ListType :
vars()[argv_var].append(_argv)
else:
vars()[argv_var] += _argv
# Imprimir en pantalla todo lo anotado
print "Script:",sys.argv[0],"\n"
print "Argumentos y opciones:\n",
for _opt,_var in options.iteritems() :
if vars()[_var] is not None and type(vars()[_var]) is not FunctionType:
#print _opt,pprint(type(vars()[_var]))
if type(vars()[_var]) is ListType:
print " -"+_opt+": "+str(", ".join(vars()[_var]))
else :
print " -"+_opt+": "+str(vars()[_var])
optparse es quizás mejor opción que getopt
ResponderEliminary cómo se procesan varias opciones de un mismo argumento con optparse??
ResponderEliminarpues no he probado nunca, pero diría que no se puede. Para qué casos quieres más de una opción, además de en el caso de los ficheros de entrada?
ResponderEliminarsi quieres especificar varios formatos de salida, varios organismos, varios algoritmos, varias librerías...
ResponderEliminarEntiendo que se puede dar la situación, aunque nunca he necesitado hacer eso en una sola ejecución. Suelo capearlo con varias ejecuciones
ResponderEliminarcmd opts1 > out1 2>&1 &
cmd opts2 > out2 2>&1 &
y así
En cualquier caso, siempre se puede pasar un argumento conteniendo varios
cmd "opt1;opt2;opt3"
y procesarlo con opt.split(";").
Por otro lado, para tu código, no sería más fácil utilizar optparse para lo que ya hace y añadir la funcionalidad que dices?