在PerlShell和Python中传参与输出帮助文档

Posted 分析不凉

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在PerlShell和Python中传参与输出帮助文档相关的知识,希望对你有一定的参考价值。

基于本人对多种编程语言的粗浅了解,不论是哪种编程语言它的参数传递方式主要分为下面两类:

  • 直接传递(以Perl为例进行说明) 在调用脚本时,直接传递参数,如:./script.pl a b c,然后在脚本中用@ARGV变量获取这些参数

  • getopt方法 这种方法是大多数专业程序中都会用到的方法,使用的时候在参数名前加连接符,后面接上参数的实际赋值,例如:-a 1,不过getopt方法的参数解析方式略显复杂,下面会在具体的语言中进行逐一说明

直接传递的传参方式的优点是编写和使用起来很方便,但缺点很明显,参数的顺序是固定的,不能随意改变,每回使用时都需要确定各个参数分别是什么,而且一般采用这种传参方式的人是不会编写帮助文档的,所以一旦忘了只能查看源代码

getopt方法的优点是,传参方式灵活,而且采用这种传参方式的程序员一般都会在程序中添加帮助文档,因此这种传参方式对用户是非常友好的,但是对于程序员来说,则意味着他或她不得不多写好几行代码——所以一个好的程序员头顶凉凉是可以理解的~

以下我们只介绍第二种传参方法


Perl

Perl中getopt传参

Perl中的这个功能需要通过调用Getopt::Long模块实现,然后使用GetOptions函数承接传递的参数:

 
   
   
 
  1. use Getopt::Long;

  2. my ($var1,$var2,$var3,$var4); # 若使用"use strict"模式,则需要提前定义变量

  3. GetOptions(

  4. "i:s"=>\$var1,

  5. "o:s"=>\$var2,

  6. "n:i"=>\$var3,

  7. "m:i"=>\$var4

  8. );

这样,你就可以通过以下的方式进行灵活的Perl脚本参数传递了:

 
   
   
 
  1. perl perlscript.pl -i var1 -o var2 ...

Perl中输出帮助文档

可以使用POD文档实现在Perl中输出帮助文档:

 
   
   
 
  1. =head1 part1

  2. doc in part1

  3. =head2 part2

  4. doc in part2

  5. .

  6. .

  7. .

  8. =cut # pod文档结束的标志

注意:每个=标签上下必须隔一行,否则就会错误解析。

pod2doc $0可以将程序中的文档打印出来,不过一般用在程序内部,当程序参数设定错误时打印pod文档:

 
   
   
 
  1. die `pod2doc $0` if (...);

实现实例

 
   
   
 
  1. #!/usr/bin/perl

  2. use strict;

  3. use warnings;

  4. use Getopt::Long;

  5. use POSIX;

  6. # 帮助文档

  7. =head1 Description

  8. This script is used to split fasta file, which is too large with thosands of sequence

  9. =head1 Usage

  10. $0 -i <input> -o <output_dir> [-n <seq_num_per_file>] [-m <output_file_num>]

  11. =head1 Parameters

  12. -i [str] Input raw fasta file

  13. -o [str] Output file to which directory

  14. -n [int] Sequence number per file, alternate chose paramerter "-n" or "-m", if set "-n" and "-m" at the same time, only take "-n" parameter

  15. -m [int] Output file number (default:100)

  16. =cut

  17. my ($input,$output_dir,$seq_num,$file_num);

  18. GetOptions(

  19. "i:s"=>\$input,

  20. "o:s"=>\$output_dir,

  21. "n:i"=>\$seq_num,

  22. "m:i"=>\$file_num

  23. );

  24. die `pod2text $0` if ((!$input) or (!$output_dir));

  25. .

  26. .

  27. .


Shell

Shell中的getopt传参

Shell中的这个功能可以通过getopts函数实现

 
   
   
 
  1. getopts [option[:]] [DESCPRITION] VARIABLE

option:表示为某个脚本可以使用的选项

":":如果某个选项(option)后面出现了冒号(”:”),则表示这个选项后面可以接参数(即一段描述信息DESCPRITION)

VARIABLE:表示将某个选项保存在变量VARIABLE中

 
   
   
 
  1. while getopts ":a:b:c:" opt

  2. do

  3. case $opt in

  4. a)

  5. echo "参数a的值$OPTARG"

  6. ;;

  7. b)

  8. echo "参数b的值$OPTARG"

  9. ;;

  10. c)

  11. echo "参数c的值$OPTARG"

  12. ;;

  13. ?)

  14. echo "未知参数"

  15. exit 1;;

  16. esac

  17. done

