<?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>IGI&#039;s Blog &#187; shell</title>
	<atom:link href="http://www.igigo.net/archives/category/shell/feed" rel="self" type="application/rss+xml" />
	<link>http://www.igigo.net</link>
	<description></description>
	<lastBuildDate>Fri, 09 Dec 2011 04:19:40 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.4</generator>
	
<!-- Start Of Script Generated By WP-PostViews Plus -->
<script type='text/javascript' src='http://www.igigo.net/wp-includes/js/jquery/jquery.js?ver=1.4.2'></script>
<script type="text/javascript">
/* <![CDATA[ */
/* ]]> */
</script>
<!-- End Of Script Generated By WP-PostViews Plus -->
	<item>
		<title>Dash与Bash的语法区别</title>
		<link>http://www.igigo.net/archives/169</link>
		<comments>http://www.igigo.net/archives/169#comments</comments>
		<pubDate>Sat, 19 Feb 2011 06:25:36 +0000</pubDate>
		<dc:creator>igi</dc:creator>
				<category><![CDATA[shell]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[dash]]></category>

		<guid isPermaLink="false">http://www.igigo.net/?p=169</guid>
		<description><![CDATA[如今Debian和Ubuntu中，/bin/sh默认已经指向dash，这是一个不同于bash的shell，它主要是为了执行脚本而出现，而不是交互，它速度更快，但功能相比bash要少很多，语法严格遵守POSIX标准，下面简要列举下从bash迁移到dash一般需要注意的问题 1.定义函数 bash: function在bash中为关键字 igi@gentoo ~ $ foo(){ echo $0;} igi@gentoo ~ $ foo /bin/bash igi@gentoo ~ $ function foo2(){ echo $0;} igi@gentoo ~ $ foo2 /bin/bash dash: dash中没有function这个关键字 $ foo(){ echo $0;} $ foo dash $ function foo2(){ echo $0;} dash: Syntax error: &#34;(&#34; unexpected 2.select var in list; do command; done bash:支持 igi@gentoo [...]]]></description>
			<content:encoded><![CDATA[<p>如今Debian和Ubuntu中，/bin/sh默认已经指向dash，这是一个不同于bash的shell，它主要是为了执行脚本而出现，而不是交互，它速度更快，但功能相比bash要少很多，语法严格遵守POSIX标准，下面简要列举下从bash迁移到dash一般需要注意的问题</p>
<h1>1.定义函数</h1>
<p>bash: function在bash中为关键字</p>
<pre class="brush: bash; title: ;">
igi@gentoo ~ $ foo(){ echo $0;}
igi@gentoo ~ $ foo
/bin/bash
igi@gentoo ~ $ function foo2(){ echo $0;}
igi@gentoo ~ $ foo2
/bin/bash
</pre>
<p>dash: dash中没有function这个关键字                                                                              </p>
<pre class="brush: bash; title: ;">
$ foo(){ echo $0;}
$ foo
dash
$ function foo2(){ echo $0;}
dash: Syntax error: &quot;(&quot; unexpected
</pre>
<h1>2.select var in list; do command; done</h1>
<p>bash:支持</p>
<pre class="brush: bash; title: ;">
igi@gentoo ~ $ select input in A B
&gt; do
&gt;   case $input in
&gt;     A)
&gt;        echo 'Input:A'
&gt;        break
&gt;        ;;
&gt;     B)
&gt;        echo 'Input:B'
&gt;        break
&gt;        ;;
&gt;   esac
&gt; done
1) A
2) B
#? 1
Input:A
igi@gentoo ~ $ echo $0
/bin/bash
</pre>
<p>dash:不支持, 替代方法:采用while+read+case来实现</p>
<pre class="brush: bash; title: ;">
menu(){ echo -n &quot;1)A;\n2)B\n&gt;&quot;;}
menu
while read input
do
    case $input in
      1)
         echo 'A'
         break
         ;;
      2)
         echo 'B'
         break
         ;;
      *)
         menu
         continue
         ;;
    esac
