Hom's Blog


读取命令行选项

  • 从命令行输入参数选项是我们基本的程序互动内容,是基本的功能.调用命令行参数是第一个技能,分析命令行参数是第二步.每种不同语言的程序或脚本都具有读取命令行参数的功能.

Python: sys.argv

sys库里的argv是所有命令行选项的列表.根据空格/tab来分隔来放置.第0个是脚本名字,1开始才是参数列表.所以参数个数是len(sys.argv)-1.第一个选项就是sys.argv[1]

python例子
#!/usr/bin/python
# Filename: cat.py
import sys
def readfile(filename):
    print '''Print a file to the standard output.'''
    f = file(filename)
    while True:
        line = f.readline()
        if len(line) == 0:
            break
        print line, # notice comma
    f.close()
# Script starts from here

# No argv given.
if len(sys.argv) < 2:
    print 'No action specified.'
    sys.exit()
# Analyse argv with --
if sys.argv[1].startswith('--'):
    option = sys.argv[1][2:]
    # fetch sys.argv[1] but without the first two characters
    if option == 'version':
        print 'Version 1.2'
    elif option == 'help':
        print '''/
This program prints files to the standard output.
Any number of files can be specified.
Options include:
  --version : Prints the version number
  --help    : Display this help'''
    else:
        print 'Unknown option.'
    sys.exit()
else:
    for filename in sys.argv[1:]:
        readfile(filename)

Shell

shell更为简单,就是调用变量$1 $2 $3这样子.

  • $0 脚本文件名
  • $n n为具体某个数字,指代对于参数.
  • $# 参数总个数.
  • $* 传递给脚本或函数的所有参数。
  • $@ 传递给脚本或函数的所有参数。被双引号包含时,"$*"表示所有参数作为一个整体,"$@"会表示逐个参数列出来,在for循环时很明显.
Shell例子:
#! /bin/bash

filename=$1
if [ -f ${filename} ];then
echo ${filename}
echo "变量文件名: ${1%.*}"
echo "变量文件所在目录: ${1%/*}"
echo "变量文件的后缀名: ${1##*.}"
fi

C++

主要利用main函数的参数main( int argc, char* argv[] ).前者指明参数个数,后者是参数数组.

CPP 参数分析器(对象化).
#ifndef OPTPARSER_H
#define OPTPARSER_H

#include <string>
#include <map>
#include <iostream>
using namespace std;

class Option//选项对象,每个选项对象包括简称,全称,是否必须,描述内容.
{
public:
    string _shortName;     // short name of option
    string _longName;      // long name of option
    string _argRequired;   // need an argument?是否需要参数的,0时只是指示器,:需要参数
    string _description;   // description of option
    string _value;         // value of option,具体命令行分析后储存递给接口信息
    bool _specified;       // whether specified in CmdLine,具体命令行分析后用来判断是否指明

public:
    Option( const char* shortName = NULL, const char* longName = NULL,
            const char* argRequired = NULL, const char* description = NULL )
    {
        _shortName = shortName ? shortName : "";
        _longName = longName ? longName : "";
        _argRequired = argRequired ? argRequired : "";
        _description = description ? description : "";
        _value = "";
        _specified = false;
    }
};

class OptParser//选项解释器对象,分析和储存程序的选项,并利用接口注册信息
{
public:
    OptParser( const int numOpt, const char* options[] );
    ~OptParser();
    bool ParseOpt( int ___argc, char* ___argv[] );//结合具体命令行参数分析.
    string GetOpt( const string& opt );//获取存入的命令行参数
	bool ExistOpt( const string& opt );//是否有这个参数
	void PrintUsage();//打印使用说明
	bool NoOptSpecified();//是否非指定性参数.
    void ShowOpts( bool all = false );

private://储存了程序内部的选项信息.
	int _numOpts; //num of options,多少个预存的选项.
	const char** _options; //options,程序预存的选项
    string _progname; //program name,所在程序名
    map<string, Option*> _optmap; //简称和选项对象,读取命令行参数后存入.
};

#endif

主文件:

#include "OptParser.h"
#include <sstream>
#include <iomanip>
#include <set>
using namespace std;

//// code for test
#ifdef OP_MAIN

