golang编程之获取命令行参数及环境变量

http://blog.chinaunix.net/uid-24774106-id-3990722.html


  我们写习惯了C代码,都知道了解析输入参数argc argv,获取环境变量env,常见的C语言main函数有:

  1.     int main(int argc,char* argv[],char** envp)
    我们首先给出C语言的获取命令行参数和环境变量的代码:  
  1. manu@manu-hacks:~/code/c/self/env$ cat env.

  2. #include<stdio.h>
  3. #include<stdlib.h>


  4. int main(int argc,char* argv[],char** envp)
  5. {
  6.     int i; 
  7.     printf("there are %d input param\n",argc);
  8.     printf("they are :\n");
  9.     for(= 0 ; i < argc ; i++)
  10.     {
  11.         printf("%s\n",argv[i]);
  12.     }
  13.     
  14.     printf("env LIST--------------------------------------\n");
  15.     char **= envp;
  16.     for(;*!= NULL;p++)
  17.     {
  18.         printf("%s\n",*p);
  19.     }
  20.     return 0;
  21. }
    golang自然也可以做到,获取命令行参数,获取环境变量。
  1. manu@manu-hacks:~/code/go/self$ godoc os Args
  2. PACKAGE DOCUMENTATION

  3. package os
  4.     import "os"



  5. VARIABLES

  6. var Args []string
  7.     Args hold the command-line arguments, starting with the program name.
    我们先写一个简单的获取命令行参数的go 程序:   
  1. manu@manu-hacks:~/code/go/self$ cat sum.go 
  2. package main
  3. import "fmt"
  4. import "os"
  5. import "strconv"


  6. func main() int{
  7.     arg_num := len(os.Args)
  8.     fmt.Printf("the num of input is %d\n",arg_num)

  9.     fmt.Printf("they are :\n")
  10.     for i := 0 ; i < arg_num ;i++{
  11.         fmt.Println(os.Args[i])
  12.     }

  13.     sum := 0
  14.     for i := 1 ; i < arg_num; i++{
  15.         curr,err := strconv.Atoi(os.Args[i]) 
  16.         if(err != nil){
  17.             fmt.Println("error happened ,exit")
  18.             return 1 
  19.         }
  20.         sum += curr
  21.     }

  22.     fmt.Printf("sum of Args is %d\n",sum)
  23.     return 0
  24. }
输出如下:
  1. manu@manu-hacks:~/code/go/self$ ./sum 1 2 4 
  2. the num of input is 4
  3. they are :
  4. ./sum
  5. 1
  6. 2
  7. 4
  8. sum of Args is 7
  9. manu@manu-hacks:~/code/go/self$ ./sum 1 2 4 f 5 
  10. the num of input is 6
  11. they are :
  12. ./sum
  13. 1
  14. 2
  15. 4
  16. f
  17. 5
  18. error happened ,exit
    另外一个方面是如何获取环境变量。对于C而言,直接就是 之际而言os中也有获取环境变量的函数:
  1. FUNCTIONS

  2. func Environ() []string
  3.     Environ returns a copy of strings representing the environment, in the
  4.     form "key=value".

  5. func Getenv(key string) string
  6.     Getenv retrieves the value of the environment variable named by the key.
  7.     It returns the value, which will be empty if the variable is not
  8.     present.
    有了这个,就简单了。写了个简单的例子:  
  1. manu@manu-hacks:~/code/go/self$ cat env.go 
  2. package main
  3. import "fmt"
  4. import "os"

  5. func main(){

  6.     environ := os.Environ()
  7.     for i := range environ {
  8.         fmt.Println(environ[i])
  9.     }
  10.     fmt.Println("------------------------------------------------------------\n")
  11.     logname := os.Getenv("LOGNAME")
  12.     fmt.Printf("logname is %s\n",logname)
  13. }
    输出如下:
  1. manu@manu-hacks:~/code/go/self$ go run env.go 
  2. SSH_AGENT_PID=2331
  3. GPG_AGENT_INFO=/tmp/keyring-5CkALe/gpg:0:1
  4. TERM=xterm
  5. SHELL=/bin/bash
  6. 。。。

  7. ------------------------------------------------------------

  8. logname is manu
参考文献
Package os


我们随便写一个日常使用的psql的命令行用法

  1. manu@manu-hacks:~$ pg_ctl -D /home/manu/DB_data/ -l /home/manu/DB_data/postgres_manu.log   start 
  2. server starting
    这种情况下我们更需要的是解析各个参数的意义,比如-D选项 是通知pg_ctl pgdata的路径在那,-l选项告知的是log记录到那个文件,start相当于子命令,告知action。对于这种命令,我们都知道C语言有getopt及其getopt_long来解决。go语言怎么解决?
    go语言提供了flag这个package。来应对这种入参的解析。
    flag支持的语言格式如下:
  •     -flag     // bool类型only
  •     -flag=x
  •     -flag x  //not bool 类型
    很自然,这个flag能够解析 -D /home/manu/DB_data,对应第二种类型,我们知道pg_ctl有-W选项,属于一个开关性质的bool型的选项
  1. -W do not wait until operation completes