Shell中输出帮助文档

在Shell中编辑一个helpdoc( )的函数即可实现输出帮助文档

 
   
   
 
  1. helpdoc(){

  2. cat <<EOF

  3. Description:

  4. .

  5. .

  6. .

  7. Usage:

  8. $0 -a <argv1> -b <argv2> -c <argv3> ...

  9. Option:

  10. .

  11. .

  12. .

  13. EOF

  14. }

之所以使用EOF来编写是因为,只是一种所见即所得的文本编辑形式(这个不好解释,请自行百度)

当你要打印帮助文档时,直接调用执行helpdoc( )函数即可

 
   
   
 
  1. # 当没有指定参数时,即参数个数为0时,输出帮助文档并退出程序执行

  2. if [ $# = 0 ]

  3. then

  4. helpdoc()

  5. exit 1

  6. fi

实现实例

 
   
   
 
  1. helpdoc(){

  2. cat <<EOF

  3. Description:

  4. This shellscript is used to run the pipeline to call snp using GATK4

  5. - Data merge: merge multi-BAM files coresponding to specified strain

  6. - Data pre-processing: Mark Duplicates + Base (Quality Score) Recalibration

  7. - Call variants per-sample

  8. - Filter Variants: hard-filtering

  9. Usage:

  10. $0 -S <strain name> -R <bwa index> -k <known-site> -i <intervals list>

  11. Option:

  12. -S strain name, if exist character "/", place "/" with "_" (Required)

  13. -R the path of bwa index (Required)

  14. -k known-sites variants VCF file

  15. -i intervals list file,must be sorted (Required)

  16. EOF

  17. }

  18. workdir="/work_dir"

  19. # 若无指定任何参数则输出帮助文档

  20. if [ $# = 0 ]

  21. then

  22. helpdoc

  23. exit 1

  24. fi

  25. while getopts "hS:k:R:i:" opt

  26. do

  27. case $opt in

  28. h)

  29. helpdoc

  30. exit 0

  31. ;;

  32. S)

  33. strain=$OPTARG

  34. # 检测输入的strain名是否合格:是否含有非法字符"/"

  35. if [[ $strain =~ "/" ]]

  36. then

  37. echo "Error in specifing strain name, if exist character \"/\", place \"/\" with \"_\""

  38. helpdoc

  39. exit 1

  40. fi

  41. if [ ! -d $workdir/SAM/$strain ]

  42. then

  43. echo "There is no such folder coresponding to $strain"

  44. helpdoc

  45. exit 1

  46. fi

  47. ;;

  48. R)

  49. index=$OPTARG

  50. ;;

  51. k)

  52. vcf=$OPTARG

  53. if [ ! -f $vcf ]

  54. then

  55. echo "No such file: $vcf"

  56. helpdoc

  57. exit 1

  58. fi

  59. ;;

  60. i)

  61. intervals=$OPTARG

  62. if [ ! -f $bed ]

  63. then

  64. echo "No such file: $intervals"

  65. helpdoc

  66. exit 1

  67. fi

  68. ;;

  69. ?)

  70. echo "Unknown option: $opt"

  71. helpdoc

  72. exit 1

  73. ;;

  74. esac

  75. done

  76. .

  77. .

  78. .


Python

Python中的getopt传参

Python中的这种功能需要通过getopt模块实现

 
   
   
 
  1. import getopt

Python脚本获得成对的参数名和参数值后,会分别把它们保存在一个字典变量中,参数名为key,参数值为value

 
   
   
 
  1. opts,args = getopt.getopt(argv,"hi:o:t:n:",["ifile=","ofile=","time="])

getopt函数的使用说明:

argv:使用argv过滤掉第一个参数(它是执行脚本的名字,不应算作参数的一部分)

"hi:o:t:n:":使用短格式分析串,当一个选项只是表示开关状态时,即后面不带附加参数时,在分析串中写入选项字符。当选项后面是带一个附加参数时,在分析串中写入选项字符同时后面加一个”:” 号

["ifile=","ofile=","time="]:使用长格式分析串列表,长格式串也可以有开关状态,即后面不跟”=” 号。如果跟一个等号则表示后面还应有一个参数