int main( int argc, char* argv[] )
{
#ifdef _DEBUG
    argc = 6;
    argv[0] = "ccbgkit";
    argv[1] = "-i=a.mol2";
    argv[2] = "-ob.sdf";
    argv[3] = "-s";
    argv[4] = "3";
    argv[5] = "-hv";
#endif

    /* step 1.
      define all your options in a const char* array
      make sure to follow the format, one opt per line.
      ---------------------------------------------------------------------------
      "short_opt", "long_opt", "arg_required", "description",
      Note: 1. short_opt starts with -, eg. -i or -out
            2. long_opt starts with --, eg. --help or --version
            3. arg_required of ":" indicates that opt requires an argument
            4. description of opt
      ---------------------------------------------------------------------------
    */
    const char* options[] = {//注册你的选项
        "i", "in", ":", "Specify input file",
		"o", "out", ":","Specify output file",
		"s", "size", ":", "Block size",
		"v", "version", 0, "Print version information",
		"u", "usage", 0, "Print the usage",
        "h", "help", 0, "Print help topic",
		"m", "man", 0, "Print the complete man page",
    };

    /* step 2.
      Initialize OptParser with
      number of options and the array
    */
    OptParser op( 7, options );//注册你的解释器

    /* step 3.
      Parse the command line
       */
    op.ParseOpt( argc, argv );//对输入的命令行的解释

    /* step 4.
      Get the arg of an option
      return "OP::undefined" if opt was undefined in options[];
             "OP::unspecified" if opt was unspecified by user;
             otherwise the specified arg
    */
    string opt_in = op.GetOpt( "in" );//具体情况调用命令行的信息

    cout << "CmdLine: ";
    for ( int i = 0; i < argc; ++i ) {
        cout << argv[i] << " ";
    }
    cout << "\n";

    /*
      Show specified options
      op.ShowOpts( true ) will show all defined options
    */
    op.ShowOpts();

    /*
      Print (automatically build) formatted usage information
    */
    op.PrintUsage();

    //
    system( "pause" );
    exit( 0 );
}

#endif // OP_MAIN

// -------------------------------------------------------------------

OptParser::OptParser( const int numOpts, const char* options[] )
{
	//init
	_numOpts = numOpts;
	_options = options;//备份解析器内信息

    for ( int i = 0; i < numOpts; ++i ) {
        Option* opt = new Option( options[i*4 + 0], options[i*4 + 1],
                                  options[i*4 + 2], options[i*4 + 3] );//产生选项动态对象的指针
        if ( options[i*4 + 0] ) {
            _optmap.insert( make_pair( options[i*4 + 0], opt ) );
        }
        if ( options[i*4 + 1] ) {
            _optmap.insert( make_pair( options[i*4 + 1], opt ) );//注册简称和全称对应的选项对象指针的字典.
        }
    }
}

OptParser::~OptParser()
{
    map<string, Option*>::iterator i;//注册个字典的迭代器指针,删除注册信息
    set<Option*> cs;//储存选项?
    for ( i = _optmap.begin(); i != _optmap.end(); ++i ) {
        if ( i->second && cs.find( i->second ) == cs.end() ) {//存在选项.
            cs.insert( i->second );
            delete i->second;//删除释放内存,回归指针
            i->second = NULL;
        }
    }
    _optmap.clear();//清空选项器对象字典的内容
}