done
</pre>
<h1>3. echo {0..10}</h1>
<p>bash:支持{n..m}展开</p>
<pre class="brush: bash; title: ;">
igi@gentoo ~ $ echo $0
/bin/bash
igi@gentoo ~ $ echo {0..10}
0 1 2 3 4 5 6 7 8 9 10
</pre>
<p>dash:不支持，替代方法, 采用seq外部命令</p>
<pre class="brush: bash; title: ;">
$ echo $0
dash
$ echo {0..10}
{0..10}
$ echo `seq 0 10`
0 1 2 3 4 5 6 7 8 9 10
</pre>
<h1>4. here string</h1>
<p>bash:支持here string</p>
<pre class="brush: bash; title: ;">
igi@gentoo ~ $ cat &lt;&lt;&lt;&quot;string&quot;
string
igi@gentoo ~ $ echo $0
/bin/bash
</pre>
<p>dash:不支持, 替代方法:可采用here documents</p>
<pre class="brush: bash; title: ;">
$ echo $0
dash
$ cat &lt;&lt;&lt;&quot;string&quot;
dash: Syntax error: redirection unexpected
$ cat &lt;&lt;EOF
&gt; string
&gt; EOF
string
</pre>
<h1>5. >&#038;word重定向标准输出和标准错误</h1>
<p>bash: 当word为非数字时，>&#038;word变成重定向标准错误和标准输出到文件word, 常见用法>&#038;/dev/null</p>
<pre class="brush: bash; title: ;">
igi@gentoo ~/test $ ls
a
igi@gentoo ~/test $ ls a b
ls: cannot access b: No such file or directory
a
igi@gentoo ~/test $ ls a b &gt;&amp;/dev/null
igi@gentoo ~/test $ ls a b &gt;/dev/null 2&gt;&amp;1
igi@gentoo ~/test $ echo $0
/bin/bash
</pre>
<p>dash: >&#038;word, word不支持非数字, 替代方法: >word 2>&#038;1; 常见用法 >/dev/null 2>&#038;1</p>
<pre class="brush: bash; title: ;">
$ echo $0
dash
$ ls a
a
$ ls a b
ls: cannot access b: No such file or directory
a
$ ls a b &gt;&amp;/dev/null
dash: Syntax error: Bad fd number
$ ls a b &gt;/dev/null 2&gt;&amp;1
$
</pre>
<h1>6. 数组</h1>
<p>bash: 支持数组, bash4支持关联数组</p>
<pre class="brush: bash; title: ;">
igi@gentoo ~/test $ echo $0
/bin/bash
igi@gentoo ~/test $ array=( a b c )
igi@gentoo ~/test $ echo ${array[2]}
c
</pre>
<p>dash: 不支持数组，替代方法, 采用变量名+序号来实现类似的效果</p>
<pre class="brush: bash; title: ;">
$ for i in a b c
&gt; do
&gt; id=$((${id:=-1}+1))
&gt; eval array_$id=$i
&gt; done
$ echo ${array_1}
b
$ echo $0
dash
</pre>
<p>很蛋疼的方法，非不得以不建议这么用</p>
<h1>7. 子字符串扩展</h1>
<p>bash: 支持${parameter:offset:length},${parameter:offset}</p>
<pre class="brush: bash; title: ;">
igi@gentoo ~/test $ string='hello'
igi@gentoo ~/test $ echo ${string:1:3}
ell
igi@gentoo ~/test $ echo ${string:1}
ello
igi@gentoo ~/test $ echo $0
/bin/bash
</pre>
<p>dash: 不支持， 替代方法:采用expr或cut外部命令代替</p>
<pre class="brush: bash; title: ;">
$ string='hello'
$ expr substr &quot;$string&quot; 2 3
ell
$ echo &quot;$string&quot; | cut -c2-4
ell
$ expr substr &quot;$string&quot; 2 &quot;${#string}&quot;
ello
$ echo &quot;$string&quot; | cut -c2-
ello
$ echo $0
dash
$
</pre>
<h1>8. 大小写转换</h1>
<p>bash: 支持${parameter^pattern},${parameter^^pattern},${parameter,pattern},${parameter,,pattern}</p>
<pre class="brush: bash; title: ;">
igi@gentoo ~/test $ string=&quot;abcABC&quot;
igi@gentoo ~/test $ echo ${string^^}
ABCABC
igi@gentoo ~/test $ echo ${string,,}
abcabc
igi@gentoo ~/test $ echo ${string^^b}
aBcABC
igi@gentoo ~/test $ echo $0
/bin/bash
</pre>
<p>dash: 不支持，替代方法:采用tr/sed/awk等外部命令转换</p>
<pre class="brush: bash; title: ;">
$ string='abcABC'
$ echo &quot;$string&quot; | tr '[a-z]' '[A-Z]'
ABCABC
$ echo &quot;$string&quot; | tr '[A-Z]' '[a-z]'
abcabc
$ echo &quot;$string&quot; | sed 's/b/\U&amp;/g'
aBcABC
$
</pre>
<h1>9. 进程替换<(command), >(command)</h1>
<p>bash: 支持进程替换</p>
<pre class="brush: bash; title: ;">
igi@gentoo ~ $ diff &lt;(seq 3) &lt;(seq 4)
3a4
&gt; 4
igi@gentoo ~ $ echo $0
/bin/bash
</pre>
<p>dash: 不支持, 替代方法, 通过临时文件中转</p>
<pre class="brush: bash; title: ;">
$ diff &lt;(seq 3) &lt;(seq 4)
dash: Syntax error: &quot;(&quot; unexpected
$ seq 3 &gt;tmp1
$ seq 4 &gt;tmp2
$ diff tmp1 tmp2
3a4
&gt; 4
$ echo $0
dash
$
</pre>
<h1>10. [ string1 = string2 ] 和 [ string1 == string2 ]</h1>
<p>bash: 支持两者</p>
<pre class="brush: bash; title: ;">
igi@gentoo ~ $ [ 'a' = 'a' ] &amp;&amp; echo 'equal'
equal
igi@gentoo ~ $ [ 'a' == 'a' ] &amp;&amp; echo 'equal'
equal
igi@gentoo ~ $ echo $0
/bin/bash
</pre>
<p>dash: 只支持=</p>
<pre class="brush: bash; title: ;">
$ [ 'a' = 'a' ] &amp;&amp; echo 'equal'
equal
$ [ 'a' == 'a' ] &amp;&amp; echo 'equal'
[: 2: a: unexpected operator
$ echo $0
dash
$
</pre>
<h1>11. [[ 加强版test</h1>
<p>bash: 支持[[ ]], 可实现正则匹配等强大功能</p>
<pre class="brush: bash; title: ;">
igi@gentoo ~ $ [[ 'xyz123' =~ xyz[0-9]+ ]] &amp;&amp; echo 'equal'
equal
igi@gentoo ~ $ echo $0
/bin/bash
</pre>
<p>dash: 不支持[[ ]], 替代方法，采用外部命令</p>
<pre class="brush: bash; title: ;">
$ [[ 'xyz123' =~ xyz[0-9]+ ]] &amp;&amp; echo 'equal'
dash: [[: not found
$ echo 'xyz123' | grep -q 'xyz[0-9]\+' &amp;&amp; echo 'equal'
equal
$ echo $0
dash
$
</pre>
<h1>12. for (( expr1 ; expr2 ; expr3 )) ; do list ; done</h1>
<p>bash: 支持C语言格式的for循环 </p>
<pre class="brush: bash; title: ;">
igi@gentoo ~ $ for((i=0;i&lt;=3;i++));do echo &quot;$i&quot;;done
0
1
2
3
igi@gentoo ~ $ echo $0
/bin/bash
</pre>
<p>dash: 不支持该格式的for, 替代方法，用while+$((expression))实现</p>
<pre class="brush: bash; title: ;">
$ i=0
$ while [ &quot;$i&quot; -le 3 ]
&gt; do
&gt; echo &quot;$i&quot;
&gt; i=$((i+1))
&gt; done
0
1
2
3
$ echo $0
dash
$
</pre>
<h1>13. let命令和((expression))</h1>
<p>bash: 有内置命令let, 也支持((expression))方式</p>
<pre class="brush: bash; title: ;">
igi@gentoo ~ $ i=0
igi@gentoo ~ $ let i++
igi@gentoo ~ $ echo $i
1
igi@gentoo ~ $ ((i++))
igi@gentoo ~ $ echo $i
2
igi@gentoo ~ $ echo $0
/bin/bash
</pre>
<p>dash: 不支持，替代方法，采用$((expression))或者外部命令做计算</p>
<pre class="brush: bash; title: ;">
$ i=0
$ i=$((i+1))
$ echo $i
1
$ echo $0
dash
$
</pre>
<h1>14. $((expression))</h1>
<p>bash: 支持id++,id--,++id,--id这样到表达式</p>
<pre class="brush: bash; title: ;">
igi@gentoo ~ $ i=0
igi@gentoo ~ $ echo $((i++))
0
igi@gentoo ~ $ echo $i
1
igi@gentoo ~ $ echo $((++i))
2
igi@gentoo ~ $ echo $i
2
igi@gentoo ~ $ echo $0
/bin/bash
</pre>
<p>dash: 不支持++,--, 替代方法:id+=1,id-=1, id=id+1,id=id-1</p>
<pre class="brush: bash; title: ;">
$ i=0
$ echo $((i++))
dash: arithmetic expression: expecting primary: &quot;i++&quot;
$ echo $i;i=$((i+1))
0
$ echo $i
1
$ echo $((i+=1))
2
$ echo $i
2
$ echo $0
dash
$
</pre>
<p>以上列举的都是常见容易混淆的地方，更多区别可以查看manpage</p>
]]></content:encoded>
			<wfw:commentRss>http://www.igigo.net/archives/169/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Bash星号的那点事</title>
		<link>http://www.igigo.net/archives/164</link>
		<comments>http://www.igigo.net/archives/164#comments</comments>
		<pubDate>Mon, 14 Feb 2011 08:12:00 +0000</pubDate>
		<dc:creator>igi</dc:creator>
				<category><![CDATA[bash那点事]]></category>
		<category><![CDATA[shell]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[star]]></category>

		<guid isPermaLink="false">http://www.igigo.net/?p=164</guid>
		<description><![CDATA[星号，这是个神奇的符号，在bash中，星号也充满魔力，它是通配符之一。 简单列举下星号的功能，被称为万能字符不是没有理由的. 1)文件名匹配: 默认情况下匹配所有非隐藏文件(即非.开头到文件) 2)字符串匹配: 匹配任意字符 3)$*匹配所有参数 4)${array[*]}，表示了所有数组元素 5)乘法运算 6)** 冪运算 7)** bash4中提供的更牛b的文件名匹配，包含递归功能 接下我们来见识下它强大到魔力： 1)文件名匹配: igi@gentoo ~ $ ls a b c d igi@gentoo ~ $ ls -A a b c d .t .u .v .w .x .y igi@gentoo ~ $ echo * a b c d 我们可以看到，*号匹配了所有非隐藏文件名，如果要匹配所有文件名(包括隐藏文件)，可以打开dotglob开关 igi@gentoo ~ $ ls -A a b [...]]]></description>
			<content:encoded><![CDATA[<p>    星号，这是个神奇的符号，在bash中，星号也充满魔力，它是通配符之一。<br />
    简单列举下星号的功能，被称为万能字符不是没有理由的.<br />
        1)文件名匹配: 默认情况下匹配所有非隐藏文件(即非.开头到文件)<br />
        2)字符串匹配: 匹配任意字符<br />
        3)$*匹配所有参数<br />
        4)${array[*]}，表示了所有数组元素<br />
        5)乘法运算<br />
        6)** 冪运算<br />
        7)** bash4中提供的更牛b的文件名匹配，包含递归功能<br />
    接下我们来见识下它强大到魔力：<br />