然后通过条件判断的方法对参数进行解析:

 
   
   
 
  1. for opt,arg in opts:

  2. if opt in ("-h","--help"):

  3. print(helpdoc)

  4. sys.exit()

  5. elif opt in ("-i","--ifile"):

  6. infile = arg

  7. elif opt in ("-t","--time"):

  8. sleep_time = int(arg)

  9. .

  10. .

  11. .

Python中的argparse传参

该示例例来自黄树嘉大佬的github项目 cmdbtools

 
   
   
 
  1. import argparse # 导入命令行解析的库文件

  2. # 为了别人执行代码的时候用--help看出来怎么使用这些代码

  3. argparser = argparse.ArgumentParser(description='Manage authentication for CMDB API and do querying from command line.')

  4. # 添加子命令

  5. commands = argparser.add_subparsers(dest='command', title='Commands')

  6. # 分别定义各个子命令,并未各个子命令设置参数

  7. # 1. 定义子命令login

  8. login_command = commands.add_parser('login', help='Authorize access to CMDB API.')

  9. login_command.add_argument('-k', '--token', type=str, required=True, dest='token',help='CMDB API access key(Token).') # 给子命令添加'-k'参数

  10. # 2. 定义子命令logout

  11. logout_command = commands.add_parser('logout', help='Logout CMDB.')

  12. # 3. 定义子命令token

  13. token_command = commands.add_parser('print-access-token', help='Display access token for CMDB API.')

  14. # 4. 定义子命令annotate

  15. annotate_command = commands.add_parser('annotate', help='Annotate input VCF.',

  16. description='Input VCF file. Multi-allelic variant records in input VCF must be split into multiple bi-allelic variant records.')

  17. annotate_command.add_argument('-i', '--vcffile', metavar='VCF_FILE', type=str, required=True, dest='in_vcffile',help='input VCF file.')

  18. # 5. 定义子命令query_variant

  19. query_variant_command = commands.add_parser('query-variant',

  20. help='Query variant by variant identifier or by chromosome name and chromosomal position.',

  21. description='Query variant by identifier chromosome name and chromosomal position.')

  22. query_variant_command.add_argument('-c', '--chromosome', metavar='name', type=str, dest='chromosome',help='Chromosome name.', default=None)

  23. query_variant_command.add_argument('-p', '--position', metavar='genome-position', type=int, dest='position',help='Genome position.', default=None)

  24. query_variant_command.add_argument('-l', '--positions', metavar='File-contain-a-list-of-genome-positions',

  25. type=str, dest='positions',

  26. help='Genome positions list in a file. One for each line. You can input single '

  27. 'position by -c and -p or using -l for multiple poisitions in a single file, '

  28. 'could be .gz file',

  29. default=None)

  30. argparser.parse_args()

输出的主命令的帮助文档如下:

 
   
   
 
  1. $ cmdbtools --help

  2. usage: cmdbtools [-h]

  3. {login,logout,print-access-token,annotate,query-variant} ...

  4. Manage authentication for CMDB API and do querying from command line.

  5. optional arguments:

  6. -h, --help show this help message and exit

  7. Commands:

  8. {login,logout,print-access-token,annotate,query-variant}

  9. login Authorize access to CMDB API.

  10. logout Logout CMDB.

  11. print-access-token Display access token for CMDB API.

  12. annotate Annotate input VCF.

  13. query-variant Query variant by variant identifier or by chromosome

  14. name and chromosomal position.

下面换一种思路来学习argparse:给出要实现的帮助文档,如何通过编写代码实现

帮助文档以上面的为例,将帮助文档的内容分成了三个在实现过程中相对独立的部分

1.脚本基本语法和描述信息

在创建好argparse对象之后,就设定好了这一部分的信息

 
   
   
 
  1. argparser = argparse.AugumentParser(description='Manage authentication for CMDB API and do querying from command line.')

  2. .

  3. .

  4. .

  5. argparser.parse_args()

描述信息在description参数中添加

从脚本基本语法可以看出:

 
   
   
 
  1. usage: cmdbtools [-h]

  2. {login,logout,print-access-token,annotate,query-variant} ...

在主程序的parser下方还创建了附属的子parser,可以通过argparser.add_subparsers创建附属的子parsers对象(例子中将子parsers对象命名为commands):

 
   
   
 
  1. commands = argparser.add_subparsers(dest='command', title='Commands')

创建好子parsers对象之后,还需要创建其下所附属的具体的每一个子parser,使用command.add_parser:

 
   
   
 
  1. login_command = commands.add_parser('login', help='Authorize access to CMDB API.')

  2. logout_command = commands.add_parser('logout', help='Logout CMDB.')

  3. ...