bool OptParser::ParseOpt( int ___argc, char* ___argv[] )//将具体命令行用来解释和注册选项器.
{
    if ( ___argc == 0 || ___argv == NULL || _optmap.empty() ) {//没输入或预存选项字典为空
        cerr << "Something must be wrong\n";
        return false;
    }

    // the program name
    _progname = ___argv[0];//注册选项器所在的程序

    int optidx = 0;//逐项分析命令行参数,参数索引.
    //定义个判断是否参数的宏变量,方便分析.在该索引的参数中, 第一个是不能是-;或 第二个是只有一个字符;或只有两字符而第二个是-
#define IS_ARG ( ___argv[optidx][0] != '-' \
              || ___argv[optidx][1] == '\0' \
              || ( ___argv[optidx][1] == '-' && ___argv[optidx][2] == '\0' ) )

    const char* p0( NULL );
    const char* p( NULL );
    string opt( "" ), val( "" );

    /* starts from 1, ARGV[0] is the program name */
    for ( optidx = 1; optidx < ___argc; ) {
        if ( IS_ARG ) {
        	//只有当输入 program input.in output.out 这样时调用以下内容
			// if ___argc is less than 4 or ___argv[1] and/or ___argv[2]
			// are value, make them as default parameters.
			// make ___argv[1] as input file and ___argv[2] as output file
			if ( optidx == 1 ) {
				// if argv[1] is a argument, make it as default input
				opt = "in";
				if ( _optmap.find( opt ) != _optmap.end() ) {
					_optmap[opt]->_specified = true;
					_optmap[opt]->_value = ___argv[optidx];
					++optidx;
				}
				else {
					cerr << "Croak: no opt can take the parameter '"
						 << ___argv[optidx] << "'\n";
					return false;
				}
				continue;
			}
			if ( optidx == 2 ) {
				// if argv[2] is also a argument, make it as default output
				opt = "out";
				if ( _optmap.find( opt ) != _optmap.end() ) {
					_optmap[opt]->_specified = true;
					_optmap[opt]->_value = ___argv[optidx];
					++optidx;
				}
				else {
					cerr << "Croak: no opt can take the parameter '"
						<< ___argv[optidx] << "'\n";
					return false;
				}
				continue;
			}
            // an argument, unexpected
            if ( opt != "" ) {
                cerr << "Croak: opt '" << opt
                     << "' takes too many arguments\n";
            }
            else {
                cerr << "Croak: no opt can take the parameter '"
                     << ___argv[optidx] << "'\n";
            }
            return false;
        }
        else {
            // an option
            p0 = ___argv[optidx] + 1 + ( ___argv[optidx][1] == '-' );//参数内容,根据-或--定义参数内容指针

            for ( p = p0; *p && *p != '='; ++p ) {//非结尾或=时,将p移到参数如--sin=hi的sin的=处
                /* do nothing */
            }

            opt.assign( p0, p - p0 );//sin选项名,p0起p-p0个字符

            /* Test all options for exact match match */
            if ( _optmap.find( opt ) != _optmap.end() ) {
                if ( *p ) {//到达的非结尾,只有=情况罗
                    // *p == '='
                    if ( _optmap[opt]->_argRequired == ":" ) {//是要赋值的选项
                        // ok, expects an arg
                        val.assign( p + 1 );//将选项的值放入val
                        //
                        _optmap[opt]->_specified = true;//已指定
                        _optmap[opt]->_value = val;//给该选项放置值.

                        // advance to next ARGV-element
                        optidx++;//完成读取一个选项,下一个选项继续.
                        continue;
                    }
                    else {//非赋值型选项给了值,如-s=hi,但-s只是只是选项
                        // error, opt expects no argument
                        cerr << "Croak: opt '" << opt
                             << "' expects no argument!\n";
                        return false;
                    }
                }
                else {//到达的是结尾,例如-s,--sin.而-oFile.out则因为没有该选项.
                    //
                    ++optidx;//读取下一选项,这才是值
                    if ( optidx >= ___argc ) {
                        // the last ARGV-element
                        if ( _optmap[opt]->_argRequired == "" ) {//非赋参选项.
                            // ok, expects no arg
                            _optmap[opt]->_specified = true;
                            return true;
                        }
                        else {
                            // error, expects an arg
                            cerr << "Croak: opt '" << opt
                                 << "' expects an argument!\n";
                            return false;
                        }
                    }

                    if ( IS_ARG ) {//如下一选项是一个参数值,例如-f file的file
                        if ( _optmap[opt]->_argRequired == ":" ) {
                            // ok, expects an arg
                            val.assign( ___argv[optidx] );//好,是一个值,给该参数赋值
                            //
                            _optmap[opt]->_specified = true;
                            _optmap[opt]->_value = val;
                            // advance to next ARGV-element
                            ++optidx;
                            continue;
                        }
                        else {
                            // error, expects no arg,不该赋值的赋值了报错
                            cerr << "Croak: opt '" << opt
                                 << "' expects no argument!\n";
                            return false;
                        }
                    }
                    else {//是不给参数型的选项
                        // an opt
                        if ( _optmap[opt]->_argRequired == "" ) {
                            // ok, expects no arg
                            _optmap[opt]->_specified = true;
                        }
                        else {
                            // error, expects an arg
                            cerr << "Croak: opt '" << opt
                                 << "' expects an argument!\n";
                            return false;
                        }
                    }
                }
            }
            /* otherwise interpret as bundled short opt */
            else {//找不到这个词作为参数,例如-oFile.out型参数,复合参数-sk或-K没有该参数.
                for ( p = p0; *p; ++p ) {//重新分析该选项
                    opt.assign( p, 1 );//-oFile的o
                    if ( _optmap.find( opt ) != _optmap.end() ) {
                        if ( _optmap[opt]->_argRequired == ":" ) {
                            // expects an argument, accept all the rest
                            val.assign( p + 1 );//-oFile.out将后面都当做值
                            //
                            _optmap[opt]->_specified = true;
                            _optmap[opt]->_value = val;
                            // break out
                            break;//跳出不再读了.
                        }
                        else {//-sk型的符合选项
                            _optmap[opt]->_specified = true;
                            continue;
                        }
                    }
                    else {//-sK没定义的K
                        // not defined
                        cerr
                     << "Croak: opt '"
                     << opt
                     << "' is not defined!\n";
                        return false;
                    }
                }

                // advance to next ARGV-element
                ++optidx;
                continue;
            }
        }
    }

    //
    return true;
}

