<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Fwolf's Blog &#187; script - Fwolf's Blog</title>
	<atom:link href="http://www.fwolf.com/blog/post/tag/script/feed" rel="self" type="application/rss+xml" />
	<link>http://www.fwolf.com/blog</link>
	<description>随心·随意·随缘·努力～</description>
	<lastBuildDate>Wed, 07 Jul 2010 07:07:52 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Bash script中的命令行参数处理</title>
		<link>http://www.fwolf.com/blog/post/371</link>
		<comments>http://www.fwolf.com/blog/post/371#comments</comments>
		<pubDate>Sat, 01 Dec 2007 11:00:48 +0000</pubDate>
		<dc:creator>Fwolf</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[cli]]></category>
		<category><![CDATA[script]]></category>

		<guid isPermaLink="false">http://www.fwolf.com/blog/post/371</guid>
		<description><![CDATA[Bash中的script是强大的，但如果想让写出的脚本更加实用、灵活，不能简单的堆砌命令，势必要加上一些命令行参数。命令行参数除了实际的操作对象以外，还可能是一些选项（通常是用-开头的），如果还是用$1、$2这样的方式一个一个的判断参数到底是不是选项、是哪个选项就太低效了，更好的方式是用getopts，先看简单的例子： #!/bin/bash while getopts 'd:Dm:f:t:' OPT; do case $OPT in d) DEL_DAYS="$OPTARG";; D) DEL_ORIGINAL='yes';; f) DIR_FROM="$OPTARG";; m) MAILDIR_NAME="$OPTARG";; t) DIR_TO="$OPTARG";; ?) echo "Usage: `basename $0` [options] filename" esac done shift $(($OPTIND - 1)) getopts后面的字符串就是可以使用的选项列表，每个字母代表一个选项，后面带:的意味着选项除了定义本身之外，还会带上一个参数作为选项的值，比如d:在实际的使用中就会对应-d 30，选项的值就是30；getopts字符串中没有跟随:的是开关型选项，不需要再指定值，相当于true/false，只要带了这个参数就是true。如果命令行中包含了没有在getopts列表中的选项，会有警告信息，如果在整个getopts字符串前面也加上个:，就能消除警告信息了。 使用getopts识别出各个选项之后，就可以配合case来进行相应的操作了。操作中有两个相对固定的“常量”，一个是OPTARG，用来取当前选项的值，另外一个是OPTIND，代表当前选项在参数列表中的位移。注意case中的最后一个选择──?，代表这如果出现了不认识的选项，所进行的操作。 选项参数识别完成之后，如果要取剩余的其它命令行参数，可以使用shift把选项参数抹去，就像例子里面的那样，对整个参数列表进行左移操作，最左边的参数就丢失了（已经用case判断并进行了处理，不再需要了），位移的长度正好是刚才case循环完毕之后的OPTIND - 1，因为参数从1开始编号，选项处理完毕之后，正好指向剩余其它参数的第一个。在这里还要知道，getopts在处理参数的时候，处理一个开关型选项，OPTIND加1，处理一个带值的选项参数，OPTIND则会加2。 最后，真正需要处理的参数就是$1~$#了，可以用for循环依次处理。 使用getopts处理参数虽然是更加方便了，但仍然有两个小小的局限： 选项参数的格式必须是-d val，而不能是中间没有空格的-dval。 所有选项参数必须写在其它参数的前面，因为getopts是从命令行前面开始处理，遇到非-开头的参数，或者选项参数结束标记--就中止了，如果中间遇到非选项的命令行参数，后面的选项参数就都取不到了。 参考 Parsing arguments for your shell script Tags: bash, cli, Linux, [...]]]></description>
			<content:encoded><![CDATA[<p>Bash中的script是强大的，但如果想让写出的脚本更加实用、灵活，不能简单的堆砌命令，势必要加上一些命令行参数。命令行参数除了实际的操作对象以外，还可能是一些选项（通常是用-开头的），如果还是用$1、$2这样的方式一个一个的判断参数到底是不是选项、是哪个选项就太低效了，更好的方式是用getopts，先看简单的例子：</p>

<pre><code>#!/bin/bash
while getopts 'd:Dm:f:t:' OPT; do
    case $OPT in
        d)
            DEL_DAYS="$OPTARG";;
        D)
            DEL_ORIGINAL='yes';;
        f)
            DIR_FROM="$OPTARG";;
        m)
            MAILDIR_NAME="$OPTARG";;
        t)
            DIR_TO="$OPTARG";;
        ?)
            echo "Usage: `basename $0` [options] filename"
    esac