2.默认的可选参数-h/--help

这个默认的可选参数不需要单独创建,在创建argparse对象后就会默认内置了

3.添加具体的参数

例如,子parser login下的帮助文档:

 
   
   
 
  1. usage: cmdbtools login [-h] -k TOKEN

  2. optional arguments:

  3. -h, --help show this help message and exit

  4. -k TOKEN, --token TOKEN

  5. CMDB API access key(Token).

则可以通过下面的代码添加对应的参数解析:

 
   
   
 
  1. login_command.add_argument('-k', '--token', type=str, required=true, dest='token', help='CMDB API access key(Token).')

Python中输出帮助文档

在Python中创建一个字符串变量helpdoc即可实现输出帮助文档

 
   
   
 
  1. helpdoc = '''

  2. Description

  3. ...

  4. Usage

  5. python pyscript.py -i/--ifile <input file> -o/--ofile <output file> -t/--time <int> ...

  6. Parameters

  7. -h/--help

  8. Print helpdoc

  9. -i/--ifile

  10. Input file, including only one column with sampleId

  11. -o/--ofile

  12. Output file, including two columns, the 1st column is sampleId, the 2nd column is attribute information

  13. -t/--time

  14. Time for interval (seconds, default 5s)

  15. ...

  16. '''

在需要时将这个变量打印出来即可:

 
   
   
 
  1. try:

  2. opts,args = getopt.getopt(argv,"hi:o:t:n:",["ifile=","ofile=","time="])

  3. if len(opts) == 0:

  4. print("Options Error!\n\n"+helpdoc)

  5. sys.exit(2)

  6. except getopt.GetoptError:

  7. print("Options Error!\n\n"+helpdoc)

  8. sys.exit(2)

实现实例

 
   
   
 
  1. import getopt

  2. .

  3. .

  4. .

  5. if __name__ == '__main__':

  6. ...

  7. helpdoc = '''

  8. Description

  9. This script is used to grab SRA sample attributes information based on SampleId

  10. Usage

  11. python webspider_ncbiBiosample.py -i/--ifile <input file> -o/--ofile <output file> -t/--time <int> -n/--requests-number <int>

  12. Parameters

  13. -h/--help

  14. Print helpdoc

  15. -i/--ifile

  16. Input file, including only one column with sampleId

  17. -o/--ofile

  18. Output file, including two columns, the 1st column is sampleId, the 2nd column is attribute information

  19. -t/--time

  20. Time for interval (seconds, default 5s)

  21. -n/--requests-number

  22. Setting the requests number between interval (default 10)

  23. '''

  24. # 获取命令行参数

  25. try:

  26. opts,args = getopt.getopt(argv,"hi:o:t:n:",["ifile=","ofile=","time="])

  27. if len(opts) == 0:

  28. print("Options Error!\n\n"+helpdoc)

  29. sys.exit(2)

  30. except getopt.GetoptError:

  31. print("Options Error!\n\n"+helpdoc)

  32. sys.exit(2)

  33. # 设置参数

  34. for opt,arg in opts:

  35. if opt in ("-h","--help"):

  36. print(helpdoc)

  37. sys.exit()

  38. elif opt in ("-i","--ifile"):

  39. infile = arg

  40. elif opt in ("-o","--ofile"):

  41. outfile = arg

  42. # 若指定的输出文件已经存在,让用户决定覆盖该文件,还是直接退出程序

  43. if os.path.exists(outfile):

  44. keyin = input("The output file you specified exists, rewrite it?([y]/n: ")

  45. if keyin in ("y","Y",""):

  46. os.remove(outfile)

  47. elif keyin in ("n","N"):

  48. print("The output file existed!\n")

  49. sys.exit(2)

  50. else:

  51. print("Input error!\n")

  52. sys.exit(2)

  53. elif opt in ("-t","--time"):

  54. sleep_time = int(arg)

  55. elif opt in ("-n","--requests-number"):

  56. requestNum = int(arg)

  57. .

  58. .

  59. .


以上是关于在PerlShell和Python中传参与输出帮助文档的主要内容,如果未能解决你的问题,请参考以下文章

cmd向Python中传参传不进去

Linux下PerlShell脚本加密方法

cmd怎么往python中传参数

python 向sql语句中传参

php中传值与传引用的区别?

PHP中传值与传引用的区别 能举一个例子吗