string OptParser::GetOpt( const string& opt )
{
	if ( _optmap.find( opt ) != _optmap.end() ) {
		if ( _optmap[opt]->_specified ) {
			return _optmap[opt]->_value;
		}
		else {
			return "OP::unspecified";//未赋值,未提供
		}
	}
	else {
		return "OP::undefined";//未定义
	}
}

bool OptParser::ExistOpt( const string& opt ) {
	if ( _optmap.find( opt ) != _optmap.end() ) {//有定义时,赋值了或未
		return _optmap[opt]->_specified;
	}
	return false;//压根没定义
}

void OptParser::PrintUsage()
{
	map<string, Option*>::const_iterator i;
	string usage, shortopt, bundled;
	stringstream detail;

	// max short name size and long name size,为了输出时对齐...
	int maxSNSize = 0;
	int maxLNSize = 0;
	for ( i = _optmap.begin(); i != _optmap.end(); ++i ) {
		int snsize = (int)(i->second->_shortName).size();
		int lnsize = (int)(i->second->_longName).size();
		if ( snsize > maxSNSize ) {
			maxSNSize = snsize;
		}
		if ( lnsize > maxLNSize ) {
			maxLNSize = lnsize;
		}
	}

	usage += "  Usage: " + _progname;

	for ( int N = 0; N < _numOpts; ++N ) {
		for ( i = _optmap.begin(); i != _optmap.end(); ++i ) {
			if ( i->first == _options[N*4 + 0] &&
				 i->first == i->second->_shortName ) {
				if ( i->second->_argRequired != "" ) {
					usage += " [-" + i->first + " <:>]";
				}
				else if ( ( int ) i->first.size() > 1 ) {
					shortopt += " [-" + i->first + "]";
				}
				else {
					bundled += i->first;
				}
				detail << "    -" << left
					<< setw( maxSNSize + 1 ) << i->first
					<< left << setw( maxLNSize + 5 )
					<< ( i->second->_longName != ""
					? " --" + i->second->_longName
					: " " )
					<< left << i->second->_description << "\n";
				break;
			}
		}
	}

	cout << usage << shortopt << " [-" << bundled << "]" << "\n\n";
	cout << detail.str() << "\n";//将字符串流中变字符串并输出.
}

bool OptParser::NoOptSpecified() {
	map<string, Option*>::const_iterator i;
	for ( i = _optmap.begin(); i != _optmap.end(); ++i ) {
		if ( i->second->_specified ) {
			return false;
		}
	}
	return true;
}

void OptParser::ShowOpts( bool all )
{
    map<string, Option*>::const_iterator i;
    for ( i = _optmap.begin(); i != _optmap.end(); ++i ) {
        if ( i->first == i->second->_shortName
          && ( all || i->second->_specified ) ) {
            cout << "opt '" << i->first << "' " << i->second->_value << endl;
        }
    }
}

Fortran

argc=iargc() 命令行参数个数,用于方便循环读取. call getarg(i,buffer) 读取命令行,i是第几个,buffer是字符组用于储存.

Fortran例子

分析参数, 将多个输入参数的磨光次数进行排序. 更多细节和后续用法就不列了.

!* For input arguments
!* 1st: file; other: polish times for writing result.
argc=iargc();
CALL GETARG(1, mapname)
if (argc < 1) then
    print *,'Error, Please assign the filename!'
    print *,'1:filename '
    stop
end if

! Analyse file name.
dotPlace=index(mapname,'.',back = .true.);
basename=mapname(:dotPlace-1);
extname=mapname(dotPlace+1:);
if (extname(1:3)/='map') then
	print *,'Error, Please assign the filename!'
    print *,'1:filename '
    stop
endif

! read the other arguments
Kpolish=0; j=0
if (argc>1) then
	do i=2,argc
		call GETARG(i,tmpstr)
		read(tmpstr,*) j
		if (j == 0 ) then
			readFromMap=.true.
            writedat=.false.
		else
			Kpolish=Kpolish+1
			Tpolish(Kpolish)=j
		end if 
	enddo
	!* sort from small to large
	call bubble_sort(Tpolish,Kpolish);
else 
	readFromMap=.true.
endif


◆ 本文地址: http://platinhom.github.io/2015/06/13/ReadArgv/, 转载请注明 ◆

前一篇: 操作系统判断的指令:uname
后一篇: Amber输入结构的预处理


Contact: Hom / 已阅读()
Source 类别: Coding  标签: Shell  Python  Fortran  C++  Key