1)文件名匹配:</p>
<pre class="brush: bash; title: ;">
igi@gentoo ~ $ ls
a  b  c  d
igi@gentoo ~ $ ls -A
a  b  c  d  .t  .u  .v  .w  .x  .y
igi@gentoo ~ $ echo *
a b c d
</pre>
<p>我们可以看到，*号匹配了所有非隐藏文件名，如果要匹配所有文件名(包括隐藏文件)，可以打开dotglob开关                                                                                        </p>
<pre class="brush: bash; title: ;">
igi@gentoo ~ $ ls -A
a  b  c  d  .t  .u  .v  .w  .x  .y
igi@gentoo ~ $ echo *
a b c d
igi@gentoo ~ $ shopt -s dotglob
igi@gentoo ~ $ echo *
a b c d .t .u .v .w .x .y
</pre>
<p>如果只是匹配隐藏文件呢？可别想得太复杂了哦                                                                                                                                              </p>
<pre class="brush: bash; title: ;">
igi@gentoo ~ $ ls -a
.  ..  a  b  c  d  .t  .u  .v  .w  .x  .y
igi@gentoo ~ $ echo .*
. .. .t .u .v .w .x .y
</pre>
<p>需要注意到是，.*会把当前目录下到.目录和..目录也匹配进去</p>
<p>2)字符串匹配:这一般用在case语句、字符串截取中</p>
<pre class="brush: bash; title: ;">
igi@gentoo ~ $ case &quot;abc&quot; in
&gt; a)
&gt;   echo 'a'
&gt;   ;;
&gt; a*)
&gt;   echo 'a*'
&gt;   ;;
&gt; esac
a*
igi@gentoo ~ $ var='abc123'
igi@gentoo ~ $ echo &quot;${var%c*}&quot;
ab
</pre>
<p>可以看到*号匹配了任意字符，在这里，先提醒一下，这里用的是模式匹配，而不是正则(正则与模式匹配不同，以后到文章中，将会仔细对比这两者到区别)</p>
<p>3)$*表示所有参数</p>
<pre class="brush: bash; title: ;">
igi@gentoo ~ $ foo() { for i in $*; do echo &quot;var: $i&quot;; done; }
igi@gentoo ~ $ foo a b &quot;c cc&quot;
var: a
var: b
var: c
var: cc
igi@gentoo ~ $ foo() { for i in &quot;$*&quot;; do echo &quot;var: $i&quot;; done; }
igi@gentoo ~ $ IFS=&quot;|&quot; foo a b &quot;c cc&quot;
var: a|b|c cc
</pre>
<p>最后到例子中，我设置了新到IFS变量，只是为了让大家更清晰到看到，bash是如何对待&#8221;$*&#8221;的，bash用IFS变量，把所有参数拼成一个字符串，这就是&#8221;$*&#8221;<br />
这里先说下$@和&#8221;$@&#8221;，在没有用双引号包围时，$@和$*一样表示了 $1 $2 $3 &#8230;<br />
而&#8221;$@&#8221; 则与&#8221;$*&#8221;不同，&#8221;$@&#8221;表示了 &#8220;$1&#8243; &#8220;$2&#8243; &#8220;$3&#8243; &#8230;(注意这里到双引号，双引号中的字符串是一个整体)，似乎有点不明白，看看下面的例子</p>
<pre class="brush: bash; title: ;">
igi@gentoo ~ $ foo() { for i in $*;do echo &quot;var: $i&quot;;done;}
igi@gentoo ~ $ foo a b &quot;c cc&quot;
var: a
var: b
var: c
var: cc
igi@gentoo ~ $ foo() { for i in $@;do echo &quot;var: $i&quot;;done;}
igi@gentoo ~ $ foo a b &quot;c cc&quot;
var: a
var: b
var: c
var: cc
igi@gentoo ~ $ foo() { for i in &quot;$*&quot;;do echo &quot;var: $i&quot;;done;}
igi@gentoo ~ $ foo a b &quot;c cc&quot;
var: a b c cc
igi@gentoo ~ $ foo() { for i in &quot;$@&quot;;do echo &quot;var: $i&quot;;done;}
igi@gentoo ~ $ foo a b &quot;c cc&quot;
var: a
var: b
var: c cc
</pre>
<p>4)${array[*]}表示所有数组元素</p>
<pre class="brush: bash; title: ;">
igi@gentoo ~ $ array=( a b &quot;c cc&quot; )
igi@gentoo ~ $ for i in ${array[*]};do echo &quot;array: $i&quot;; done
array: a
array: b
array: c
array: cc
igi@gentoo ~ $ for i in ${array[@]};do echo &quot;array: $i&quot;; done
array: a
array: b
array: c
array: cc
igi@gentoo ~ $ for i in &quot;${array[*]}&quot;;do echo &quot;array: $i&quot;; done
array: a b c cc
igi@gentoo ~ $ for i in &quot;${array[@]}&quot;;do echo &quot;array: $i&quot;; done
array: a
array: b
array: c cc
</pre>
<p>细心的你应该不难看出，这和$*是一样的，我就不罗嗦了。</p>
<p>5、6)*号乘法运算, **冪运算</p>
<pre class="brush: bash; title: ;">
igi@gentoo ~ $ ((num=3*4))
igi@gentoo ~ $ echo $num
12
igi@gentoo ~ $ let num=3*3
igi@gentoo ~ $ echo $num
9
igi@gentoo ~ $ ((num=2**4))
igi@gentoo ~ $ echo $num
16
igi@gentoo ~ $ let num=2**2
igi@gentoo ~ $ echo $num
4
</pre>
<p>乘法运算和冪运算应该很容易理解吧。</p>
<p>7)bash4中更牛B的通配符**</p>
<pre class="brush: bash; title: ;">
igi@gentoo ~/test $ tree
.
├── a
│   ├── 1
│   ├── 2
│   ├── 3
│   ├── 4
│   └── 5
└── c
    ├── 2.txt
    ├── 3.txt
    ├── 4.txt
    └── dir