done

shift $(($OPTIND - 1))
</code></pre>

<p>getopts后面的字符串就是可以使用的选项列表，每个字母代表一个选项，后面带<code>:</code>的意味着选项除了定义本身之外，还会带上一个参数作为选项的值，比如<code>d:</code>在实际的使用中就会对应<code>-d 30</code>，选项的值就是30；getopts字符串中没有跟随<code>:</code>的是开关型选项，不需要再指定值，相当于true/false，只要带了这个参数就是true。如果命令行中包含了没有在getopts列表中的选项，会有警告信息，如果在整个getopts字符串前面也加上个<code>:</code>，就能消除警告信息了。</p>

<p>使用getopts识别出各个选项之后，就可以配合case来进行相应的操作了。操作中有两个相对固定的“常量”，一个是<code>OPTARG</code>，用来取当前选项的值，另外一个是<code>OPTIND</code>，代表当前选项在参数列表中的位移。注意case中的最后一个选择──<code>?</code>，代表这如果出现了不认识的选项，所进行的操作。</p>

<p>选项参数识别完成之后，如果要取剩余的其它命令行参数，可以使用<code>shift</code>把选项参数抹去，就像例子里面的那样，对整个参数列表进行左移操作，最左边的参数就丢失了（已经用case判断并进行了处理，不再需要了），位移的长度正好是刚才case循环完毕之后的<code>OPTIND - 1</code>，因为参数从1开始编号，选项处理完毕之后，正好指向剩余其它参数的第一个。在这里还要知道，getopts在处理参数的时候，处理一个开关型选项，OPTIND加1，处理一个带值的选项参数，OPTIND则会加2。</p>

<p>最后，真正需要处理的参数就是$1~$#了，可以用for循环依次处理。</p>

<p>使用getopts处理参数虽然是更加方便了，但仍然有两个小小的局限：</p>

<ol>
<li>选项参数的格式必须是<code>-d val</code>，而不能是中间没有空格的<code>-dval</code>。</li>
<li>所有选项参数必须写在其它参数的前面，因为getopts是从命令行前面开始处理，遇到非<code>-</code>开头的参数，或者选项参数结束标记<code>--</code>就中止了，如果中间遇到非选项的命令行参数，后面的选项参数就都取不到了。</li>
</ol>

<h4>参考</h4>

<ul>
<li><a href="http://www.linux.com/feature/118031">Parsing arguments for your shell script</a></li>
</ul>

	Tags: <a href="http://www.fwolf.com/blog/post/tag/bash" title="bash" rel="tag">bash</a>, <a href="http://www.fwolf.com/blog/post/tag/cli" title="cli" rel="tag">cli</a>, <a href="http://www.fwolf.com/blog/post/tag/linux" title="Linux" rel="tag">Linux</a>, <a href="http://www.fwolf.com/blog/post/tag/script" title="script" rel="tag">script</a><br />

	<h4>Related posts</h4>
	<ul class="st-related-posts">
	<li><a href="http://www.fwolf.com/blog/post/279" title="配置ssh的自动登录 (2007-01-05)">配置ssh的自动登录</a> (12)</li>
	<li><a href="http://www.fwolf.com/blog/post/400" title="选择Eclipse PHP Development Tools(PDT)作为PHP开发工具 (2008-05-03)">选择Eclipse PHP Development Tools(PDT)作为PHP开发工具</a> (8)</li>
	<li><a href="http://www.fwolf.com/blog/post/410" title="用ssh打通反向隧道，内网也可对外提供服务 (2008-07-10)">用ssh打通反向隧道，内网也可对外提供服务</a> (2)</li>
	<li><a href="http://www.fwolf.com/blog/post/437" title="安装ibus输入法 (2009-04-06)">安装ibus输入法</a> (3)</li>
	<li><a href="http://www.fwolf.com/blog/post/347" title="升级MT dv 3.0主机到php5 (2007-08-09)">升级MT dv 3.0主机到php5</a> (9)</li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://www.fwolf.com/blog/post/371/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>