自然对应第一种类型,也可以解析。第二种也很好理解。
    下面我给出一个例子,简单的解析这个pg_ctl的命令:
  1. manu@manu-hacks:~/code/go/self$ cat pg_ctl_parse.go 


  2. package main
  3. import (
  4.     "fmt"
  5.     "flag"
  6. )

  7. func main(){

  8.     data_path := flag.String("D","/home/manu/sample/","DB data path")
  9.     log_file := flag.String("l","/home/manu/sample.log","log file")
  10.     nowait_flag :=flag.Bool("W",false,"do not wait until operation completes")

  11.     flag.Parse()

  12.     var cmd string = flag.Arg(0);

  13.     fmt.Printf("action   : %s\n",cmd)
  14.     fmt.Printf("data path: %s\n",*data_path)
  15.     fmt.Printf("log file : %s\n",*log_file)
  16.     fmt.Printf("nowait     : %v\n",*nowait_flag)

  17.     fmt.Printf("-------------------------------------------------------\n")

  18.     fmt.Printf("there are %d non-flag input param\n",flag.NArg())
  19.     for i,param := range flag.Args(){
  20.         fmt.Printf("#%d    :%s\n",i,param)
  21.     }


  22. }
    OK,我们分析下代码( 分割线下面的我们暂时不看):
    第一行对应的是data_path的解析规则
    -D选项对应的值是字符串类型字符串,
    默认值是“/home/manu/sample”,
     DB data path提示信息或者help信息或者说明是。

  1. manu@manu-hacks:~/code/go/self$ go run pg_ctl_parse.go  -D /home/manu/DB_data/ -l /home/manu/DB_data/postgres_manu.log -W start
    action   : start
    data path: /home/manu/DB_data/
    log file : /home/manu/DB_data/postgres_manu.log
    nowait : true
    -------------------------------------------------------
    there are 1 non-flag input param
    #0 :start

    manu@manu-hacks:~/code/go/self$ go run pg_ctl_parse.go   -l=/home/manu/DB_data/postgres_manu.log -W -D /home/manu/DB_data/  start
    action   : start
    data path: /home/manu/DB_data/
    log file : /home/manu/DB_data/postgres_manu.log
    nowait : true
    -------------------------------------------------------
    there are 1 non-flag input param
    #0 :start

    我们看到了,解析出了data_path,log_file无论 -l -D出现的顺序如何,只要正常的出现了,就能正常的解析。
    但是晴朗的天空中也有一片乌云,start不是这种 -key=alue 或则-option的类型,flag是解析不了的。我们称这种参数为non-flag参数,flag解析遇到non-flag参数就停止了:
  1. := f.args[0]
  2. if len(s) == 0 || s[0] != '-' || len(s) == 1 {
  3.     return false, nil
  4. }
    所以如果我们将non-flag参数放在最前面,flag什么也不会解析,因为flag遇到了这个就停止解析了。
  1. manu@manu-hacks:~/code/go/self$ go run pg_ctl_parse.go  start -l=/home/manu/DB_data/postgres_manu.log -W -D /home/manu/DB_data/  
    action   : start
    data path: /home/manu/sample
    log file : /home/manu/sample.log
    nowait   : false
    -------------------------------------------------------
    there are 5 non-flag input param
    #0 :start
    #1 :-l=/home/manu/DB_data/postgres_manu.log
    #2 :-W
    #3 :-D
    #4 :/home/manu/DB_data/


    OK,flag提供了Arg(i),Args()来获取non-flag参数,NArg()来获取non-flag的个数。正如我们们sample 代码看到的。    
  1. fmt.Printf("there are %d non-flag input param\n",flag.NArg())
  2.     for i,param := range flag.Args(){
  3.         fmt.Printf("#%d :%s\n",i,param)
  4.     }
    flag还提供了NFlag()获取那些匹配上的参数的个数。
    从例子上看,flag package很有用,但是并没有强大到解析一切的程度。
    如果你有类似-option或者-key =value这种参数,不妨试试 flag。如果你的入参解析非常复杂,flag可能捉襟见肘。

参考文献:
标准库—命令行参数解析flag
Go 语言简介(下)— 特性

你可能感兴趣的:(大规模分布计算(云,搜索引擎))