3 directories, 8 files
igi@gentoo ~/test $ shopt globstar
globstar        off
igi@gentoo ~/test $ echo **
a c
igi@gentoo ~/test $ echo **/
a/ c/
igi@gentoo ~/test $ echo *
a c
igi@gentoo ~/test $ echo **
a c
igi@gentoo ~/test $ echo */
a/ c/
igi@gentoo ~/test $ echo **/
a/ c/
</pre>
<p>默认情况下，globstar是关闭的，也就是**与*是一样的，我们来看看打开globstar后是怎么个牛b法？</p>
<pre class="brush: bash; title: ;">
igi@gentoo ~/test $ tree
.
├── a
│   ├── 1
│   ├── 2
│   ├── 3
│   ├── 4
│   └── 5
└── c
    ├── 2.txt
    ├── 3.txt
    ├── 4.txt
    └── dir

3 directories, 8 files
igi@gentoo ~/test $ shopt -s globstar
igi@gentoo ~/test $ shopt globstar
globstar        on
igi@gentoo ~/test $ echo *
a c
igi@gentoo ~/test $ echo **
a a/1 a/2 a/3 a/4 a/5 c c/2.txt c/3.txt c/4.txt c/dir
igi@gentoo ~/test $ echo */
a/ c/
igi@gentoo ~/test $ echo **/
a/ c/ c/dir/
</pre>
<p>可以看到打开globstar后，**递归的匹配了所有文件和目录， 如果**后面跟着/(即是**/)，则只匹配目录。<br />
问题来了，如果递归显示以.txt结尾到文件，是不是**.txt? 非也，来看看</p>
<pre class="brush: bash; title: ;">
igi@gentoo ~/test $ shopt -s globstar
igi@gentoo ~/test $ shopt globstar
globstar        on
igi@gentoo ~/test $ find . -name '*.txt'
./a.txt
./c/3.txt
./c/2.txt
./c/4.txt
igi@gentoo ~/test $ echo **.txt
a.txt
igi@gentoo ~/test $ echo **/*.txt
a.txt c/2.txt c/3.txt c/4.txt
</pre>
<p>看到了吧，**.txt是无法递归的，而**/*.txt就可以了，同理， foo**这样也不行，**/foo*这样到才可以。<br />
这个功能是bash4才有的哦，使用之前，先确认下你到bash版本。</p>
<p>接下来，我们来看看常见到错误<br />
1)用单引号或双引号包围了星号<br />
在&#8217;<a href="http://www.igigo.net/archives/128">Bash引号的那点事</a>&#8216;中我讲过，单引号中到字符都只有字符的原本意义，而双引号中，*号也是它本身到字符意义，在单双引号中，*号将失去它到魔力，这里就不再罗嗦<br />
如果在双引号中，$*将表示一个由所有参数拼接而成到字符串，上面已经提到过。</p>
<p>2)没有考虑星号匹配不到任何文件的情况<br />
如果指定到目录下没有任何文件时，使用星号匹配，会有啥现象？</p>
<pre class="brush: bash; title: ;">
igi@gentoo ~ $ rm -rf *
igi@gentoo ~ $ ls
igi@gentoo ~ $ echo *
*
</pre>
<p>看到了吧，如果星号匹配不到任何文件时，它变回了自己原本到意思(就是字符*)</p>
<pre class="brush: bash; title: ;">
igi@gentoo ~ $ ls
a  b  c  d
igi@gentoo ~ $ for i in *;do echo &quot;file: $i&quot; ;done
file: a
file: b
file: c
file: d
igi@gentoo ~ $ rm -rf *
igi@gentoo ~ $ ls
igi@gentoo ~ $ for i in *;do echo &quot;file: $i&quot; ;done
file: *
</pre>
<p>只是一个echo时，似乎没多大问题，但你想想，如果你在for中对文件做某些操作，如果匹配不到，变成对*号文件进行操作，我想结果肯定不是你要的，多数情况下，我们想要是，匹配不到则不进行任何操作，有没有办法？办法很多，例如你可以先做个判断，bash中，有个nullglob, 利用它，我们可以直接达到我们要到效果。</p>
<pre class="brush: bash; title: ;">
igi@gentoo ~ $ rm -rf *
igi@gentoo ~ $ shopt nullglob
nullglob        off
igi@gentoo ~ $ for i in *;do echo &quot;file: $i&quot;; done
file: *
igi@gentoo ~ $ shopt -s nullglob
igi@gentoo ~ $ for i in *;do echo &quot;file: $i&quot;; done
igi@gentoo ~ $
</pre>
<p>当然你也可以设置failglob，使得匹配不到文件时报错，这里就不再罗嗦了。</p>
<p>3)混淆模式匹配和正则<br />
先申明，这两者是不同到，这里不打算详细阐述，只列举些常见错误做法</p>
<pre class="brush: bash; title: ;">
igi@gentoo ~/test $ ls
foo-a-log  foo-b-log  foo-c-log  zoo-a-log  zoo-b-log  zoo-c-log
igi@gentoo ~/test $ ls foo.*
ls: cannot access foo.*: No such file or directory
igi@gentoo ~/test $ ls foo*
foo-a-log  foo-b-log  foo-c-log
</pre>
<p>.*在正则中匹配了所有，但请记住，shell中绝大多数用的是模式匹配([[ "$string" =~ RE ]]例外)<br />
在模式匹配中*匹配了所有，?匹配了单个字符，.号没有特殊意义，还是.号<br />
所以，第二个命令才是正确</p>
]]></content:encoded>
			<wfw:commentRss>http://www.igigo.net/archives/164/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Bash空格的那点事</title>
		<link>http://www.igigo.net/archives/152</link>
		<comments>http://www.igigo.net/archives/152#comments</comments>
		<pubDate>Wed, 19 Jan 2011 08:58:45 +0000</pubDate>
		<dc:creator>igi</dc:creator>
				<category><![CDATA[bash那点事]]></category>
		<category><![CDATA[shell]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[space]]></category>

		<guid isPermaLink="false">http://www.igigo.net/?p=152</guid>
		<description><![CDATA[空格，一个看不见的字符，很不起眼，也正由于不起眼，很多人经常忽略它，导致代码出错，却还找不着北。这里，我们来聊聊bash中空格的那点事。 先了解下bash中什么时候该用空格，什么时候不该用。 1. 等号赋值两边不能有空格 2. 命令与选项之间需要空格 3. 管道两边空格可有可无 我们来看看常见的问题 1. 赋值时等号两边或者只有左边多了空格 igi@gentoo ~ $ var1 = test bash: var1: command not found igi@gentoo ~ $ echo ${var1:?error} bash: var1: error igi@gentoo ~ $ echo ${var1?error} bash: var1: error igi@gentoo ~ $ var2 =test bash: var2: command not found igi@gentoo ~ $ echo ${var2:?error} bash: var2: [...]]]></description>
			<content:encoded><![CDATA[<p>空格，一个看不见的字符，很不起眼，也正由于不起眼，很多人经常忽略它，导致代码出错，却还找不着北。这里，我们来聊聊bash中空格的那点事。<br />
先了解下bash中什么时候该用空格，什么时候不该用。</p>
<pre>
    1. 等号赋值两边不能有空格
    2. 命令与选项之间需要空格
    3. 管道两边空格可有可无
</pre>
<p>我们来看看常见的问题<br />
1. 赋值时等号两边或者只有左边多了空格</p>
<pre class="brush: bash; title: ;">
igi@gentoo ~ $ var1 = test
bash: var1: command not found
igi@gentoo ~ $ echo ${var1:?error}
bash: var1: error
igi@gentoo ~ $ echo ${var1?error}
bash: var1: error
igi@gentoo ~ $ var2 =test
bash: var2: command not found
igi@gentoo ~ $ echo ${var2:?error}
bash: var2: error
igi@gentoo ~ $ echo ${var2?error}
bash: var2: error
</pre>
<p>这里我用了bash的变量扩展，${var1:?error}当var1为unset或null(未定义或空)时, 报指定错误; ${var1?error}当var1为unset时，报指定错误 。从执行结果来看，如果等号左边有空格，则变量名当成命令执行，结果报command not found，变量没有被赋值</p>
<p>2. 赋值时等号左边没有空格，右边有空格(这种情况有点特别，你会发现两种情况)</p>
<pre class="brush: bash; title: ;">
igi@gentoo ~ $ var= test
igi@gentoo ~ $ var= nocmd
bash: nocmd: command not found
</pre>
<p>同样是等号右边有空格，第一条命令没报错，而第二条报错了。<br />
这是因为shell中有这么一种执行命令的方式: var=string command<br />
命令command将得到变量var的值(至于在命令执行后，变量var的值是否保留下来，bash4中没有保留，但我在dash中发现时保留下来的，不同的shell对这个的处理不同), 由于test是个命令，而nocmd不是，所以报了command not found.</p>
<pre class="brush: bash; title: ;">
igi@gentoo ~ $ var=newtest eval echo \$var
newtest
igi@gentoo ~ $ echo $var
</pre>
<p>注意: 这里我使用了eval, 是想避免在第一次解析时$var被替换成空字符串, 不然就会出现下面的情况(下面是错误的测试方法，在echo还没执行时，$var已经被替换成空字符串)</p>
<pre class="brush: bash; title: ;">
igi@gentoo ~ $ var=newtest echo $var

igi@gentoo ~ $ echo $var
</pre>
<p>到这里，相信大家都明白了吧， 对于等号赋值，左右两边不可以有空格，虽然右边有空格不一定报错，但那绝对不是你想要的结果。</p>
<p>3. 命令和选项之间必须有空格<br />
这个似乎大家都明白，为何我还这么罗嗦呢？说到这里，不得不提一下一个非常特别的命令: [ 命令(你没看错，是[ ), 也就是test命令(当然bash中，这是个内置命令，但在这里不影响<br />
我们的理解)。或许你会觉得[命令眼熟，没错，我保证你见过它，来看看下面的例子</p>
<pre class="brush: bash; title: ;">
igi@gentoo ~ $ if [ &quot;abc&quot; = &quot;abc&quot; ]; then echo &#8216;they are the same&#8217;; fi
they are the same
igi@gentoo ~ $ type -a [
[ is a shell builtin
[ is /usr/bin/[
</pre>
<p>想起来了吧？[命令经常用到if判断中，当然也有人喜欢这么写</p>
<pre class="brush: bash; title: ;">
igi@gentoo ~ $ [ &quot;abc&quot; = &quot;cba&quot; ] || echo &#8216;they are not the same&#8217;
they are not the same
igi@gentoo ~ $ type -a [
[ is a shell builtin
[ is /usr/bin/[
</pre>
<p>[ 命令正名叫test命令，它们两者几乎一样，为什么不是完全一样？来看看这个</p>
<pre class="brush: bash; title: ;">
igi@gentoo ~ $ [ &quot;abc&quot; = &quot;cba&quot;
bash: [: missing `]&#8216;
igi@gentoo ~ $ [ &quot;abc&quot; = &quot;cba&quot; ]
igi@gentoo ~ $ test &quot;abc&quot; = &quot;cba&quot; ]
bash: test: too many arguments
igi@gentoo ~ $ test &quot;abc&quot; = &quot;cba&quot;
</pre>
<p>清晰了吧，用[命令时，你必须给它个尾巴], 用test命令时，就不能加个尾巴。尾巴］是[最后一个参数，不可缺少的参数, 代表[命令的结束</p>
<p>扯了这么多，那到底这个和空格有毛关系？说这些，是先让大家明白: [在shell中是个命令，它左右必须有空格！]是[的最后不可缺少的参数，它两边也需要空格(虽然有些命令的参数能连一起，例如ps, 但［命令不行，它的参数之间必须有空格)。让我们看看关于[常见的错误</p>
<p>a. if 与 [ 之间缺少空格</p>
<pre class="brush: bash; title: ;">
igi@gentoo ~ $ if[ &quot;$HOME&quot; = &quot;/home/igi&quot;];then echo 'equal'; fi
bash: syntax error near unexpected token `then'
igi@gentoo ~ $ if[ &quot;$HOME&quot; = &quot;/home/igi&quot; ];then echo 'equal'; fi
bash: syntax error near unexpected token `then'
igi@gentoo ~ $ if[&quot;$HOME&quot; = &quot;/home/igi&quot;];then echo 'equal'; fi
bash: syntax error near unexpected token `then'
igi@gentoo ~ $ if[&quot;$HOME&quot; = &quot;/home/igi&quot; ];then echo 'equal'; fi
bash: syntax error near unexpected token `then'
</pre>
<p>语法分析错误，很明显，if[ 对于bash来说，不知道是什么鬼东西</p>
<p>b. [与后面的参数之间缺少空格</p>
<pre class="brush: bash; title: ;">
igi@gentoo ~ $ if [&quot;$HOME&quot; = &quot;/home/igi&quot; ];then echo 'equal'; fi
bash: [/home/igi: No such file or directory
igi@gentoo ~ $ if [&quot;$HOME&quot; = &quot;/home/igi&quot;];then echo 'equal'; fi
bash: [/home/igi: No such file or directory
</pre>
<p>["$HOME" 对于bash来说，也不知道是什么鬼东西 </p>
<p>c. [ ] 之间的参数之间缺少空格</p>
<pre class="brush: bash; title: ;">
igi@gentoo ~ $ if [ &quot;abc&quot;=&quot;abc&quot; ]; then echo 'equal'; fi
equal
igi@gentoo ~ $ if [ &quot;abc&quot;=&quot;cba&quot; ]; then echo 'equal'; fi
equal
</pre>
<p>第一条命令似乎是对的(实际上是正巧而已)，看看第二条命令"abc" 和 "cba"明显不同，但却判断为相同。这是因为参数之间缺少了空格，被[命令认为内部是个值而已。看看下面的命令，你就会释然</p>
<pre class="brush: bash; title: ;">
igi@gentoo ~ $ if [ 0 ]; then echo 'equal'; fi
equal
igi@gentoo ~ $ if [ &quot;1&quot; ]; then echo 'equal'; fi
equal
igi@gentoo ~ $ if [ &quot;&quot; ]; then echo 'equal'; fi
igi@gentoo ~ $ if [ ]; then echo 'equal'; fi
</pre>
<p>在[ ] 内部，如果只有一个值(那些因为缺少了空格而连一起的也算)，不是空字符串就为真。所以在[ ] 之间的参数，也要两边有空格，而不能堆一起</p>
<p>d. 参数和尾巴]之间缺少空格<br />
这个就不罗嗦了，尾巴]也是[命令的参数，如同上面所讲，参数之间必须有空格</p>
<p>扯了这么多[命令与空格的事，但有些时候，缺了空格却能正确运行, 当然这只是你好运, 一起来看看</p>
<pre class="brush: bash; title: ;">
igi@gentoo ~ $ var=' abc'
igi@gentoo ~ $ if [$var = &quot;abc&quot; ];then echo 'equal'; fi
equal
igi@gentoo ~ $ if [&quot;$var&quot; = &quot;abc&quot; ];then echo 'equal'; fi
bash: [ abc: command not found
</pre>
<p>之前<a href="http://www.igigo.net/archives/128">Bash引号那点事</a>提到过，双引号包围起来的是一个整体，而没双引号的时候，字符串前后的空格或制表符都被切开。如果恰巧你遇到了或者你故意要丢弃字符串前后的空格或制表符，那也不是不可能, 但非常不建议你这么写，你的代码将是非常脆弱的。</p>
<p>或者你该加的空格都加了，但还是报错，这也可能和缺少双引号有关。这样的情况很普遍，最后再看看</p>
<pre class="brush: bash; title: ;">
igi@gentoo ~ $ var=''
igi@gentoo ~ $ if [ &quot;$var&quot; = &quot;abc&quot; ];then echo 'equal'; fi
igi@gentoo ~ $ if [ $var = &quot;abc&quot; ];then echo 'equal'; fi
bash: [: =: unary operator expected
igi@gentoo ~ $ dvar='a b c'
igi@gentoo ~ $ if [ $dvar = &quot;a b c&quot; ];then echo 'equal'; fi
bash: [: too many arguments
igi@gentoo ~ $ if [ &quot;$dvar&quot; = &quot;a b c&quot; ];then echo 'equal'; fi
equal
</pre>
<p>我再罗嗦一次，不要轻易省略双引号。很清楚了吧？如果你还不明白，<br />
请读读<a href="http://www.igigo.net/archives/128">Bash引号那点事</a></p>
<p>最后，对于管道两边可有可无的空格，就不扯淡了，因为没遇到有人对此有疑惑.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.igigo.net/archives/152/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Bash引号的那点事</title>
		<link>http://www.igigo.net/archives/128</link>
		<comments>http://www.igigo.net/archives/128#comments</comments>
		<pubDate>Fri, 14 Jan 2011 06:27:12 +0000</pubDate>
		<dc:creator>igi</dc:creator>
				<category><![CDATA[bash那点事]]></category>
		<category><![CDATA[shell]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[quote]]></category>

		<guid isPermaLink="false">http://www.igigo.net/?p=128</guid>
		<description><![CDATA[促使我想写这个系列的文章，是因为看到总有人提到相同的问题，犯相同的错误，曾经我也是这么过来的，不忍心看到后面还有人经常这么曲折的过来。 先了解下，在bash脚本中，有三种引号 1. 单引号 ' 2. 双引号 " 3. 反引号 ` 单引号 两个单引号包围起来的字符串就是普通的字符串，它将保留原始的字面意思. 双引号 两个双引号包围起来的字符串，部分特殊字符将起到它们的作用. 这些特殊字符有: 美元符$, 反斜杠\, 反引号, 感叹号!. 反引号 两个反引号包围起来的字符串，将作为命令来运行， 执行的输出结果作为该反引号的内容，称为命令替换， 它有另一种更好的写法: $(command) 我们来看几个例子，更直接的了解这三种引号的特性. 1. 美元符$在单、双引号中的表现: 在双引号中的$, 将发生变量引用, 而在单引号中的$, 将保留它的字面意思 igi@gentoo ~ $ echo '$HOME' $HOME igi@gentoo ~ $ echo &#34;$HOME&#34; /home/igi 注: HOME为内部变量 2. 反斜杠\ 在单、双引号中的表现: 在双引号中的\, 将转义它后面的字符，使其具有特殊意义或者失去原来的特殊意义, 在单引号中的\, 将保留它的字面意思 igi@gentoo ~ [...]]]></description>
			<content:encoded><![CDATA[<p>促使我想写这个系列的文章，是因为看到总有人提到相同的问题，犯相同的错误，曾经我也是这么过来的，不忍心看到后面还有人经常这么曲折的过来。</p>
<p>先了解下，在bash脚本中，有三种引号</p>
<pre>
1. 单引号 '
2. 双引号 "
3. 反引号 `

单引号
        两个单引号包围起来的字符串就是普通的字符串，它将保留原始的字面意思.
双引号
        两个双引号包围起来的字符串，部分特殊字符将起到它们的作用.
        这些特殊字符有: 美元符$, 反斜杠\, 反引号,  感叹号!.
反引号
        两个反引号包围起来的字符串，将作为命令来运行，
        执行的输出结果作为该反引号的内容，称为命令替换，
        它有另一种更好的写法: $(command)
</pre>
<p>我们来看几个例子，更直接的了解这三种引号的特性.<br />
1. 美元符$在单、双引号中的表现: 在双引号中的$, 将发生变量引用, 而在单引号中的$, 将保留它的字面意思</p>
<pre class="brush: bash; title: ;">
igi@gentoo ~ $ echo '$HOME'
$HOME
igi@gentoo ~ $ echo &quot;$HOME&quot;
/home/igi
</pre>
<p>注: HOME为内部变量</p>
<p>2. 反斜杠\ 在单、双引号中的表现: 在双引号中的\, 将转义它后面的字符，使其具有特殊意义或者失去原来的特殊意义, 在单引号中的\, 将保留它的字面意思</p>
<pre class="brush: bash; title: ;">
igi@gentoo ~ $ echo '\$HOME'
\$HOME
igi@gentoo ~ $ echo &quot;\$HOME&quot;
$HOME
</pre>
<p>注: 双引号中的\，后面跟着$, 这里发生了转义，使得$失去特殊意义, 变成普通字符.</p>
<p>3. 反引号与其他两种引号的不同: 反引号包围起来的字符串将被运行，取其结果</p>
<pre class="brush: bash; title: ;">
igi@gentoo ~ $ echo 'date'
date
igi@gentoo ~ $ echo &quot;date&quot;
date
igi@gentoo ~ $ echo `date`
Fri Dec 3 18:34:09 CST 2010
</pre>
<p>注: 在反引号中的date被当成命令执行，包含的正是命令的输出信息</p>
<p>了解了他们的不同，我们来聊一聊常见的问题</p>
<p>1. 把反引号` 写 成单引号&#8217;</p>
<p>不得不说，它们长得确实很像，个别书的印刷字体区别度不高或者印刷质量不过关, 导致了很多新手认错，常把反引号`写成单引号&#8217;。如果你不知道反引号在哪，请看看Esc键下面的那个按键, 那个就是反引号。当然也不排除有些人看书不注意，这也是常有的事。只要我们明白了反引号与单引号作用的区别，什么时候要用单引号，什么时候要用反引号就一清二楚了。当你需要一个字符串时，使用单引号； 而当你需要捕捉命令的输出时，请用反引号。</p>
<p>2. 总是忘了加双引号<br />
双引号不总是多余的，被它包围的数据变得很安全，不至于被bash切开对待。</p>
<pre class="brush: bash; title: ;">
igi@gentoo ~ $ seq 3
1
2
3
igi@gentoo ~ $ echo `seq 3`
1 2 3
igi@gentoo ~ $ echo &quot;`seq 3`&quot;
1
2
3
</pre>
<p>注: seq输出的是包含换行的信息，但echo `seq 3` 却丢失了换行符，因为bash在解析时认为`seq 3`的输出结果是3个独立的字符，解析后与echo 1 2 3相同(这个过程，bash做了很多工作，有兴趣的可以了解下bash解析顺序); 而echo &#8220;`seq 3`&#8221;时，bash把`seq 3`的输出结果当成一个整体对待(因为它被双引号包围),所以输出的结果不会被bash拆分对待，换行符得以保留。所以，当你需要保留变量或者命令替换的完整信息, 特别是换行符时，请记得给它们戴上双引号作保险，时刻加个双引号是个好习惯（为什么不是单引号呢？前面解释了，单引号里面没有魔法，变量也变不了了，命令替换也替换不了了)。再次提醒: &#8220;$var&#8221;, &#8220;`command`&#8221;, 都比$var, `command`安全得多，很多情况下，前面的才是你要的结果，除非你知道你在做什么，否则不要轻易省略双引号。</p>
<p>3. 引号嵌套总是混乱的<br />
引号中包含其他引号，只要能理解单引号和双引号中字符的表现，就不难掌握</p>
<pre class="brush: bash; title: ;">
igi@gentoo ~ $ echo &quot;abc\&quot;abc&quot;
abc&quot;abc
igi@gentoo ~ $ echo &quot;abc\'abc&quot;
abc'abc
igi@gentoo ~ $ echo &quot;abc\`abc&quot;
abc`abc
</pre>
<p>如你所见，双引号中加入其他引号很容易，你只需要用反斜杠\转义你要添加的引号(双引号中加单引号可以不用转义)。 那么单引号中是否如此简单？</p>
<pre class="brush: bash; title: ;">
igi@gentoo ~ $ echo 'abc&quot;abc'
abc&quot;abc
igi@gentoo ~ $ echo 'abc`abc'
abc`abc
</pre>
<p>到这里，确实很简单，单引号中都是普通字符，所以完全不需要转义，如果加了反斜杠\, 那么反斜杠依然是它自己，直接打印出来。</p>
<pre class="brush: bash; title: ;">
igi@gentoo ~ $ echo 'abc\&quot;\`abc'
abc\&quot;\`abc
</pre>
<p>问题来了，单引号中如何包含单引号？这个时候，反斜杠\也是无用的, 如果直接写单引号，那么bash会认为引号还没结束。好吧，如果你不幸碰到这样的问题，还是有办法解决的</p>
<pre class="brush: bash; title: ;">
igi@gentoo ~ $ echo $'abc\'abc'
abc'abc
igi@gentoo ~ $ echo -e 'abc\x27abc'
abc'abc
igi@gentoo ~ $ echo 'abc'\''abc'
abc'abc
</pre>
<p>第一种方法是bash特有的，$&#8217;string&#8217; 之间到反斜杠都将转义字符，第二种方法，通过单引号的ASCII码来打印单引号，而第三种方法，则是通过截断命令，在中间插入单引号来实现。一般用第一种方法是最优雅的。</p>
<p>最后: 希望能更多的人喜欢Bash，使用Bash。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.igigo.net/archives/128/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>bash重定向详解</title>
		<link>http://www.igigo.net/archives/79</link>
		<comments>http://www.igigo.net/archives/79#comments</comments>
		<pubDate>Wed, 23 Jun 2010 05:11:49 +0000</pubDate>
		<dc:creator>igi</dc:creator>
				<category><![CDATA[shell]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[Redirections]]></category>

		<guid isPermaLink="false">http://www.igigo.net/?p=79</guid>
		<description><![CDATA[首先我们先回顾下bash现有的重定向符号 1.重定向输入输出，目标是文件word [n]&#60;word 默认n为0 [n]&#62;word 默认n为1 [n]&#62;&#124;word 默认n为1 noclobber选项有关，直接例子就明白它的用处了 [n]&#62;&#62;word 默认n为1 igi@igi-debian:~$ rm -f testfile igi@igi-debian:~$ touch testfile igi@igi-debian:~$ cat testfile igi@igi-debian:~$ set -o noclobber igi@igi-debian:~$ echo 2 &#62;testfile bash: testfile: cannot overwrite existing file igi@igi-debian:~$ echo 2 &#62;&#124; testfile igi@igi-debian:~$ cat testfile 2 2.重定向标准错误和标准输出到指定文件描述符 &#38;&#62;word 更通用 &#62;&#38;word &#62;word 2&#62;&#38;1 追加输出 &#38;&#62;&#62;word 没有&#62;&#62;&#38;word的表达方法 &#62;&#62;word 2&#62;&#38;1 [...]]]></description>
			<content:encoded><![CDATA[<p>首先我们先回顾下bash现有的重定向符号</p>
<h3>1.重定向输入输出，目标是文件word</h3>
<pre class="brush: plain; gutter: false; title: ;">
[n]&lt;word    默认n为0
[n]&gt;word    默认n为1
[n]&gt;|word   默认n为1    noclobber选项有关，直接例子就明白它的用处了
[n]&gt;&gt;word   默认n为1
</pre>
<pre class="brush: bash; title: ;">
igi@igi-debian:~$ rm -f testfile
igi@igi-debian:~$ touch testfile
igi@igi-debian:~$ cat testfile
igi@igi-debian:~$ set -o noclobber
igi@igi-debian:~$ echo 2 &gt;testfile
bash: testfile: cannot overwrite existing file
igi@igi-debian:~$ echo 2 &gt;| testfile
igi@igi-debian:~$ cat testfile
2
</pre>
<h3>2.重定向标准错误和标准输出到指定文件描述符</h3>
<pre class="brush: plain; gutter: false; title: ;">
&amp;&gt;word      更通用
&gt;&amp;word
&gt;word 2&gt;&amp;1
</pre>
<p>追加输出</p>
<pre class="brush: plain; gutter: false; title: ;">
&amp;&gt;&gt;word     没有&gt;&gt;&amp;word的表达方法
&gt;&gt;word 2&gt;&amp;1
</pre>
<h3>3.Here Documents</h3>
<pre class="brush: plain; gutter: false; title: ;">
 &lt;&lt;[-]word
   here-document
delimiter
-符号将删除所有行开头的tab符
</pre>
<h3>4.Here Strings</h3>
<pre class="brush: plain; gutter: false; title: ;">
&lt;&lt;&lt;word
</pre>
<h3>5.复制文件描述符</h3>
<pre class="brush: plain; gutter: false; title: ;">
[n]&lt;&amp;word   默认n为0，如果为数字，必须得为打开的文件描述符
[n]&lt;&amp;-      关闭文件描述符

[n]&gt;&amp;word   默认n为1，如果为数字，必须得为打开的文件描述符
[n]&gt;&amp;-      关闭文件描述符
</pre>
<h3>6.移动文件描述符</h3>
<pre class="brush: plain; gutter: false; title: ;">
[n]&lt;&amp;digit- 默认n为0
[n]&gt;&amp;digit- 默认n为1
</pre>
<h3>7.以读写方式打开文件描述符</h3>
<pre class="brush: plain; gutter: false; title: ;">
[n]&lt;&gt;word   文件不在时会被创建
</pre>
<p>如果要深刻理解重定向，先要明白以下2点<br />
1.shell(bash或者csh等)负责重定向，对于程序或者函数，这一切都是透明的，它只管输入输出，至于从哪输入哪输出，是shell解释器负责<br />
2.shell命令解析过程中，在实际执行命令前，IO重定向先设置好</p>
<p>我们来看以下的例子</p>
<h4>1.&#8217;echo 1 a1 >a2&#8242; 与 &#8216;echo 1 >a2 a1&#8242;</h4>
<pre class="brush: bash; title: ;">
igi@igi-debian:~$ echo 1 a1 &gt;a2
igi@igi-debian:~$ cat a2
1 a1
igi@igi-debian:~$ rm a2
igi@igi-debian:~$ echo 1 &gt;a2 a1
igi@igi-debian:~$ cat a2
1 a1
</pre>
<p>IO重定向是在命令执行前设置好，所以上面两种情况，最后的效果一样，bash先把输出重定向到a2文件，再执行&#8217;echo 1 a1&#8242;</p>
<h4>2.&#8217;ls nothisfile >res 2>&#038;1&#8242; 与 &#8216;ls nothisfile 2>&#038;1 >res&#8217;</h4>
<pre class="brush: bash; title: ;">
igi@igi-debian:~/rtest$ ls nothisfile
ls: cannot access nothisfile: No such file or directory
igi@igi-debian:~/rtest$ ls nothisfile &gt;res 2&gt;&amp;1
igi@igi-debian:~/rtest$ cat res
ls: cannot access nothisfile: No such file or directory
igi@igi-debian:~/rtest$ ls nothisfile 2&gt;&amp;1 &gt;res
ls: cannot access nothisfile: No such file or directory
igi@igi-debian:~/rtest$ cat res
igi@igi-debian:~/rtest$ ls -1
a
b
c
res
igi@igi-debian:~/rtest$ ls -1 2&gt;&amp;1 &gt;res
igi@igi-debian:~/rtest$ cat res
a
b
c
res
</pre>
<p>
&#8216;ls nothisfile >res 2>&#038;1&#8242;，文件描述符1被重定向到文件res(本来是标准输出)，然后再把文件描述符2重定向到文件描述符1(此时是文件描述符1指向文件res)，最后执行&#8221;ls nothisfile&#8221;，产生错误，被送往文件描述符2，最后流向文件res。<br />
&#8216;ls nothisfile 2>&#038;1 >res&#8217;，文件描述符2被重定向到文件描述符1(即标准输出：屏幕)，然后再把文件描述符1重定向到文件res，结果是文件描述符2被重定向到标准输出，文件描述符1被重定向到文件res，最后执行&#8221;ls nothisfile&#8221;产生的错误就被送往屏幕。
</p>
<h4>3.&#8217;ls nothisfile a >&#038;word&#8217; 与 &#8216;ls nothisfile a >&#038;123456&#8242;</h4>
<pre class="brush: bash; title: ;">
igi@igi-debian:~/test/shell$ ls -1
a
igi@igi-debian:~/test/shell$ cat a
this is a
igi@igi-debian:~/test/shell$ ls nothisfile a &gt;&amp;word
igi@igi-debian:~/test/shell$ cat word
ls: cannot access nothisfile: No such file or directory
a
igi@igi-debian:~/test/shell$ ls nothisfile a &gt;&amp;123456
-bash: 123456: Bad file descriptor
igi@igi-debian:~/test/shell$ cat 123456
cat: 123456: No such file or directory
</pre>
<p>
>&#038;这个重定向符号，在前面有提到，“重定向标准错误和标准输出到指定文件描述符“ 和 “复制文件描述符“ 都有这个符号, 实际上“重定向标准错误和标准输出到指定文件描述符“ 是 “复制文件描述符“ 的一种特别情况， 即当 [n]>&#038;word 的n省略 且  word不是数字时， 会重定向标准错误和标准输出 到指定文件。<br />
&#8220;ls nothisfile a >&#038;word&#8221; , 由于word不是纯数字， bash解析成 ”重定向标准错误和标准输出到指定文件描述符“， 效果相当于 &#8221; ls nothisfile a >word 2>&#038;1&#8243;<br />
&#8220;ls nothisfile a >&#038;123456&#8243;, 由于123456是纯数字， bash解析成 &#8220;复制文件描述符&#8221;, 相当于 &#8221; ls nothisfile a 1>&#038;123456&#8243; , 但由于 “ 复制文件描述符 “规定　“如果为数字，必须得为打开的文件描述符”<br />
所以发生了错误。
</p>
<h4>4.&#8217;ls a 1>&#038;-&#8217; 与 &#8216; ls a >&#038;1- &#8216;</h4>
<pre class="brush: bash; title: ;">
igi@igi-debian:~/test/shell$ ls
a
igi@igi-debian:~/test/shell$ cat a
this is a
igi@igi-debian:~/test/shell$ ls a &gt;&amp;1-
a
igi@igi-debian:~/test/shell$ ls a 1&gt;&amp;-
ls: write error: Bad file descriptor
</pre>
<p>
“  ls a >&#038;1- “，　>&#038;1-属于“移动文件描述符” 提到的 &#8220;[n]>&#038;digit-&#8221;, 用文件描述符digit替换掉文件描述符n, n描述符被关闭.n默认为1.  &#8220;ls a >&#038;1-&#8221;,  相当与 &#8221; ls a 1>&#038;1- &#8220;,  把文件描述符1替换掉原<br />
文件描述符1, 然后关闭原文件描述符1, 没发生变化, 输出依然被送到屏幕<br />
&#8221; ls a 1>&#038;- &#8220;,  >&#038;- 属于 &#8220;复制文件描述符&#8221; 提到的&#8221;关闭文件描述符&#8221;,  &#8221; ls a 1>&#038;- &#8220;, 关闭了文件描述符1, 在运行&#8221; ls a&#8221;, 由于输出默认都送到文件描述符1, 而它被关闭, 报&#8221;错误的文件描述符&#8221;
</p>
<h4>5.&#8217;ls a nothisfile 1>&#038;2-&#8217; 与 &#8216; ls a nothisfile 1<&#038;2- '</h4>
<pre class="brush: bash; title: ;">
igi@igi-debian:~/test/shell$ ls -1
a
igi@igi-debian:~/test/shell$ ls a nothisfile 1&lt;&amp;2-
a
igi@igi-debian:~/test/shell$ ls a nothisfile 1&gt;&amp;2-
a
igi@igi-debian:~/test/shell$ exec 3&lt;&gt;test
igi@igi-debian:~/test/shell$ ls a nothisfile 1&gt;&amp;3-
ls: cannot access nothisfile: No such file or directory
igi@igi-debian:~/test/shell$ cat test
a
igi@igi-debian:~/test/shell$
</pre>
<p>
&#8216; 1>&#038;2- &#8216; 与 &#8216; 1<&#038;2- ' 是一个效果的, [n]>&#038;digit- 和 [n]<&#038;digit-  这两个移动文件描述符的操作, 都是移动digit 到 n , 区别在n没有指定时, <&#038;digit- 等于 0<&#038;digit-,  而 >&#038;digit- 等于 1>&#038;digit-<br />
移动文件描述符, 就是把描诉符digit的指向给描述符n, 然后关了digit.  例子中的exec很好的解释移动文件描述符的行为, 文件描述符3被定向到文件test, 然后1>&#038;3-, 会使得1也定向到3所定向的文件test, 然后文件描诉符3被关闭, 效果就是标准输出被定向到test文件.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.igigo.net/archives/79/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

