shell编程
本文主要介绍shell编程的基本语法以及实际应用中的常见命令。
1. 注释
1.1. 单行注释
# 这是单行注释
1.2. 多行注释
:<<EOF
多行注释内容
多行注释内容
多行注释内容
EOF
多行注释EOF也可替换成!或'
:<<'
多行注释内容
多行注释内容
多行注释内容
'
:<<!
多行注释内容
多行注释内容
多行注释内容
!
2. 变量
2.1. 变量定义
使用VARIABLENAME=VALUE的形式,VALUE如果是字符串的话,可以使用单引号、双引号或者不加引号。单引号内的任何字符都会原样输出,不能进行转义,单引号内不能单独出现一个单引号,但可成对出现,作为字符串拼接使用。双引号内可以有变量,可以出现转义字符。
2.2. 变量使用
只需要在变量前加$符号,变量加{}是可选的,方便解释器识别边界。将变量加上{}是一个好习惯,不容易出错。
your_age=25
your_name="shinerio"
your_name=shinerio
your_name='shinerio'
echo $your_age # 输出25
echo $your_name # 输出shinerio
echo "${your_name}hello" <span class="tag">#这里</span>{}必须添加,否则解释器认为是${your_namehello}
str='hello'' # 非法
str='hello'__'world' # 成对出现的单引号做字符拼接
echo $str <span class="tag">#输出hello__world</span>
str1='helloworld${your_age}\nnew line'
str2="helloworld${your_age}\nnew line"
echo $str1 # 输出helloworld${your_age}\nnew line
echo $str2 # 输出helloworld25\nnew line
echo -e $str2 # -e开启转义 \n表示换行 echo默认换行,通过\c强制不换行
<span class="tag">#helloworld25</span>
<span class="tag">#new</span> line
2.3. 只读变量
使用readonly VARIABLENAME设置变量只读,只读变量的值不能更改
readonly name='jack'
name='kelly'
zsh: read-only variable: name
2.4. 删除变量
使用unset VARIABLENAME删除变量。
3. 字符串操作
3.1. 字符串拼接
str1="hello"${your_name}"world"
str2="hello${your_name}world"
str3='hello'${your_name}'world'
3.2. 字符串长度
str='hello'
echo ${<span class="tag">#str</span>}
5
3.3. 字符串截取
${string:start:length},索引从0开始,从start(包含)开始截取共计length长度的字符。
str='helloworld'
echo ${str:0:5}
hello
3.4. 字符串运算符
| 运算符 | 说明 | 举例 |
|---|---|---|
= |
检测两个字符串是否相等,相等返回true | [ 'hello' = 'hello' ] |
!= |
检测两个字符串是否相等,不相等返回true | [ 'hello' != 'ello' ] |
-z |
检测字符串长度是否为0,为0返回true | [ -z '' ] |
-n |
检测字符串长度是否不为0,不为0返回true | [ -n 'hello' ] |
$ |
检测字符串是否为空,不为空返回true | [ <p>本文主要介绍shell编程的基本语法以及实际应用中的常见命令。</p>
<h1>1. 注释</h1>
<h2>1.1. 单行注释</h2>
<pre><code class="language-shell"># 这是单行注释
</code></pre>
<h2>1.2. 多行注释</h2>
<pre><code class="language-shell">:<<EOF
多行注释内容
多行注释内容
多行注释内容
EOF
</code></pre>
<p>多行注释<code>EOF</code>也可替换成<code>!</code>或<code>'</code></p>
<pre><code class="language-shell">:<<'
多行注释内容
多行注释内容
多行注释内容
'
:<<!
多行注释内容
多行注释内容
多行注释内容
!
</code></pre>
<h1>2. 变量</h1>
<h2>2.1. 变量定义</h2>
<p>使用<code>VARIABLENAME=VALUE</code>的形式,VALUE如果是字符串的话,可以使用单引号、双引号或者不加引号。单引号内的任何字符都会原样输出,不能进行转义,单引号内不能单独出现一个单引号,但可成对出现,作为字符串拼接使用。双引号内可以有变量,可以出现转义字符。</p>
<h2>2.2. 变量使用</h2>
<p>只需要在变量前加<code><article>
<header>
<h1>shell编程</h1>
<time datetime="2023-01-24T00:00:00.000Z">2023年1月24日</time>
<div class="tags">
<span class="tag">linux</span>
</div>
</header>
<section class="content">
<p>本文主要介绍shell编程的基本语法以及实际应用中的常见命令。</p>
<h1>1. 注释</h1>
<h2>1.1. 单行注释</h2>
<pre><code class="language-shell"># 这是单行注释
</code></pre>
<h2>1.2. 多行注释</h2>
<pre><code class="language-shell">:<<EOF
多行注释内容
多行注释内容
多行注释内容
EOF
</code></pre>
<p>多行注释<code>EOF</code>也可替换成<code>!</code>或<code>'</code></p>
<pre><code class="language-shell">:<<'
多行注释内容
多行注释内容
多行注释内容
'
:<<!
多行注释内容
多行注释内容
多行注释内容
!
</code></pre>
<h1>2. 变量</h1>
<h2>2.1. 变量定义</h2>
<p>使用<code>VARIABLENAME=VALUE</code>的形式,VALUE如果是字符串的话,可以使用单引号、双引号或者不加引号。单引号内的任何字符都会原样输出,不能进行转义,单引号内不能单独出现一个单引号,但可成对出现,作为字符串拼接使用。双引号内可以有变量,可以出现转义字符。</p>
<h2>2.2. 变量使用</h2>
<p>只需要在变量前加<code>$</code>符号,变量加<code>{}</code>是可选的,方便解释器识别边界。将变量加上<code>{}</code>是一个好习惯,不容易出错。</p>
<pre><code class="language-shell">your_age=25
your_name="shinerio"
your_name=shinerio
your_name='shinerio'
echo $your_age # 输出25
echo $your_name # 输出shinerio
echo "${your_name}hello" <span class="tag">#这里</span>{}必须添加,否则解释器认为是${your_namehello}
str='hello'' # 非法
str='hello'__'world' # 成对出现的单引号做字符拼接
echo $str <span class="tag">#输出hello__world</span>
str1='helloworld${your_age}\nnew line'
str2="helloworld${your_age}\nnew line"
echo $str1 # 输出helloworld${your_age}\nnew line
echo $str2 # 输出helloworld25\nnew line
echo -e $str2 # -e开启转义 \n表示换行 echo默认换行,通过\c强制不换行
<span class="tag">#helloworld25</span>
<span class="tag">#new</span> line
</code></pre>
<h2>2.3. 只读变量</h2>
<p>使用<code>readonly VARIABLENAME</code>设置变量只读,只读变量的值不能更改</p>
<pre><code class="language-shell">readonly name='jack'
name='kelly'
zsh: read-only variable: name
</code></pre>
<h2>2.4. 删除变量</h2>
<p>使用<code>unset VARIABLENAME</code>删除变量。</p>
<h1>3. 字符串操作</h1>
<h2>3.1. 字符串拼接</h2>
<pre><code class="language-shell">str1="hello"${your_name}"world"
str2="hello${your_name}world"
str3='hello'${your_name}'world'
</code></pre>
<h2>3.2. 字符串长度</h2>
<pre><code class="language-shell">str='hello'
echo ${<span class="tag">#str</span>}
5
</code></pre>
<h2>3.3. 字符串截取</h2>
<p><code>${string:start:length}</code>,索引从0开始,从start(包含)开始截取共计length长度的字符。</p>
<pre><code class="language-shell">str='helloworld'
echo ${str:0:5}
hello
</code></pre>
<h2>3.4. 字符串运算符</h2>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>=</code></td>
<td>检测两个字符串是否相等,相等返回true</td>
<td><code>[ 'hello' = 'hello' ]</code></td>
</tr>
<tr>
<td><code>!=</code></td>
<td>检测两个字符串是否相等,不相等返回true</td>
<td><code>[ 'hello' != 'ello' ]</code></td>
</tr>
<tr>
<td><code>-z</code></td>
<td>检测字符串长度是否为0,为0返回true</td>
<td><code>[ -z '' ]</code></td>
</tr>
<tr>
<td><code>-n </code></td>
<td>检测字符串长度是否不为0,不为0返回true</td>
<td><code>[ -n 'hello' ]</code></td>
</tr>
<tr>
<td><code>$</code></td>
<td>检测字符串是否为空,不为空返回true</td>
<td><code>[ <p>本文主要介绍shell编程的基本语法以及实际应用中的常见命令。</p>
<h1>1. 注释</h1>
<h2>1.1. 单行注释</h2>
<pre><code class="language-shell"># 这是单行注释
</code></pre>
<h2>1.2. 多行注释</h2>
<pre><code class="language-shell">:&lt;&lt;EOF
多行注释内容
多行注释内容
多行注释内容
EOF
</code></pre>
<p>多行注释<code>EOF</code>也可替换成<code>!</code>或<code>&#39;</code></p>
<pre><code class="language-shell">:&lt;&lt;&#39;
多行注释内容
多行注释内容
多行注释内容
&#39;
:&lt;&lt;!
多行注释内容
多行注释内容
多行注释内容
!
</code></pre>
<h1>2. 变量</h1>
<h2>2.1. 变量定义</h2>
<p>使用<code>VARIABLENAME=VALUE</code>的形式,VALUE如果是字符串的话,可以使用单引号、双引号或者不加引号。单引号内的任何字符都会原样输出,不能进行转义,单引号内不能单独出现一个单引号,但可成对出现,作为字符串拼接使用。双引号内可以有变量,可以出现转义字符。</p>
<h2>2.2. 变量使用</h2>
<p>只需要在变量前加<code>$</code>符号,变量加<code>{}</code>是可选的,方便解释器识别边界。将变量加上<code>{}</code>是一个好习惯,不容易出错。</p>
<pre><code class="language-shell">your_age=25
your_name=&quot;shinerio&quot;
your_name=shinerio
your_name=&#39;shinerio&#39;
echo $your_age # 输出25
echo $your_name # 输出shinerio
echo &quot;${your_name}hello&quot; &lt;span class=&quot;tag&quot;&gt;#这里&lt;/span&gt;{}必须添加,否则解释器认为是${your_namehello}
str=&#39;hello&#39;&#39; # 非法
str=&#39;hello&#39;__&#39;world&#39; # 成对出现的单引号做字符拼接
echo $str &lt;span class=&quot;tag&quot;&gt;#输出hello__world&lt;/span&gt;
str1=&#39;helloworld${your_age}\nnew line&#39;
str2=&quot;helloworld${your_age}\nnew line&quot;
echo $str1 # 输出helloworld${your_age}\nnew line
echo $str2 # 输出helloworld25\nnew line
echo -e $str2 # -e开启转义 \n表示换行 echo默认换行,通过\c强制不换行
&lt;span class=&quot;tag&quot;&gt;#helloworld25&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;#new&lt;/span&gt; line
</code></pre>
<h2>2.3. 只读变量</h2>
<p>使用<code>readonly VARIABLENAME</code>设置变量只读,只读变量的值不能更改</p>
<pre><code class="language-shell">readonly name=&#39;jack&#39;
name=&#39;kelly&#39;
zsh: read-only variable: name
</code></pre>
<h2>2.4. 删除变量</h2>
<p>使用<code>unset VARIABLENAME</code>删除变量。</p>
<h1>3. 字符串操作</h1>
<h2>3.1. 字符串拼接</h2>
<pre><code class="language-shell">str1=&quot;hello&quot;${your_name}&quot;world&quot;
str2=&quot;hello${your_name}world&quot;
str3=&#39;hello&#39;${your_name}&#39;world&#39;
</code></pre>
<h2>3.2. 字符串长度</h2>
<pre><code class="language-shell">str=&#39;hello&#39;
echo ${&lt;span class=&quot;tag&quot;&gt;#str&lt;/span&gt;}
5
</code></pre>
<h2>3.3. 字符串截取</h2>
<p><code>${string:start:length}</code>,索引从0开始,从start(包含)开始截取共计length长度的字符。</p>
<pre><code class="language-shell">str=&#39;helloworld&#39;
echo ${str:0:5}
hello
</code></pre>
<h2>3.4. 字符串运算符</h2>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>=</code></td>
<td>检测两个字符串是否相等,相等返回true</td>
<td><code>[ &#39;hello&#39; = &#39;hello&#39; ]</code></td>
</tr>
<tr>
<td><code>!=</code></td>
<td>检测两个字符串是否相等,不相等返回true</td>
<td><code>[ &#39;hello&#39; != &#39;ello&#39; ]</code></td>
</tr>
<tr>
<td><code>-z</code></td>
<td>检测字符串长度是否为0,为0返回true</td>
<td><code>[ -z &#39;&#39; ]</code></td>
</tr>
<tr>
<td><code>-n </code></td>
<td>检测字符串长度是否不为0,不为0返回true</td>
<td><code>[ -n &#39;hello&#39; ]</code></td>
</tr>
<tr>
<td><code>$</code></td>
<td>检测字符串是否为空,不为空返回true</td>
<td><code>[ $&#39;hello&#39; ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ &#39;hello&#39; = &#39;hello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ &#39;hello&#39; != &#39;ello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ -z &#39;&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ -n &#39;hello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ $&#39;hello&#39; ];then echo &#39;hello&#39;;fi
str=&#39;hello&#39;
if [ $str ];then echo &#39;hello&#39;;fi
# hello
</code></pre>
<p>注意字符串的等值判断是一个等号<code>&quot;=&quot;</code>,与下文要讲的逻辑运算符使用两个等号<code>&quot;==&quot;</code>做等值判断不一样。</p>
<h1>4. 文件测试运算符</h1>
<table>
<thead>
<tr>
<th>操作符</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>-b file</code></td>
<td>检测文件是否是块设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-c file</code></td>
<td>检测文件是否是字符设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-d file</code></td>
<td>检测文件是否是目录,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-f file</code></td>
<td>检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-g file</code></td>
<td>检测文件是否设置了<code>SGID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-k file</code></td>
<td>检测文件是否设置了粘着位(Sticky Bit),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-p file</code></td>
<td>检测文件是否是有名管道,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-u file</code></td>
<td>检测文件是否设置了<code>SUID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-r file</code></td>
<td>检测文件是否可读,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-w file</code></td>
<td>检测文件是否可写,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-x file</code></td>
<td>检测文件是否可执行,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-s file</code></td>
<td>检测文件是否为空(文件大小是否大于0),不为空返回true。</td>
</tr>
<tr>
<td><code>-e file</code></td>
<td>检测文件(包括目录)是否存在,如果是,则返回true。</td>
</tr>
</tbody></table>
<pre><code class="language-shell">if &lt;a href=&quot;f-home.html&quot; class=&quot;internal-link&quot;&gt; -f &#39;/home&#39; &lt;/a&gt;;then echo &#39;directory&#39;;else echo &#39;file&#39;;fi
# file
if &lt;a href=&quot;d-home.html&quot; class=&quot;internal-link&quot;&gt; -d &#39;/home&#39; &lt;/a&gt;;then echo &#39;directory&#39;;else echo &#39;file&#39;;fi
# directory
if &lt;a href=&quot;e-tmpfake-file.html&quot; class=&quot;internal-link&quot;&gt; -e &#39;/tmp/fake_file&#39; &lt;/a&gt;;then echo &#39;exist&#39;;else echo &#39;not exist&#39;;fi
# not exist
</code></pre>
<h1>5. 数组</h1>
<p><code>shell</code>只支持一维数组,用括号表示,元素通过空格分隔,形如<code>数组名=(值1 值2 ... 值n)</code>。<code>shell</code>数组下标从<code>1</code>开始。</p>
<ul>
<li><code>${数组名[下标]}</code>,读取指索引位置数组元素</li>
<li>使用<code>@</code>或<code>*</code>代替下标,获取数组中所有元素。</li>
<li>使用<code>{&lt;span class=&quot;tag&quot;&gt;#数组名&lt;/span&gt;[@]}</code>或<code>{&lt;span class=&quot;tag&quot;&gt;#数组名&lt;/span&gt;[*]}</code>获取数组元素个数。</li>
</ul>
<pre><code class="language-shell">arr=(value1 value2 value3 value4)
echo ${arr[3]}
# value3
echo ${arr[*]}
# value1 value2 value3 value4
echo ${arr[@]}
# value1 value2 value3 value4
arr[3]=&#39;new_value3&#39;
echo $arr[3]
# new_value3
echo ${&lt;span class=&quot;tag&quot;&gt;#arr&lt;/span&gt;[@]}
# 4
echo &quot;arr[1]的长度为:${&lt;span class=&quot;tag&quot;&gt;#arr&lt;/span&gt;[1]}&quot;
# arr[1]的长度为:6
</code></pre>
<h1>6. 运算符</h1>
<h2>6.1. 赋值运算符</h2>
<pre><code class="language-shell">a=10
b=$a
</code></pre>
<h2>6.2. 算术运算符</h2>
<p>算数运算符支持<code>+,-,*,/,%</code></p>
<h3>6.2.1. expr表示法</h3>
<pre><code class="language-shell">echo `expr 10 + 20`
# 30
echo $(expr 20 / 2)
# 10
echo $(expr 10 \* 20) # 使用expr进行乘法运算时必须使用\进行转义
# 200
</code></pre>
<blockquote>
<p>使用expr表示方法时,表达式和运算符之间必须有空格。</p>
</blockquote>
<h3>6.2.2. <code>$[]</code></h3>
<pre><code class="language-shell">echo $[10%3]
# 1
</code></pre>
<h3>6.2.3. <code>$(())</code></h3>
<pre><code class="language-shell">echo $((10*20))
# 200
</code></pre>
<h2>6.3. 关系运算符</h2>
<p>最常见的关系运算符是:<code>==,!=,&lt;,&gt;,&gt;=,&lt;=</code></p>
<pre><code class="language-shell">echo $[10==10]
# 1
flag=$[20==10]
echo $flag
# 1
echo $[10&gt;=10]
# 1
</code></pre>
<p>如下关系运算符只能使用在条件表达式<code>if、while</code>下,类似<code>flag=[ $a -eq $b ]</code>的直接赋值语句是非法的。关系运算符的条件表达式要放在<strong>一对</strong>方括号中,并且中间需要有空格。也可以使用<code>(())</code>替代<code>[]</code>,此时<code>-eq,-lt,-le</code>之类的需要使用<code>==,&lt;,&lt;=</code>等替换。</p>
<blockquote>
<p><code>[]</code>搭配<code>-eq -ne</code>等使用,<code>(())</code>搭配<code>|| &amp;&amp;</code>等使用。</p>
</blockquote>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>-eq</code></td>
<td>检测两个数是否相等,相等返回true。</td>
<td><code>[ $a -eq $b ]</code></td>
</tr>
<tr>
<td><code>-ne</code></td>
<td>检测两个数是否不相等,不相等返回 true。</td>
<td><code>[ $a -ne $b ]</code></td>
</tr>
<tr>
<td><code>-gt</code></td>
<td>检测左边的数是否大于右边的,如果是,则返回 true。</td>
<td><code>[ $a -gt $b ]</code></td>
</tr>
<tr>
<td><code>-lt</code></td>
<td>检测左边的数是否小于右边的,如果是,则返回 true。</td>
<td><code>[ $a -lt $b ]</code></td>
</tr>
<tr>
<td><code>-ge</code></td>
<td>检测左边的数是否大于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -ge $b ]</code></td>
</tr>
<tr>
<td><code>-le</code></td>
<td>检测左边的数是否小于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -le $b ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ 1 -eq 1 ];then echo &#39;hello&#39;;fi;
# hello
if ((10&gt;=10));then echo &#39;hello&#39;;fi;
# hello
</code></pre>
<h2>6.4. 布尔、逻辑运算符</h2>
<p>布尔、逻辑运算的条件表达式也要放在一对方括号中<code>[]</code>。</p>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>!</code></td>
<td>非运算,表达式为true则返回false,否则返回true。</td>
<td><code>[ ! 10 -eq 0 ]</code></td>
</tr>
<tr>
<td><code>-o</code></td>
<td>或运算,有一个表达式为true则返回true。</td>
<td><code>[ 10 -lt 20 -o 10 -gt 100 ]</code></td>
</tr>
<tr>
<td><code>-a</code></td>
<td>与运算,两个表达式都为true才返回true。</td>
<td><code>[ 10 -lt 20 -a 10 -gt 100 ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ ! 10 -eq 0 ];then echo &#39;hello&#39;;fi
# hello
if [ 10 -ge 10 -a 10 -ge 10 ];then echo &#39;hello&#39;;fi
# hello
if [ 10 -ge 20 -o 10 -ge 0 ];then echo &#39;hello&#39;;fi
# hello
</code></pre>
<p> <code>-o</code>也可以使用<code>||</code>替代,<code>-a</code>也可以使用<code>&amp;&amp;</code>替代,此时需要使用<code>(())</code>或<code>[[]]</code>替代<code>[]</code>。</p>
<pre><code class="language-shell">if &lt;a href=&quot;1010-55.html&quot; class=&quot;internal-link&quot;&gt; 10==10 &amp;&amp; 5==5 &lt;/a&gt;;then echo &#39;hello&#39;;fi
# hello
if ((10==10 &amp;&amp; 5==5));then echo &#39;hello&#39;;fi
# hello
</code></pre>
<h1>7. 传递参数</h1>
<p>在执行 <code>Shell</code>脚本时,向脚本传递参数,脚本内获取参数的格式为:<code>$n</code>。<code>n</code>代表一个数字,<code>1</code>为执行脚本的第一个参数,<code>2</code>为执行脚本的第二个参数,<code>$0</code>为执行的文件名。在为<code>shell</code>脚本传递的参数中如果包含空格,应该使用单引号或者双引号将该参数括起来,以便于脚本将这个参数作为整体来接收。另外,还有几个特殊字符用来处理参数:</p>
<table>
<thead>
<tr>
<th>参数处理</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>$#</code></td>
<td>传递到脚本的参数个数</td>
</tr>
<tr>
<td><code>$*</code></td>
<td>以一个单字符串显示所有向脚本传递的参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$$</code></td>
<td>脚本运行的当前进程ID号</td>
</tr>
<tr>
<td><code>$!</code></td>
<td>后台运行的最后一个进程的ID号</td>
</tr>
<tr>
<td><code>$@</code></td>
<td>与<code>$*</code>相同,但是使用时加引号,并在引号中返回每个参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$-</code></td>
<td>显示Shell使用的当前选项,与set功能相同。</td>
</tr>
<tr>
<td><code>$?</code></td>
<td>显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。</td>
</tr>
</tbody></table>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-bash">set -e
echo &quot;执行的文件名:$0&quot;
echo &quot;参数个数为$#&quot;
echo &quot;第一个参数为:$1&quot;
echo &quot;第二个参数为:$2&quot;
echo &quot;所有参数为:$@&quot;
echo &quot;进程ID号为:$$&quot;
echo &quot;当前shell选项为$-&quot;
echo &quot;上一个命令退出的状态为$?&quot;
</code></pre>
<p>执行结果如下:</p>
<pre><code class="language-shell">$ sh test.sh param1 &quot;param2 with space&quot;
执行的文件名:test.sh
参数个数为2
第一个参数为:param1
第二个参数为:param2 with space
所有参数为:param1 param2 with space
进程ID号为:3700
当前shell选项为ehB
上一个命令退出的状态为0
</code></pre>
<h1>8. 函数</h1>
<p>函数定义通过<code>function_name(){}</code>的形式定义,函数返回值可以显示用return返回,如果不加,将以最后一条命令的运行结果作为返回值,函数返回值只能是数字。函数也可以传递参数,但是函数定义的()中不需要申明。</p>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-shell">sayhello(){
echo &quot;hello&quot;
}
# 注意函数调用只需要函数名,不需要加()
sayhello
sayhellowithparam(){
echo &quot;hello, $1 $2 $3&quot;
return 1
}
sayhellowithparam zhangsan lisi wangwu
echo $?
</code></pre>
<p>输出如下:</p>
<blockquote>
<p>hello<br>hello, zhangsan lisi wangwu<br>1</p>
</blockquote>
<h1>9. 命令替换</h1>
<p>命令替换可以将一个命令的输出作为另外一个命令的参数。</p>
<pre><code class="language-shell"># command1 `command2`
cd `pwd` # 该命令将pwd命令列出的目录作为cd命令的参数,结果仍然是停留在当前目录下
cd `echo $HOME` # 将echo的输出作为cd的参数,即打开用户根目录
</code></pre>
<h1>10. let命令</h1>
<p>let 命令是 BASH 中用于计算的工具,用于执行一个或多个表达式,变量计算中不需要加上 $ 来表示变量。如果表达式中包含了空格或其他特殊字符,则必须引起来。</p>
<ul>
<li>自加操作:<code>let no++</code></li>
<li>自减操作:<code>let no--</code></li>
<li>简写形式 <code>let no+=10</code>,<code>let no-=20</code>,分别等同于<code>let no=no+10</code>,<code>let no=no-20</code></li>
</ul>
<h1>11. 流程控制</h1>
<h2>11.1. if</h2>
<pre><code class="language-shell">if ((10&lt;2));then
echo &quot;10小于2&quot;
elif ((10&gt;20));then
echo &quot;a大于10&quot;
else
echo &quot;10大于2且小于10&quot;
fi
</code></pre>
<h2>11.2. case</h2>
<p><code>case</code>每一种情况以右括号结尾,执行到<code>;;</code>结束</p>
<pre><code class="language-shell">case 10 in
0|1)
echo &quot;a为0或1&quot;
;;
11|12)
echo &quot;a为11或12&quot;
;;
*)
# *用来匹配所有情况
echo &quot;a为10&quot;
;;
esac
</code></pre>
<h2>11.3. while</h2>
<pre><code class="language-shell">count=0
while(($count&lt;5))
do
echo $count
let count++
done
</code></pre>
<h2>11.4. util</h2>
<pre><code class="language-shell">count=0
until(($count&gt;=5))
do
echo $count
let count++
done
</code></pre>
<h2>11.5. for</h2>
<pre><code class="language-shell"># for写法1
for ((count=0;$count&lt;5;count=$count+1))
do
echo $count
done
# for写法2
arr=(0 1 2 3 4)
for count in ${arr[*]}
do
echo $int
done
# for写法3
for int in 0 1 2 3 4
do
echo $int
done
</code></pre>
<h2>11.6. break和continue</h2>
<p>用法与一般编程语言类似,break跳出循环,continue跳出当前循环</p>
<pre><code class="language-shell">for ((count=0;$count&gt;=0;count=$count+1))
do
if (($count&gt;=5));then
break;
fi
echo $count
done
</code></pre>
<h1>12. 输入输出重定向</h1>
<h2>12.1. 输出重定向</h2>
<p><code>command &gt; file</code>将命令输出结果保存的file文件中。<code>&gt;</code>从文件头开始写,会覆盖旧内容,<code>&gt;&gt;</code>将内容追加到文件末尾</p>
<pre><code class="language-shell"># 将who命令的输出保存的users文件中,可以通过cat users查看
who &gt; users
# 将字符串hello world保存到text.txt文件中
echo &quot;hello world&quot; &gt; text.txt
</code></pre>
<h2>12.2. 输入重定向</h2>
<p><code>command &lt; file</code>从file文件获取输入</p>
<pre><code class="language-shell">wc -l /etc/passwd
# 123 /etc/passwd
wc -l &lt; users
# 123
# 第一个例子,会输出文件名;第二个不会,因为它仅仅知道从标准输入读取内容
# command &lt; infile &gt; outfile, 同时替换输入和输出,执行command,从文件infile读取内容,然后将输出写入到outfile中。
wc -l &lt; /etc/passwd &gt; result
cat result
# 123
</code></pre>
<h2>12.3. 文件描述符</h2>
<p>一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件</p>
<ul>
<li>标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。</li>
<li>标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。</li>
<li>标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。</li>
</ul>
<pre><code class="language-shell"># 将标准错误输出重定向到error_trace
cat /tmp/fake_file 2&gt;error_trace
cat error_trace
# cat: /tmp/fake_fule: No such file or directory
# 将标准输出和标准错误输出都重定向到result
cat /tmp/fake_file &amp;&gt;result
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准错误重定向到标准输出
ls /tmp/fake_file &gt; result 2&gt;&amp;1
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准输入重定向到result,将标准错误输出重定向到error_trace
cat /tmp/fake_file 1&gt;result 2&gt;error_trace
</code></pre>
<h2>12.4. Here Document</h2>
<p>将两个<code>EOF</code>之间的内容(document) 作为输入传递给<code>command</code></p>
<pre><code class="language-bash"># command &lt;&lt; EOF
# document
# EOF
cat &lt;&lt; EOF
hello
shinerio
learn shell
EOF
</code></pre>
<blockquote>
<p>结尾的<code>EOF</code>一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和<code>tab</code>缩进。开始的<code>EOF</code>前后的空格会被忽略掉。</p>
</blockquote>
<h2>12.5. /dev/null</h2>
<p>如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null。<code>command &gt; /dev/null</code></p>
<pre><code class="language-shell">cat users &gt; /dev/null
cat users &gt; /dev/null 2&gt;&amp;1
</code></pre>
<h1>13. set命令</h1>
<p>set指令能设置所使用shell的执行方式,可依照不同的需求来做设置。以下只列出常用的选项参数:</p>
<ul>
<li>-e 若指令传回值不等于0,则立即退出shell。</li>
<li>-f 取消使用通配符。</li>
<li>-n 只读取指令,而不实际执行。</li>
<li>-x 执行指令后,会先显示该指令及所下的参数。</li>
</ul>
#39;hello' ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ 'hello' = 'hello' ];then echo 'hello';fi
# hello
if [ 'hello' != 'ello' ];then echo 'hello';fi
# hello
if [ -z '' ];then echo 'hello';fi
# hello
if [ -n 'hello' ];then echo 'hello';fi
# hello
if [ <p>本文主要介绍shell编程的基本语法以及实际应用中的常见命令。</p>
<h1>1. 注释</h1>
<h2>1.1. 单行注释</h2>
<pre><code class="language-shell"># 这是单行注释
</code></pre>
<h2>1.2. 多行注释</h2>
<pre><code class="language-shell">:&lt;&lt;EOF
多行注释内容
多行注释内容
多行注释内容
EOF
</code></pre>
<p>多行注释<code>EOF</code>也可替换成<code>!</code>或<code>&#39;</code></p>
<pre><code class="language-shell">:&lt;&lt;&#39;
多行注释内容
多行注释内容
多行注释内容
&#39;
:&lt;&lt;!
多行注释内容
多行注释内容
多行注释内容
!
</code></pre>
<h1>2. 变量</h1>
<h2>2.1. 变量定义</h2>
<p>使用<code>VARIABLENAME=VALUE</code>的形式,VALUE如果是字符串的话,可以使用单引号、双引号或者不加引号。单引号内的任何字符都会原样输出,不能进行转义,单引号内不能单独出现一个单引号,但可成对出现,作为字符串拼接使用。双引号内可以有变量,可以出现转义字符。</p>
<h2>2.2. 变量使用</h2>
<p>只需要在变量前加<code>$</code>符号,变量加<code>{}</code>是可选的,方便解释器识别边界。将变量加上<code>{}</code>是一个好习惯,不容易出错。</p>
<pre><code class="language-shell">your_age=25
your_name=&quot;shinerio&quot;
your_name=shinerio
your_name=&#39;shinerio&#39;
echo $your_age # 输出25
echo $your_name # 输出shinerio
echo &quot;${your_name}hello&quot; &lt;span class=&quot;tag&quot;&gt;#这里&lt;/span&gt;{}必须添加,否则解释器认为是${your_namehello}
str=&#39;hello&#39;&#39; # 非法
str=&#39;hello&#39;__&#39;world&#39; # 成对出现的单引号做字符拼接
echo $str &lt;span class=&quot;tag&quot;&gt;#输出hello__world&lt;/span&gt;
str1=&#39;helloworld${your_age}\nnew line&#39;
str2=&quot;helloworld${your_age}\nnew line&quot;
echo $str1 # 输出helloworld${your_age}\nnew line
echo $str2 # 输出helloworld25\nnew line
echo -e $str2 # -e开启转义 \n表示换行 echo默认换行,通过\c强制不换行
&lt;span class=&quot;tag&quot;&gt;#helloworld25&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;#new&lt;/span&gt; line
</code></pre>
<h2>2.3. 只读变量</h2>
<p>使用<code>readonly VARIABLENAME</code>设置变量只读,只读变量的值不能更改</p>
<pre><code class="language-shell">readonly name=&#39;jack&#39;
name=&#39;kelly&#39;
zsh: read-only variable: name
</code></pre>
<h2>2.4. 删除变量</h2>
<p>使用<code>unset VARIABLENAME</code>删除变量。</p>
<h1>3. 字符串操作</h1>
<h2>3.1. 字符串拼接</h2>
<pre><code class="language-shell">str1=&quot;hello&quot;${your_name}&quot;world&quot;
str2=&quot;hello${your_name}world&quot;
str3=&#39;hello&#39;${your_name}&#39;world&#39;
</code></pre>
<h2>3.2. 字符串长度</h2>
<pre><code class="language-shell">str=&#39;hello&#39;
echo ${&lt;span class=&quot;tag&quot;&gt;#str&lt;/span&gt;}
5
</code></pre>
<h2>3.3. 字符串截取</h2>
<p><code>${string:start:length}</code>,索引从0开始,从start(包含)开始截取共计length长度的字符。</p>
<pre><code class="language-shell">str=&#39;helloworld&#39;
echo ${str:0:5}
hello
</code></pre>
<h2>3.4. 字符串运算符</h2>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>=</code></td>
<td>检测两个字符串是否相等,相等返回true</td>
<td><code>[ &#39;hello&#39; = &#39;hello&#39; ]</code></td>
</tr>
<tr>
<td><code>!=</code></td>
<td>检测两个字符串是否相等,不相等返回true</td>
<td><code>[ &#39;hello&#39; != &#39;ello&#39; ]</code></td>
</tr>
<tr>
<td><code>-z</code></td>
<td>检测字符串长度是否为0,为0返回true</td>
<td><code>[ -z &#39;&#39; ]</code></td>
</tr>
<tr>
<td><code>-n </code></td>
<td>检测字符串长度是否不为0,不为0返回true</td>
<td><code>[ -n &#39;hello&#39; ]</code></td>
</tr>
<tr>
<td><code>$</code></td>
<td>检测字符串是否为空,不为空返回true</td>
<td><code>[ $&#39;hello&#39; ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ &#39;hello&#39; = &#39;hello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ &#39;hello&#39; != &#39;ello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ -z &#39;&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ -n &#39;hello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ $&#39;hello&#39; ];then echo &#39;hello&#39;;fi
str=&#39;hello&#39;
if [ $str ];then echo &#39;hello&#39;;fi
# hello
</code></pre>
<p>注意字符串的等值判断是一个等号<code>&quot;=&quot;</code>,与下文要讲的逻辑运算符使用两个等号<code>&quot;==&quot;</code>做等值判断不一样。</p>
<h1>4. 文件测试运算符</h1>
<table>
<thead>
<tr>
<th>操作符</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>-b file</code></td>
<td>检测文件是否是块设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-c file</code></td>
<td>检测文件是否是字符设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-d file</code></td>
<td>检测文件是否是目录,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-f file</code></td>
<td>检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-g file</code></td>
<td>检测文件是否设置了<code>SGID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-k file</code></td>
<td>检测文件是否设置了粘着位(Sticky Bit),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-p file</code></td>
<td>检测文件是否是有名管道,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-u file</code></td>
<td>检测文件是否设置了<code>SUID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-r file</code></td>
<td>检测文件是否可读,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-w file</code></td>
<td>检测文件是否可写,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-x file</code></td>
<td>检测文件是否可执行,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-s file</code></td>
<td>检测文件是否为空(文件大小是否大于0),不为空返回true。</td>
</tr>
<tr>
<td><code>-e file</code></td>
<td>检测文件(包括目录)是否存在,如果是,则返回true。</td>
</tr>
</tbody></table>
<pre><code class="language-shell">if &lt;a href=&quot;f-home.html&quot; class=&quot;internal-link&quot;&gt; -f &#39;/home&#39; &lt;/a&gt;;then echo &#39;directory&#39;;else echo &#39;file&#39;;fi
# file
if &lt;a href=&quot;d-home.html&quot; class=&quot;internal-link&quot;&gt; -d &#39;/home&#39; &lt;/a&gt;;then echo &#39;directory&#39;;else echo &#39;file&#39;;fi
# directory
if &lt;a href=&quot;e-tmpfake-file.html&quot; class=&quot;internal-link&quot;&gt; -e &#39;/tmp/fake_file&#39; &lt;/a&gt;;then echo &#39;exist&#39;;else echo &#39;not exist&#39;;fi
# not exist
</code></pre>
<h1>5. 数组</h1>
<p><code>shell</code>只支持一维数组,用括号表示,元素通过空格分隔,形如<code>数组名=(值1 值2 ... 值n)</code>。<code>shell</code>数组下标从<code>1</code>开始。</p>
<ul>
<li><code>${数组名[下标]}</code>,读取指索引位置数组元素</li>
<li>使用<code>@</code>或<code>*</code>代替下标,获取数组中所有元素。</li>
<li>使用<code>{&lt;span class=&quot;tag&quot;&gt;#数组名&lt;/span&gt;[@]}</code>或<code>{&lt;span class=&quot;tag&quot;&gt;#数组名&lt;/span&gt;[*]}</code>获取数组元素个数。</li>
</ul>
<pre><code class="language-shell">arr=(value1 value2 value3 value4)
echo ${arr[3]}
# value3
echo ${arr[*]}
# value1 value2 value3 value4
echo ${arr[@]}
# value1 value2 value3 value4
arr[3]=&#39;new_value3&#39;
echo $arr[3]
# new_value3
echo ${&lt;span class=&quot;tag&quot;&gt;#arr&lt;/span&gt;[@]}
# 4
echo &quot;arr[1]的长度为:${&lt;span class=&quot;tag&quot;&gt;#arr&lt;/span&gt;[1]}&quot;
# arr[1]的长度为:6
</code></pre>
<h1>6. 运算符</h1>
<h2>6.1. 赋值运算符</h2>
<pre><code class="language-shell">a=10
b=$a
</code></pre>
<h2>6.2. 算术运算符</h2>
<p>算数运算符支持<code>+,-,*,/,%</code></p>
<h3>6.2.1. expr表示法</h3>
<pre><code class="language-shell">echo `expr 10 + 20`
# 30
echo $(expr 20 / 2)
# 10
echo $(expr 10 \* 20) # 使用expr进行乘法运算时必须使用\进行转义
# 200
</code></pre>
<blockquote>
<p>使用expr表示方法时,表达式和运算符之间必须有空格。</p>
</blockquote>
<h3>6.2.2. <code>$[]</code></h3>
<pre><code class="language-shell">echo $[10%3]
# 1
</code></pre>
<h3>6.2.3. <code>$(())</code></h3>
<pre><code class="language-shell">echo $((10*20))
# 200
</code></pre>
<h2>6.3. 关系运算符</h2>
<p>最常见的关系运算符是:<code>==,!=,&lt;,&gt;,&gt;=,&lt;=</code></p>
<pre><code class="language-shell">echo $[10==10]
# 1
flag=$[20==10]
echo $flag
# 1
echo $[10&gt;=10]
# 1
</code></pre>
<p>如下关系运算符只能使用在条件表达式<code>if、while</code>下,类似<code>flag=[ $a -eq $b ]</code>的直接赋值语句是非法的。关系运算符的条件表达式要放在<strong>一对</strong>方括号中,并且中间需要有空格。也可以使用<code>(())</code>替代<code>[]</code>,此时<code>-eq,-lt,-le</code>之类的需要使用<code>==,&lt;,&lt;=</code>等替换。</p>
<blockquote>
<p><code>[]</code>搭配<code>-eq -ne</code>等使用,<code>(())</code>搭配<code>|| &amp;&amp;</code>等使用。</p>
</blockquote>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>-eq</code></td>
<td>检测两个数是否相等,相等返回true。</td>
<td><code>[ $a -eq $b ]</code></td>
</tr>
<tr>
<td><code>-ne</code></td>
<td>检测两个数是否不相等,不相等返回 true。</td>
<td><code>[ $a -ne $b ]</code></td>
</tr>
<tr>
<td><code>-gt</code></td>
<td>检测左边的数是否大于右边的,如果是,则返回 true。</td>
<td><code>[ $a -gt $b ]</code></td>
</tr>
<tr>
<td><code>-lt</code></td>
<td>检测左边的数是否小于右边的,如果是,则返回 true。</td>
<td><code>[ $a -lt $b ]</code></td>
</tr>
<tr>
<td><code>-ge</code></td>
<td>检测左边的数是否大于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -ge $b ]</code></td>
</tr>
<tr>
<td><code>-le</code></td>
<td>检测左边的数是否小于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -le $b ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ 1 -eq 1 ];then echo &#39;hello&#39;;fi;
# hello
if ((10&gt;=10));then echo &#39;hello&#39;;fi;
# hello
</code></pre>
<h2>6.4. 布尔、逻辑运算符</h2>
<p>布尔、逻辑运算的条件表达式也要放在一对方括号中<code>[]</code>。</p>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>!</code></td>
<td>非运算,表达式为true则返回false,否则返回true。</td>
<td><code>[ ! 10 -eq 0 ]</code></td>
</tr>
<tr>
<td><code>-o</code></td>
<td>或运算,有一个表达式为true则返回true。</td>
<td><code>[ 10 -lt 20 -o 10 -gt 100 ]</code></td>
</tr>
<tr>
<td><code>-a</code></td>
<td>与运算,两个表达式都为true才返回true。</td>
<td><code>[ 10 -lt 20 -a 10 -gt 100 ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ ! 10 -eq 0 ];then echo &#39;hello&#39;;fi
# hello
if [ 10 -ge 10 -a 10 -ge 10 ];then echo &#39;hello&#39;;fi
# hello
if [ 10 -ge 20 -o 10 -ge 0 ];then echo &#39;hello&#39;;fi
# hello
</code></pre>
<p> <code>-o</code>也可以使用<code>||</code>替代,<code>-a</code>也可以使用<code>&amp;&amp;</code>替代,此时需要使用<code>(())</code>或<code>[[]]</code>替代<code>[]</code>。</p>
<pre><code class="language-shell">if &lt;a href=&quot;1010-55.html&quot; class=&quot;internal-link&quot;&gt; 10==10 &amp;&amp; 5==5 &lt;/a&gt;;then echo &#39;hello&#39;;fi
# hello
if ((10==10 &amp;&amp; 5==5));then echo &#39;hello&#39;;fi
# hello
</code></pre>
<h1>7. 传递参数</h1>
<p>在执行 <code>Shell</code>脚本时,向脚本传递参数,脚本内获取参数的格式为:<code>$n</code>。<code>n</code>代表一个数字,<code>1</code>为执行脚本的第一个参数,<code>2</code>为执行脚本的第二个参数,<code>$0</code>为执行的文件名。在为<code>shell</code>脚本传递的参数中如果包含空格,应该使用单引号或者双引号将该参数括起来,以便于脚本将这个参数作为整体来接收。另外,还有几个特殊字符用来处理参数:</p>
<table>
<thead>
<tr>
<th>参数处理</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>$#</code></td>
<td>传递到脚本的参数个数</td>
</tr>
<tr>
<td><code>$*</code></td>
<td>以一个单字符串显示所有向脚本传递的参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$$</code></td>
<td>脚本运行的当前进程ID号</td>
</tr>
<tr>
<td><code>$!</code></td>
<td>后台运行的最后一个进程的ID号</td>
</tr>
<tr>
<td><code>$@</code></td>
<td>与<code>$*</code>相同,但是使用时加引号,并在引号中返回每个参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$-</code></td>
<td>显示Shell使用的当前选项,与set功能相同。</td>
</tr>
<tr>
<td><code>$?</code></td>
<td>显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。</td>
</tr>
</tbody></table>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-bash">set -e
echo &quot;执行的文件名:$0&quot;
echo &quot;参数个数为$#&quot;
echo &quot;第一个参数为:$1&quot;
echo &quot;第二个参数为:$2&quot;
echo &quot;所有参数为:$@&quot;
echo &quot;进程ID号为:$$&quot;
echo &quot;当前shell选项为$-&quot;
echo &quot;上一个命令退出的状态为$?&quot;
</code></pre>
<p>执行结果如下:</p>
<pre><code class="language-shell">$ sh test.sh param1 &quot;param2 with space&quot;
执行的文件名:test.sh
参数个数为2
第一个参数为:param1
第二个参数为:param2 with space
所有参数为:param1 param2 with space
进程ID号为:3700
当前shell选项为ehB
上一个命令退出的状态为0
</code></pre>
<h1>8. 函数</h1>
<p>函数定义通过<code>function_name(){}</code>的形式定义,函数返回值可以显示用return返回,如果不加,将以最后一条命令的运行结果作为返回值,函数返回值只能是数字。函数也可以传递参数,但是函数定义的()中不需要申明。</p>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-shell">sayhello(){
echo &quot;hello&quot;
}
# 注意函数调用只需要函数名,不需要加()
sayhello
sayhellowithparam(){
echo &quot;hello, $1 $2 $3&quot;
return 1
}
sayhellowithparam zhangsan lisi wangwu
echo $?
</code></pre>
<p>输出如下:</p>
<blockquote>
<p>hello<br>hello, zhangsan lisi wangwu<br>1</p>
</blockquote>
<h1>9. 命令替换</h1>
<p>命令替换可以将一个命令的输出作为另外一个命令的参数。</p>
<pre><code class="language-shell"># command1 `command2`
cd `pwd` # 该命令将pwd命令列出的目录作为cd命令的参数,结果仍然是停留在当前目录下
cd `echo $HOME` # 将echo的输出作为cd的参数,即打开用户根目录
</code></pre>
<h1>10. let命令</h1>
<p>let 命令是 BASH 中用于计算的工具,用于执行一个或多个表达式,变量计算中不需要加上 $ 来表示变量。如果表达式中包含了空格或其他特殊字符,则必须引起来。</p>
<ul>
<li>自加操作:<code>let no++</code></li>
<li>自减操作:<code>let no--</code></li>
<li>简写形式 <code>let no+=10</code>,<code>let no-=20</code>,分别等同于<code>let no=no+10</code>,<code>let no=no-20</code></li>
</ul>
<h1>11. 流程控制</h1>
<h2>11.1. if</h2>
<pre><code class="language-shell">if ((10&lt;2));then
echo &quot;10小于2&quot;
elif ((10&gt;20));then
echo &quot;a大于10&quot;
else
echo &quot;10大于2且小于10&quot;
fi
</code></pre>
<h2>11.2. case</h2>
<p><code>case</code>每一种情况以右括号结尾,执行到<code>;;</code>结束</p>
<pre><code class="language-shell">case 10 in
0|1)
echo &quot;a为0或1&quot;
;;
11|12)
echo &quot;a为11或12&quot;
;;
*)
# *用来匹配所有情况
echo &quot;a为10&quot;
;;
esac
</code></pre>
<h2>11.3. while</h2>
<pre><code class="language-shell">count=0
while(($count&lt;5))
do
echo $count
let count++
done
</code></pre>
<h2>11.4. util</h2>
<pre><code class="language-shell">count=0
until(($count&gt;=5))
do
echo $count
let count++
done
</code></pre>
<h2>11.5. for</h2>
<pre><code class="language-shell"># for写法1
for ((count=0;$count&lt;5;count=$count+1))
do
echo $count
done
# for写法2
arr=(0 1 2 3 4)
for count in ${arr[*]}
do
echo $int
done
# for写法3
for int in 0 1 2 3 4
do
echo $int
done
</code></pre>
<h2>11.6. break和continue</h2>
<p>用法与一般编程语言类似,break跳出循环,continue跳出当前循环</p>
<pre><code class="language-shell">for ((count=0;$count&gt;=0;count=$count+1))
do
if (($count&gt;=5));then
break;
fi
echo $count
done
</code></pre>
<h1>12. 输入输出重定向</h1>
<h2>12.1. 输出重定向</h2>
<p><code>command &gt; file</code>将命令输出结果保存的file文件中。<code>&gt;</code>从文件头开始写,会覆盖旧内容,<code>&gt;&gt;</code>将内容追加到文件末尾</p>
<pre><code class="language-shell"># 将who命令的输出保存的users文件中,可以通过cat users查看
who &gt; users
# 将字符串hello world保存到text.txt文件中
echo &quot;hello world&quot; &gt; text.txt
</code></pre>
<h2>12.2. 输入重定向</h2>
<p><code>command &lt; file</code>从file文件获取输入</p>
<pre><code class="language-shell">wc -l /etc/passwd
# 123 /etc/passwd
wc -l &lt; users
# 123
# 第一个例子,会输出文件名;第二个不会,因为它仅仅知道从标准输入读取内容
# command &lt; infile &gt; outfile, 同时替换输入和输出,执行command,从文件infile读取内容,然后将输出写入到outfile中。
wc -l &lt; /etc/passwd &gt; result
cat result
# 123
</code></pre>
<h2>12.3. 文件描述符</h2>
<p>一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件</p>
<ul>
<li>标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。</li>
<li>标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。</li>
<li>标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。</li>
</ul>
<pre><code class="language-shell"># 将标准错误输出重定向到error_trace
cat /tmp/fake_file 2&gt;error_trace
cat error_trace
# cat: /tmp/fake_fule: No such file or directory
# 将标准输出和标准错误输出都重定向到result
cat /tmp/fake_file &amp;&gt;result
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准错误重定向到标准输出
ls /tmp/fake_file &gt; result 2&gt;&amp;1
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准输入重定向到result,将标准错误输出重定向到error_trace
cat /tmp/fake_file 1&gt;result 2&gt;error_trace
</code></pre>
<h2>12.4. Here Document</h2>
<p>将两个<code>EOF</code>之间的内容(document) 作为输入传递给<code>command</code></p>
<pre><code class="language-bash"># command &lt;&lt; EOF
# document
# EOF
cat &lt;&lt; EOF
hello
shinerio
learn shell
EOF
</code></pre>
<blockquote>
<p>结尾的<code>EOF</code>一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和<code>tab</code>缩进。开始的<code>EOF</code>前后的空格会被忽略掉。</p>
</blockquote>
<h2>12.5. /dev/null</h2>
<p>如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null。<code>command &gt; /dev/null</code></p>
<pre><code class="language-shell">cat users &gt; /dev/null
cat users &gt; /dev/null 2&gt;&amp;1
</code></pre>
<h1>13. set命令</h1>
<p>set指令能设置所使用shell的执行方式,可依照不同的需求来做设置。以下只列出常用的选项参数:</p>
<ul>
<li>-e 若指令传回值不等于0,则立即退出shell。</li>
<li>-f 取消使用通配符。</li>
<li>-n 只读取指令,而不实际执行。</li>
<li>-x 执行指令后,会先显示该指令及所下的参数。</li>
</ul>
#39;hello' ];then echo 'hello';fi
str='hello'
if [ $str ];then echo 'hello';fi
# hello
</code></pre>
<p>注意字符串的等值判断是一个等号<code>"="</code>,与下文要讲的逻辑运算符使用两个等号<code>"=="</code>做等值判断不一样。</p>
<h1>4. 文件测试运算符</h1>
<table>
<thead>
<tr>
<th>操作符</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>-b file</code></td>
<td>检测文件是否是块设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-c file</code></td>
<td>检测文件是否是字符设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-d file</code></td>
<td>检测文件是否是目录,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-f file</code></td>
<td>检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-g file</code></td>
<td>检测文件是否设置了<code>SGID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-k file</code></td>
<td>检测文件是否设置了粘着位(Sticky Bit),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-p file</code></td>
<td>检测文件是否是有名管道,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-u file</code></td>
<td>检测文件是否设置了<code>SUID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-r file</code></td>
<td>检测文件是否可读,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-w file</code></td>
<td>检测文件是否可写,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-x file</code></td>
<td>检测文件是否可执行,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-s file</code></td>
<td>检测文件是否为空(文件大小是否大于0),不为空返回true。</td>
</tr>
<tr>
<td><code>-e file</code></td>
<td>检测文件(包括目录)是否存在,如果是,则返回true。</td>
</tr>
</tbody></table>
<pre><code class="language-shell">if <a href="f-home.html" class="internal-link"> -f '/home' </a>;then echo 'directory';else echo 'file';fi
# file
if <a href="d-home.html" class="internal-link"> -d '/home' </a>;then echo 'directory';else echo 'file';fi
# directory
if <a href="e-tmpfake-file.html" class="internal-link"> -e '/tmp/fake_file' </a>;then echo 'exist';else echo 'not exist';fi
# not exist
</code></pre>
<h1>5. 数组</h1>
<p><code>shell</code>只支持一维数组,用括号表示,元素通过空格分隔,形如<code>数组名=(值1 值2 ... 值n)</code>。<code>shell</code>数组下标从<code>1</code>开始。</p>
<ul>
<li><code>${数组名[下标]}</code>,读取指索引位置数组元素</li>
<li>使用<code>@</code>或<code>*</code>代替下标,获取数组中所有元素。</li>
<li>使用<code>{<span class="tag">#数组名</span>[@]}</code>或<code>{<span class="tag">#数组名</span>[*]}</code>获取数组元素个数。</li>
</ul>
<pre><code class="language-shell">arr=(value1 value2 value3 value4)
echo ${arr[3]}
# value3
echo ${arr[*]}
# value1 value2 value3 value4
echo ${arr[@]}
# value1 value2 value3 value4
arr[3]='new_value3'
echo $arr[3]
# new_value3
echo ${<span class="tag">#arr</span>[@]}
# 4
echo "arr[1]的长度为:${<span class="tag">#arr</span>[1]}"
# arr[1]的长度为:6
</code></pre>
<h1>6. 运算符</h1>
<h2>6.1. 赋值运算符</h2>
<pre><code class="language-shell">a=10
b=$a
</code></pre>
<h2>6.2. 算术运算符</h2>
<p>算数运算符支持<code>+,-,*,/,%</code></p>
<h3>6.2.1. expr表示法</h3>
<pre><code class="language-shell">echo `expr 10 + 20`
# 30
echo $(expr 20 / 2)
# 10
echo $(expr 10 \* 20) # 使用expr进行乘法运算时必须使用\进行转义
# 200
</code></pre>
<blockquote>
<p>使用expr表示方法时,表达式和运算符之间必须有空格。</p>
</blockquote>
<h3>6.2.2. <code>$[]</code></h3>
<pre><code class="language-shell">echo $[10%3]
# 1
</code></pre>
<h3>6.2.3. <code>$(())</code></h3>
<pre><code class="language-shell">echo $((10*20))
# 200
</code></pre>
<h2>6.3. 关系运算符</h2>
<p>最常见的关系运算符是:<code>==,!=,<,>,>=,<=</code></p>
<pre><code class="language-shell">echo $[10==10]
# 1
flag=$[20==10]
echo $flag
# 1
echo $[10>=10]
# 1
</code></pre>
<p>如下关系运算符只能使用在条件表达式<code>if、while</code>下,类似<code>flag=[ $a -eq $b ]</code>的直接赋值语句是非法的。关系运算符的条件表达式要放在<strong>一对</strong>方括号中,并且中间需要有空格。也可以使用<code>(())</code>替代<code>[]</code>,此时<code>-eq,-lt,-le</code>之类的需要使用<code>==,<,<=</code>等替换。</p>
<blockquote>
<p><code>[]</code>搭配<code>-eq -ne</code>等使用,<code>(())</code>搭配<code>|| &&</code>等使用。</p>
</blockquote>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>-eq</code></td>
<td>检测两个数是否相等,相等返回true。</td>
<td><code>[ $a -eq $b ]</code></td>
</tr>
<tr>
<td><code>-ne</code></td>
<td>检测两个数是否不相等,不相等返回 true。</td>
<td><code>[ $a -ne $b ]</code></td>
</tr>
<tr>
<td><code>-gt</code></td>
<td>检测左边的数是否大于右边的,如果是,则返回 true。</td>
<td><code>[ $a -gt $b ]</code></td>
</tr>
<tr>
<td><code>-lt</code></td>
<td>检测左边的数是否小于右边的,如果是,则返回 true。</td>
<td><code>[ $a -lt $b ]</code></td>
</tr>
<tr>
<td><code>-ge</code></td>
<td>检测左边的数是否大于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -ge $b ]</code></td>
</tr>
<tr>
<td><code>-le</code></td>
<td>检测左边的数是否小于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -le $b ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ 1 -eq 1 ];then echo 'hello';fi;
# hello
if ((10>=10));then echo 'hello';fi;
# hello
</code></pre>
<h2>6.4. 布尔、逻辑运算符</h2>
<p>布尔、逻辑运算的条件表达式也要放在一对方括号中<code>[]</code>。</p>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>!</code></td>
<td>非运算,表达式为true则返回false,否则返回true。</td>
<td><code>[ ! 10 -eq 0 ]</code></td>
</tr>
<tr>
<td><code>-o</code></td>
<td>或运算,有一个表达式为true则返回true。</td>
<td><code>[ 10 -lt 20 -o 10 -gt 100 ]</code></td>
</tr>
<tr>
<td><code>-a</code></td>
<td>与运算,两个表达式都为true才返回true。</td>
<td><code>[ 10 -lt 20 -a 10 -gt 100 ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ ! 10 -eq 0 ];then echo 'hello';fi
# hello
if [ 10 -ge 10 -a 10 -ge 10 ];then echo 'hello';fi
# hello
if [ 10 -ge 20 -o 10 -ge 0 ];then echo 'hello';fi
# hello
</code></pre>
<p> <code>-o</code>也可以使用<code>||</code>替代,<code>-a</code>也可以使用<code>&&</code>替代,此时需要使用<code>(())</code>或<code>[[]]</code>替代<code>[]</code>。</p>
<pre><code class="language-shell">if <a href="1010-55.html" class="internal-link"> 10==10 && 5==5 </a>;then echo 'hello';fi
# hello
if ((10==10 && 5==5));then echo 'hello';fi
# hello
</code></pre>
<h1>7. 传递参数</h1>
<p>在执行 <code>Shell</code>脚本时,向脚本传递参数,脚本内获取参数的格式为:<code>$n</code>。<code>n</code>代表一个数字,<code>1</code>为执行脚本的第一个参数,<code>2</code>为执行脚本的第二个参数,<code>$0</code>为执行的文件名。在为<code>shell</code>脚本传递的参数中如果包含空格,应该使用单引号或者双引号将该参数括起来,以便于脚本将这个参数作为整体来接收。另外,还有几个特殊字符用来处理参数:</p>
<table>
<thead>
<tr>
<th>参数处理</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>$#</code></td>
<td>传递到脚本的参数个数</td>
</tr>
<tr>
<td><code>$*</code></td>
<td>以一个单字符串显示所有向脚本传递的参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$</code></td>
<td>脚本运行的当前进程ID号</td>
</tr>
<tr>
<td><code>$!</code></td>
<td>后台运行的最后一个进程的ID号</td>
</tr>
<tr>
<td><code>$@</code></td>
<td>与<code>$*</code>相同,但是使用时加引号,并在引号中返回每个参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$-</code></td>
<td>显示Shell使用的当前选项,与set功能相同。</td>
</tr>
<tr>
<td><code>$?</code></td>
<td>显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。</td>
</tr>
</tbody></table>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-bash">set -e
echo "执行的文件名:$0"
echo "参数个数为$#"
echo "第一个参数为:$1"
echo "第二个参数为:$2"
echo "所有参数为:$@"
echo "进程ID号为:$"
echo "当前shell选项为$-"
echo "上一个命令退出的状态为$?"
</code></pre>
<p>执行结果如下:</p>
<pre><code class="language-shell">$ sh test.sh param1 "param2 with space"
执行的文件名:test.sh
参数个数为2
第一个参数为:param1
第二个参数为:param2 with space
所有参数为:param1 param2 with space
进程ID号为:3700
当前shell选项为ehB
上一个命令退出的状态为0
</code></pre>
<h1>8. 函数</h1>
<p>函数定义通过<code>function_name(){}</code>的形式定义,函数返回值可以显示用return返回,如果不加,将以最后一条命令的运行结果作为返回值,函数返回值只能是数字。函数也可以传递参数,但是函数定义的()中不需要申明。</p>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-shell">sayhello(){
echo "hello"
}
# 注意函数调用只需要函数名,不需要加()
sayhello
sayhellowithparam(){
echo "hello, $1 $2 $3"
return 1
}
sayhellowithparam zhangsan lisi wangwu
echo $?
</code></pre>
<p>输出如下:</p>
<blockquote>
<p>hello<br>hello, zhangsan lisi wangwu<br>1</p>
</blockquote>
<h1>9. 命令替换</h1>
<p>命令替换可以将一个命令的输出作为另外一个命令的参数。</p>
<pre><code class="language-shell"># command1 `command2`
cd `pwd` # 该命令将pwd命令列出的目录作为cd命令的参数,结果仍然是停留在当前目录下
cd `echo $HOME` # 将echo的输出作为cd的参数,即打开用户根目录
</code></pre>
<h1>10. let命令</h1>
<p>let 命令是 BASH 中用于计算的工具,用于执行一个或多个表达式,变量计算中不需要加上 $ 来表示变量。如果表达式中包含了空格或其他特殊字符,则必须引起来。</p>
<ul>
<li>自加操作:<code>let no++</code></li>
<li>自减操作:<code>let no--</code></li>
<li>简写形式 <code>let no+=10</code>,<code>let no-=20</code>,分别等同于<code>let no=no+10</code>,<code>let no=no-20</code></li>
</ul>
<h1>11. 流程控制</h1>
<h2>11.1. if</h2>
<pre><code class="language-shell">if ((10<2));then
echo "10小于2"
elif ((10>20));then
echo "a大于10"
else
echo "10大于2且小于10"
fi
</code></pre>
<h2>11.2. case</h2>
<p><code>case</code>每一种情况以右括号结尾,执行到<code>;;</code>结束</p>
<pre><code class="language-shell">case 10 in
0|1)
echo "a为0或1"
;;
11|12)
echo "a为11或12"
;;
*)
# *用来匹配所有情况
echo "a为10"
;;
esac
</code></pre>
<h2>11.3. while</h2>
<pre><code class="language-shell">count=0
while(($count<5))
do
echo $count
let count++
done
</code></pre>
<h2>11.4. util</h2>
<pre><code class="language-shell">count=0
until(($count>=5))
do
echo $count
let count++
done
</code></pre>
<h2>11.5. for</h2>
<pre><code class="language-shell"># for写法1
for ((count=0;$count<5;count=$count+1))
do
echo $count
done
# for写法2
arr=(0 1 2 3 4)
for count in ${arr[*]}
do
echo $int
done
# for写法3
for int in 0 1 2 3 4
do
echo $int
done
</code></pre>
<h2>11.6. break和continue</h2>
<p>用法与一般编程语言类似,break跳出循环,continue跳出当前循环</p>
<pre><code class="language-shell">for ((count=0;$count>=0;count=$count+1))
do
if (($count>=5));then
break;
fi
echo $count
done
</code></pre>
<h1>12. 输入输出重定向</h1>
<h2>12.1. 输出重定向</h2>
<p><code>command > file</code>将命令输出结果保存的file文件中。<code>></code>从文件头开始写,会覆盖旧内容,<code>>></code>将内容追加到文件末尾</p>
<pre><code class="language-shell"># 将who命令的输出保存的users文件中,可以通过cat users查看
who > users
# 将字符串hello world保存到text.txt文件中
echo "hello world" > text.txt
</code></pre>
<h2>12.2. 输入重定向</h2>
<p><code>command < file</code>从file文件获取输入</p>
<pre><code class="language-shell">wc -l /etc/passwd
# 123 /etc/passwd
wc -l < users
# 123
# 第一个例子,会输出文件名;第二个不会,因为它仅仅知道从标准输入读取内容
# command < infile > outfile, 同时替换输入和输出,执行command,从文件infile读取内容,然后将输出写入到outfile中。
wc -l < /etc/passwd > result
cat result
# 123
</code></pre>
<h2>12.3. 文件描述符</h2>
<p>一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件</p>
<ul>
<li>标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。</li>
<li>标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。</li>
<li>标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。</li>
</ul>
<pre><code class="language-shell"># 将标准错误输出重定向到error_trace
cat /tmp/fake_file 2>error_trace
cat error_trace
# cat: /tmp/fake_fule: No such file or directory
# 将标准输出和标准错误输出都重定向到result
cat /tmp/fake_file &>result
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准错误重定向到标准输出
ls /tmp/fake_file > result 2>&1
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准输入重定向到result,将标准错误输出重定向到error_trace
cat /tmp/fake_file 1>result 2>error_trace
</code></pre>
<h2>12.4. Here Document</h2>
<p>将两个<code>EOF</code>之间的内容(document) 作为输入传递给<code>command</code></p>
<pre><code class="language-bash"># command << EOF
# document
# EOF
cat << EOF
hello
shinerio
learn shell
EOF
</code></pre>
<blockquote>
<p>结尾的<code>EOF</code>一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和<code>tab</code>缩进。开始的<code>EOF</code>前后的空格会被忽略掉。</p>
</blockquote>
<h2>12.5. /dev/null</h2>
<p>如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null。<code>command > /dev/null</code></p>
<pre><code class="language-shell">cat users > /dev/null
cat users > /dev/null 2>&1
</code></pre>
<h1>13. set命令</h1>
<p>set指令能设置所使用shell的执行方式,可依照不同的需求来做设置。以下只列出常用的选项参数:</p>
<ul>
<li>-e 若指令传回值不等于0,则立即退出shell。</li>
<li>-f 取消使用通配符。</li>
<li>-n 只读取指令,而不实际执行。</li>
<li>-x 执行指令后,会先显示该指令及所下的参数。</li>
</ul>
</section>
</article>lt;/code>符号,变量加<code>{}</code>是可选的,方便解释器识别边界。将变量加上<code>{}</code>是一个好习惯,不容易出错。</p>
<pre><code class="language-shell">your_age=25
your_name="shinerio"
your_name=shinerio
your_name='shinerio'
echo $your_age # 输出25
echo $your_name # 输出shinerio
echo "${your_name}hello" <span class="tag">#这里</span>{}必须添加,否则解释器认为是${your_namehello}
str='hello'' # 非法
str='hello'__'world' # 成对出现的单引号做字符拼接
echo $str <span class="tag">#输出hello__world</span>
str1='helloworld${your_age}\nnew line'
str2="helloworld${your_age}\nnew line"
echo $str1 # 输出helloworld${your_age}\nnew line
echo $str2 # 输出helloworld25\nnew line
echo -e $str2 # -e开启转义 \n表示换行 echo默认换行,通过\c强制不换行
<span class="tag">#helloworld25</span>
<span class="tag">#new</span> line
</code></pre>
<h2>2.3. 只读变量</h2>
<p>使用<code>readonly VARIABLENAME</code>设置变量只读,只读变量的值不能更改</p>
<pre><code class="language-shell">readonly name='jack'
name='kelly'
zsh: read-only variable: name
</code></pre>
<h2>2.4. 删除变量</h2>
<p>使用<code>unset VARIABLENAME</code>删除变量。</p>
<h1>3. 字符串操作</h1>
<h2>3.1. 字符串拼接</h2>
<pre><code class="language-shell">str1="hello"${your_name}"world"
str2="hello${your_name}world"
str3='hello'${your_name}'world'
</code></pre>
<h2>3.2. 字符串长度</h2>
<pre><code class="language-shell">str='hello'
echo ${<span class="tag">#str</span>}
5
</code></pre>
<h2>3.3. 字符串截取</h2>
<p><code>${string:start:length}</code>,索引从0开始,从start(包含)开始截取共计length长度的字符。</p>
<pre><code class="language-shell">str='helloworld'
echo ${str:0:5}
hello
</code></pre>
<h2>3.4. 字符串运算符</h2>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>=</code></td>
<td>检测两个字符串是否相等,相等返回true</td>
<td><code>[ 'hello' = 'hello' ]</code></td>
</tr>
<tr>
<td><code>!=</code></td>
<td>检测两个字符串是否相等,不相等返回true</td>
<td><code>[ 'hello' != 'ello' ]</code></td>
</tr>
<tr>
<td><code>-z</code></td>
<td>检测字符串长度是否为0,为0返回true</td>
<td><code>[ -z '' ]</code></td>
</tr>
<tr>
<td><code>-n </code></td>
<td>检测字符串长度是否不为0,不为0返回true</td>
<td><code>[ -n 'hello' ]</code></td>
</tr>
<tr>
<td><code><article>
<header>
<h1>shell编程</h1>
<time datetime="2023-01-24T00:00:00.000Z">2023年1月24日</time>
<div class="tags">
<span class="tag">linux</span>
</div>
</header>
<section class="content">
<p>本文主要介绍shell编程的基本语法以及实际应用中的常见命令。</p>
<h1>1. 注释</h1>
<h2>1.1. 单行注释</h2>
<pre><code class="language-shell"># 这是单行注释
</code></pre>
<h2>1.2. 多行注释</h2>
<pre><code class="language-shell">:<<EOF
多行注释内容
多行注释内容
多行注释内容
EOF
</code></pre>
<p>多行注释<code>EOF</code>也可替换成<code>!</code>或<code>'</code></p>
<pre><code class="language-shell">:<<'
多行注释内容
多行注释内容
多行注释内容
'
:<<!
多行注释内容
多行注释内容
多行注释内容
!
</code></pre>
<h1>2. 变量</h1>
<h2>2.1. 变量定义</h2>
<p>使用<code>VARIABLENAME=VALUE</code>的形式,VALUE如果是字符串的话,可以使用单引号、双引号或者不加引号。单引号内的任何字符都会原样输出,不能进行转义,单引号内不能单独出现一个单引号,但可成对出现,作为字符串拼接使用。双引号内可以有变量,可以出现转义字符。</p>
<h2>2.2. 变量使用</h2>
<p>只需要在变量前加<code>$</code>符号,变量加<code>{}</code>是可选的,方便解释器识别边界。将变量加上<code>{}</code>是一个好习惯,不容易出错。</p>
<pre><code class="language-shell">your_age=25
your_name="shinerio"
your_name=shinerio
your_name='shinerio'
echo $your_age # 输出25
echo $your_name # 输出shinerio
echo "${your_name}hello" <span class="tag">#这里</span>{}必须添加,否则解释器认为是${your_namehello}
str='hello'' # 非法
str='hello'__'world' # 成对出现的单引号做字符拼接
echo $str <span class="tag">#输出hello__world</span>
str1='helloworld${your_age}\nnew line'
str2="helloworld${your_age}\nnew line"
echo $str1 # 输出helloworld${your_age}\nnew line
echo $str2 # 输出helloworld25\nnew line
echo -e $str2 # -e开启转义 \n表示换行 echo默认换行,通过\c强制不换行
<span class="tag">#helloworld25</span>
<span class="tag">#new</span> line
</code></pre>
<h2>2.3. 只读变量</h2>
<p>使用<code>readonly VARIABLENAME</code>设置变量只读,只读变量的值不能更改</p>
<pre><code class="language-shell">readonly name='jack'
name='kelly'
zsh: read-only variable: name
</code></pre>
<h2>2.4. 删除变量</h2>
<p>使用<code>unset VARIABLENAME</code>删除变量。</p>
<h1>3. 字符串操作</h1>
<h2>3.1. 字符串拼接</h2>
<pre><code class="language-shell">str1="hello"${your_name}"world"
str2="hello${your_name}world"
str3='hello'${your_name}'world'
</code></pre>
<h2>3.2. 字符串长度</h2>
<pre><code class="language-shell">str='hello'
echo ${<span class="tag">#str</span>}
5
</code></pre>
<h2>3.3. 字符串截取</h2>
<p><code>${string:start:length}</code>,索引从0开始,从start(包含)开始截取共计length长度的字符。</p>
<pre><code class="language-shell">str='helloworld'
echo ${str:0:5}
hello
</code></pre>
<h2>3.4. 字符串运算符</h2>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>=</code></td>
<td>检测两个字符串是否相等,相等返回true</td>
<td><code>[ 'hello' = 'hello' ]</code></td>
</tr>
<tr>
<td><code>!=</code></td>
<td>检测两个字符串是否相等,不相等返回true</td>
<td><code>[ 'hello' != 'ello' ]</code></td>
</tr>
<tr>
<td><code>-z</code></td>
<td>检测字符串长度是否为0,为0返回true</td>
<td><code>[ -z '' ]</code></td>
</tr>
<tr>
<td><code>-n </code></td>
<td>检测字符串长度是否不为0,不为0返回true</td>
<td><code>[ -n 'hello' ]</code></td>
</tr>
<tr>
<td><code>$</code></td>
<td>检测字符串是否为空,不为空返回true</td>
<td><code>[ <p>本文主要介绍shell编程的基本语法以及实际应用中的常见命令。</p>
<h1>1. 注释</h1>
<h2>1.1. 单行注释</h2>
<pre><code class="language-shell"># 这是单行注释
</code></pre>
<h2>1.2. 多行注释</h2>
<pre><code class="language-shell">:&lt;&lt;EOF
多行注释内容
多行注释内容
多行注释内容
EOF
</code></pre>
<p>多行注释<code>EOF</code>也可替换成<code>!</code>或<code>&#39;</code></p>
<pre><code class="language-shell">:&lt;&lt;&#39;
多行注释内容
多行注释内容
多行注释内容
&#39;
:&lt;&lt;!
多行注释内容
多行注释内容
多行注释内容
!
</code></pre>
<h1>2. 变量</h1>
<h2>2.1. 变量定义</h2>
<p>使用<code>VARIABLENAME=VALUE</code>的形式,VALUE如果是字符串的话,可以使用单引号、双引号或者不加引号。单引号内的任何字符都会原样输出,不能进行转义,单引号内不能单独出现一个单引号,但可成对出现,作为字符串拼接使用。双引号内可以有变量,可以出现转义字符。</p>
<h2>2.2. 变量使用</h2>
<p>只需要在变量前加<code>$</code>符号,变量加<code>{}</code>是可选的,方便解释器识别边界。将变量加上<code>{}</code>是一个好习惯,不容易出错。</p>
<pre><code class="language-shell">your_age=25
your_name=&quot;shinerio&quot;
your_name=shinerio
your_name=&#39;shinerio&#39;
echo $your_age # 输出25
echo $your_name # 输出shinerio
echo &quot;${your_name}hello&quot; &lt;span class=&quot;tag&quot;&gt;#这里&lt;/span&gt;{}必须添加,否则解释器认为是${your_namehello}
str=&#39;hello&#39;&#39; # 非法
str=&#39;hello&#39;__&#39;world&#39; # 成对出现的单引号做字符拼接
echo $str &lt;span class=&quot;tag&quot;&gt;#输出hello__world&lt;/span&gt;
str1=&#39;helloworld${your_age}\nnew line&#39;
str2=&quot;helloworld${your_age}\nnew line&quot;
echo $str1 # 输出helloworld${your_age}\nnew line
echo $str2 # 输出helloworld25\nnew line
echo -e $str2 # -e开启转义 \n表示换行 echo默认换行,通过\c强制不换行
&lt;span class=&quot;tag&quot;&gt;#helloworld25&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;#new&lt;/span&gt; line
</code></pre>
<h2>2.3. 只读变量</h2>
<p>使用<code>readonly VARIABLENAME</code>设置变量只读,只读变量的值不能更改</p>
<pre><code class="language-shell">readonly name=&#39;jack&#39;
name=&#39;kelly&#39;
zsh: read-only variable: name
</code></pre>
<h2>2.4. 删除变量</h2>
<p>使用<code>unset VARIABLENAME</code>删除变量。</p>
<h1>3. 字符串操作</h1>
<h2>3.1. 字符串拼接</h2>
<pre><code class="language-shell">str1=&quot;hello&quot;${your_name}&quot;world&quot;
str2=&quot;hello${your_name}world&quot;
str3=&#39;hello&#39;${your_name}&#39;world&#39;
</code></pre>
<h2>3.2. 字符串长度</h2>
<pre><code class="language-shell">str=&#39;hello&#39;
echo ${&lt;span class=&quot;tag&quot;&gt;#str&lt;/span&gt;}
5
</code></pre>
<h2>3.3. 字符串截取</h2>
<p><code>${string:start:length}</code>,索引从0开始,从start(包含)开始截取共计length长度的字符。</p>
<pre><code class="language-shell">str=&#39;helloworld&#39;
echo ${str:0:5}
hello
</code></pre>
<h2>3.4. 字符串运算符</h2>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>=</code></td>
<td>检测两个字符串是否相等,相等返回true</td>
<td><code>[ &#39;hello&#39; = &#39;hello&#39; ]</code></td>
</tr>
<tr>
<td><code>!=</code></td>
<td>检测两个字符串是否相等,不相等返回true</td>
<td><code>[ &#39;hello&#39; != &#39;ello&#39; ]</code></td>
</tr>
<tr>
<td><code>-z</code></td>
<td>检测字符串长度是否为0,为0返回true</td>
<td><code>[ -z &#39;&#39; ]</code></td>
</tr>
<tr>
<td><code>-n </code></td>
<td>检测字符串长度是否不为0,不为0返回true</td>
<td><code>[ -n &#39;hello&#39; ]</code></td>
</tr>
<tr>
<td><code>$</code></td>
<td>检测字符串是否为空,不为空返回true</td>
<td><code>[ $&#39;hello&#39; ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ &#39;hello&#39; = &#39;hello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ &#39;hello&#39; != &#39;ello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ -z &#39;&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ -n &#39;hello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ $&#39;hello&#39; ];then echo &#39;hello&#39;;fi
str=&#39;hello&#39;
if [ $str ];then echo &#39;hello&#39;;fi
# hello
</code></pre>
<p>注意字符串的等值判断是一个等号<code>&quot;=&quot;</code>,与下文要讲的逻辑运算符使用两个等号<code>&quot;==&quot;</code>做等值判断不一样。</p>
<h1>4. 文件测试运算符</h1>
<table>
<thead>
<tr>
<th>操作符</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>-b file</code></td>
<td>检测文件是否是块设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-c file</code></td>
<td>检测文件是否是字符设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-d file</code></td>
<td>检测文件是否是目录,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-f file</code></td>
<td>检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-g file</code></td>
<td>检测文件是否设置了<code>SGID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-k file</code></td>
<td>检测文件是否设置了粘着位(Sticky Bit),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-p file</code></td>
<td>检测文件是否是有名管道,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-u file</code></td>
<td>检测文件是否设置了<code>SUID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-r file</code></td>
<td>检测文件是否可读,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-w file</code></td>
<td>检测文件是否可写,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-x file</code></td>
<td>检测文件是否可执行,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-s file</code></td>
<td>检测文件是否为空(文件大小是否大于0),不为空返回true。</td>
</tr>
<tr>
<td><code>-e file</code></td>
<td>检测文件(包括目录)是否存在,如果是,则返回true。</td>
</tr>
</tbody></table>
<pre><code class="language-shell">if &lt;a href=&quot;f-home.html&quot; class=&quot;internal-link&quot;&gt; -f &#39;/home&#39; &lt;/a&gt;;then echo &#39;directory&#39;;else echo &#39;file&#39;;fi
# file
if &lt;a href=&quot;d-home.html&quot; class=&quot;internal-link&quot;&gt; -d &#39;/home&#39; &lt;/a&gt;;then echo &#39;directory&#39;;else echo &#39;file&#39;;fi
# directory
if &lt;a href=&quot;e-tmpfake-file.html&quot; class=&quot;internal-link&quot;&gt; -e &#39;/tmp/fake_file&#39; &lt;/a&gt;;then echo &#39;exist&#39;;else echo &#39;not exist&#39;;fi
# not exist
</code></pre>
<h1>5. 数组</h1>
<p><code>shell</code>只支持一维数组,用括号表示,元素通过空格分隔,形如<code>数组名=(值1 值2 ... 值n)</code>。<code>shell</code>数组下标从<code>1</code>开始。</p>
<ul>
<li><code>${数组名[下标]}</code>,读取指索引位置数组元素</li>
<li>使用<code>@</code>或<code>*</code>代替下标,获取数组中所有元素。</li>
<li>使用<code>{&lt;span class=&quot;tag&quot;&gt;#数组名&lt;/span&gt;[@]}</code>或<code>{&lt;span class=&quot;tag&quot;&gt;#数组名&lt;/span&gt;[*]}</code>获取数组元素个数。</li>
</ul>
<pre><code class="language-shell">arr=(value1 value2 value3 value4)
echo ${arr[3]}
# value3
echo ${arr[*]}
# value1 value2 value3 value4
echo ${arr[@]}
# value1 value2 value3 value4
arr[3]=&#39;new_value3&#39;
echo $arr[3]
# new_value3
echo ${&lt;span class=&quot;tag&quot;&gt;#arr&lt;/span&gt;[@]}
# 4
echo &quot;arr[1]的长度为:${&lt;span class=&quot;tag&quot;&gt;#arr&lt;/span&gt;[1]}&quot;
# arr[1]的长度为:6
</code></pre>
<h1>6. 运算符</h1>
<h2>6.1. 赋值运算符</h2>
<pre><code class="language-shell">a=10
b=$a
</code></pre>
<h2>6.2. 算术运算符</h2>
<p>算数运算符支持<code>+,-,*,/,%</code></p>
<h3>6.2.1. expr表示法</h3>
<pre><code class="language-shell">echo `expr 10 + 20`
# 30
echo $(expr 20 / 2)
# 10
echo $(expr 10 \* 20) # 使用expr进行乘法运算时必须使用\进行转义
# 200
</code></pre>
<blockquote>
<p>使用expr表示方法时,表达式和运算符之间必须有空格。</p>
</blockquote>
<h3>6.2.2. <code>$[]</code></h3>
<pre><code class="language-shell">echo $[10%3]
# 1
</code></pre>
<h3>6.2.3. <code>$(())</code></h3>
<pre><code class="language-shell">echo $((10*20))
# 200
</code></pre>
<h2>6.3. 关系运算符</h2>
<p>最常见的关系运算符是:<code>==,!=,&lt;,&gt;,&gt;=,&lt;=</code></p>
<pre><code class="language-shell">echo $[10==10]
# 1
flag=$[20==10]
echo $flag
# 1
echo $[10&gt;=10]
# 1
</code></pre>
<p>如下关系运算符只能使用在条件表达式<code>if、while</code>下,类似<code>flag=[ $a -eq $b ]</code>的直接赋值语句是非法的。关系运算符的条件表达式要放在<strong>一对</strong>方括号中,并且中间需要有空格。也可以使用<code>(())</code>替代<code>[]</code>,此时<code>-eq,-lt,-le</code>之类的需要使用<code>==,&lt;,&lt;=</code>等替换。</p>
<blockquote>
<p><code>[]</code>搭配<code>-eq -ne</code>等使用,<code>(())</code>搭配<code>|| &amp;&amp;</code>等使用。</p>
</blockquote>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>-eq</code></td>
<td>检测两个数是否相等,相等返回true。</td>
<td><code>[ $a -eq $b ]</code></td>
</tr>
<tr>
<td><code>-ne</code></td>
<td>检测两个数是否不相等,不相等返回 true。</td>
<td><code>[ $a -ne $b ]</code></td>
</tr>
<tr>
<td><code>-gt</code></td>
<td>检测左边的数是否大于右边的,如果是,则返回 true。</td>
<td><code>[ $a -gt $b ]</code></td>
</tr>
<tr>
<td><code>-lt</code></td>
<td>检测左边的数是否小于右边的,如果是,则返回 true。</td>
<td><code>[ $a -lt $b ]</code></td>
</tr>
<tr>
<td><code>-ge</code></td>
<td>检测左边的数是否大于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -ge $b ]</code></td>
</tr>
<tr>
<td><code>-le</code></td>
<td>检测左边的数是否小于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -le $b ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ 1 -eq 1 ];then echo &#39;hello&#39;;fi;
# hello
if ((10&gt;=10));then echo &#39;hello&#39;;fi;
# hello
</code></pre>
<h2>6.4. 布尔、逻辑运算符</h2>
<p>布尔、逻辑运算的条件表达式也要放在一对方括号中<code>[]</code>。</p>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>!</code></td>
<td>非运算,表达式为true则返回false,否则返回true。</td>
<td><code>[ ! 10 -eq 0 ]</code></td>
</tr>
<tr>
<td><code>-o</code></td>
<td>或运算,有一个表达式为true则返回true。</td>
<td><code>[ 10 -lt 20 -o 10 -gt 100 ]</code></td>
</tr>
<tr>
<td><code>-a</code></td>
<td>与运算,两个表达式都为true才返回true。</td>
<td><code>[ 10 -lt 20 -a 10 -gt 100 ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ ! 10 -eq 0 ];then echo &#39;hello&#39;;fi
# hello
if [ 10 -ge 10 -a 10 -ge 10 ];then echo &#39;hello&#39;;fi
# hello
if [ 10 -ge 20 -o 10 -ge 0 ];then echo &#39;hello&#39;;fi
# hello
</code></pre>
<p> <code>-o</code>也可以使用<code>||</code>替代,<code>-a</code>也可以使用<code>&amp;&amp;</code>替代,此时需要使用<code>(())</code>或<code>[[]]</code>替代<code>[]</code>。</p>
<pre><code class="language-shell">if &lt;a href=&quot;1010-55.html&quot; class=&quot;internal-link&quot;&gt; 10==10 &amp;&amp; 5==5 &lt;/a&gt;;then echo &#39;hello&#39;;fi
# hello
if ((10==10 &amp;&amp; 5==5));then echo &#39;hello&#39;;fi
# hello
</code></pre>
<h1>7. 传递参数</h1>
<p>在执行 <code>Shell</code>脚本时,向脚本传递参数,脚本内获取参数的格式为:<code>$n</code>。<code>n</code>代表一个数字,<code>1</code>为执行脚本的第一个参数,<code>2</code>为执行脚本的第二个参数,<code>$0</code>为执行的文件名。在为<code>shell</code>脚本传递的参数中如果包含空格,应该使用单引号或者双引号将该参数括起来,以便于脚本将这个参数作为整体来接收。另外,还有几个特殊字符用来处理参数:</p>
<table>
<thead>
<tr>
<th>参数处理</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>$#</code></td>
<td>传递到脚本的参数个数</td>
</tr>
<tr>
<td><code>$*</code></td>
<td>以一个单字符串显示所有向脚本传递的参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$$</code></td>
<td>脚本运行的当前进程ID号</td>
</tr>
<tr>
<td><code>$!</code></td>
<td>后台运行的最后一个进程的ID号</td>
</tr>
<tr>
<td><code>$@</code></td>
<td>与<code>$*</code>相同,但是使用时加引号,并在引号中返回每个参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$-</code></td>
<td>显示Shell使用的当前选项,与set功能相同。</td>
</tr>
<tr>
<td><code>$?</code></td>
<td>显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。</td>
</tr>
</tbody></table>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-bash">set -e
echo &quot;执行的文件名:$0&quot;
echo &quot;参数个数为$#&quot;
echo &quot;第一个参数为:$1&quot;
echo &quot;第二个参数为:$2&quot;
echo &quot;所有参数为:$@&quot;
echo &quot;进程ID号为:$$&quot;
echo &quot;当前shell选项为$-&quot;
echo &quot;上一个命令退出的状态为$?&quot;
</code></pre>
<p>执行结果如下:</p>
<pre><code class="language-shell">$ sh test.sh param1 &quot;param2 with space&quot;
执行的文件名:test.sh
参数个数为2
第一个参数为:param1
第二个参数为:param2 with space
所有参数为:param1 param2 with space
进程ID号为:3700
当前shell选项为ehB
上一个命令退出的状态为0
</code></pre>
<h1>8. 函数</h1>
<p>函数定义通过<code>function_name(){}</code>的形式定义,函数返回值可以显示用return返回,如果不加,将以最后一条命令的运行结果作为返回值,函数返回值只能是数字。函数也可以传递参数,但是函数定义的()中不需要申明。</p>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-shell">sayhello(){
echo &quot;hello&quot;
}
# 注意函数调用只需要函数名,不需要加()
sayhello
sayhellowithparam(){
echo &quot;hello, $1 $2 $3&quot;
return 1
}
sayhellowithparam zhangsan lisi wangwu
echo $?
</code></pre>
<p>输出如下:</p>
<blockquote>
<p>hello<br>hello, zhangsan lisi wangwu<br>1</p>
</blockquote>
<h1>9. 命令替换</h1>
<p>命令替换可以将一个命令的输出作为另外一个命令的参数。</p>
<pre><code class="language-shell"># command1 `command2`
cd `pwd` # 该命令将pwd命令列出的目录作为cd命令的参数,结果仍然是停留在当前目录下
cd `echo $HOME` # 将echo的输出作为cd的参数,即打开用户根目录
</code></pre>
<h1>10. let命令</h1>
<p>let 命令是 BASH 中用于计算的工具,用于执行一个或多个表达式,变量计算中不需要加上 $ 来表示变量。如果表达式中包含了空格或其他特殊字符,则必须引起来。</p>
<ul>
<li>自加操作:<code>let no++</code></li>
<li>自减操作:<code>let no--</code></li>
<li>简写形式 <code>let no+=10</code>,<code>let no-=20</code>,分别等同于<code>let no=no+10</code>,<code>let no=no-20</code></li>
</ul>
<h1>11. 流程控制</h1>
<h2>11.1. if</h2>
<pre><code class="language-shell">if ((10&lt;2));then
echo &quot;10小于2&quot;
elif ((10&gt;20));then
echo &quot;a大于10&quot;
else
echo &quot;10大于2且小于10&quot;
fi
</code></pre>
<h2>11.2. case</h2>
<p><code>case</code>每一种情况以右括号结尾,执行到<code>;;</code>结束</p>
<pre><code class="language-shell">case 10 in
0|1)
echo &quot;a为0或1&quot;
;;
11|12)
echo &quot;a为11或12&quot;
;;
*)
# *用来匹配所有情况
echo &quot;a为10&quot;
;;
esac
</code></pre>
<h2>11.3. while</h2>
<pre><code class="language-shell">count=0
while(($count&lt;5))
do
echo $count
let count++
done
</code></pre>
<h2>11.4. util</h2>
<pre><code class="language-shell">count=0
until(($count&gt;=5))
do
echo $count
let count++
done
</code></pre>
<h2>11.5. for</h2>
<pre><code class="language-shell"># for写法1
for ((count=0;$count&lt;5;count=$count+1))
do
echo $count
done
# for写法2
arr=(0 1 2 3 4)
for count in ${arr[*]}
do
echo $int
done
# for写法3
for int in 0 1 2 3 4
do
echo $int
done
</code></pre>
<h2>11.6. break和continue</h2>
<p>用法与一般编程语言类似,break跳出循环,continue跳出当前循环</p>
<pre><code class="language-shell">for ((count=0;$count&gt;=0;count=$count+1))
do
if (($count&gt;=5));then
break;
fi
echo $count
done
</code></pre>
<h1>12. 输入输出重定向</h1>
<h2>12.1. 输出重定向</h2>
<p><code>command &gt; file</code>将命令输出结果保存的file文件中。<code>&gt;</code>从文件头开始写,会覆盖旧内容,<code>&gt;&gt;</code>将内容追加到文件末尾</p>
<pre><code class="language-shell"># 将who命令的输出保存的users文件中,可以通过cat users查看
who &gt; users
# 将字符串hello world保存到text.txt文件中
echo &quot;hello world&quot; &gt; text.txt
</code></pre>
<h2>12.2. 输入重定向</h2>
<p><code>command &lt; file</code>从file文件获取输入</p>
<pre><code class="language-shell">wc -l /etc/passwd
# 123 /etc/passwd
wc -l &lt; users
# 123
# 第一个例子,会输出文件名;第二个不会,因为它仅仅知道从标准输入读取内容
# command &lt; infile &gt; outfile, 同时替换输入和输出,执行command,从文件infile读取内容,然后将输出写入到outfile中。
wc -l &lt; /etc/passwd &gt; result
cat result
# 123
</code></pre>
<h2>12.3. 文件描述符</h2>
<p>一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件</p>
<ul>
<li>标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。</li>
<li>标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。</li>
<li>标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。</li>
</ul>
<pre><code class="language-shell"># 将标准错误输出重定向到error_trace
cat /tmp/fake_file 2&gt;error_trace
cat error_trace
# cat: /tmp/fake_fule: No such file or directory
# 将标准输出和标准错误输出都重定向到result
cat /tmp/fake_file &amp;&gt;result
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准错误重定向到标准输出
ls /tmp/fake_file &gt; result 2&gt;&amp;1
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准输入重定向到result,将标准错误输出重定向到error_trace
cat /tmp/fake_file 1&gt;result 2&gt;error_trace
</code></pre>
<h2>12.4. Here Document</h2>
<p>将两个<code>EOF</code>之间的内容(document) 作为输入传递给<code>command</code></p>
<pre><code class="language-bash"># command &lt;&lt; EOF
# document
# EOF
cat &lt;&lt; EOF
hello
shinerio
learn shell
EOF
</code></pre>
<blockquote>
<p>结尾的<code>EOF</code>一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和<code>tab</code>缩进。开始的<code>EOF</code>前后的空格会被忽略掉。</p>
</blockquote>
<h2>12.5. /dev/null</h2>
<p>如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null。<code>command &gt; /dev/null</code></p>
<pre><code class="language-shell">cat users &gt; /dev/null
cat users &gt; /dev/null 2&gt;&amp;1
</code></pre>
<h1>13. set命令</h1>
<p>set指令能设置所使用shell的执行方式,可依照不同的需求来做设置。以下只列出常用的选项参数:</p>
<ul>
<li>-e 若指令传回值不等于0,则立即退出shell。</li>
<li>-f 取消使用通配符。</li>
<li>-n 只读取指令,而不实际执行。</li>
<li>-x 执行指令后,会先显示该指令及所下的参数。</li>
</ul>
#39;hello' ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ 'hello' = 'hello' ];then echo 'hello';fi
# hello
if [ 'hello' != 'ello' ];then echo 'hello';fi
# hello
if [ -z '' ];then echo 'hello';fi
# hello
if [ -n 'hello' ];then echo 'hello';fi
# hello
if [ <p>本文主要介绍shell编程的基本语法以及实际应用中的常见命令。</p>
<h1>1. 注释</h1>
<h2>1.1. 单行注释</h2>
<pre><code class="language-shell"># 这是单行注释
</code></pre>
<h2>1.2. 多行注释</h2>
<pre><code class="language-shell">:&lt;&lt;EOF
多行注释内容
多行注释内容
多行注释内容
EOF
</code></pre>
<p>多行注释<code>EOF</code>也可替换成<code>!</code>或<code>&#39;</code></p>
<pre><code class="language-shell">:&lt;&lt;&#39;
多行注释内容
多行注释内容
多行注释内容
&#39;
:&lt;&lt;!
多行注释内容
多行注释内容
多行注释内容
!
</code></pre>
<h1>2. 变量</h1>
<h2>2.1. 变量定义</h2>
<p>使用<code>VARIABLENAME=VALUE</code>的形式,VALUE如果是字符串的话,可以使用单引号、双引号或者不加引号。单引号内的任何字符都会原样输出,不能进行转义,单引号内不能单独出现一个单引号,但可成对出现,作为字符串拼接使用。双引号内可以有变量,可以出现转义字符。</p>
<h2>2.2. 变量使用</h2>
<p>只需要在变量前加<code>$</code>符号,变量加<code>{}</code>是可选的,方便解释器识别边界。将变量加上<code>{}</code>是一个好习惯,不容易出错。</p>
<pre><code class="language-shell">your_age=25
your_name=&quot;shinerio&quot;
your_name=shinerio
your_name=&#39;shinerio&#39;
echo $your_age # 输出25
echo $your_name # 输出shinerio
echo &quot;${your_name}hello&quot; &lt;span class=&quot;tag&quot;&gt;#这里&lt;/span&gt;{}必须添加,否则解释器认为是${your_namehello}
str=&#39;hello&#39;&#39; # 非法
str=&#39;hello&#39;__&#39;world&#39; # 成对出现的单引号做字符拼接
echo $str &lt;span class=&quot;tag&quot;&gt;#输出hello__world&lt;/span&gt;
str1=&#39;helloworld${your_age}\nnew line&#39;
str2=&quot;helloworld${your_age}\nnew line&quot;
echo $str1 # 输出helloworld${your_age}\nnew line
echo $str2 # 输出helloworld25\nnew line
echo -e $str2 # -e开启转义 \n表示换行 echo默认换行,通过\c强制不换行
&lt;span class=&quot;tag&quot;&gt;#helloworld25&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;#new&lt;/span&gt; line
</code></pre>
<h2>2.3. 只读变量</h2>
<p>使用<code>readonly VARIABLENAME</code>设置变量只读,只读变量的值不能更改</p>
<pre><code class="language-shell">readonly name=&#39;jack&#39;
name=&#39;kelly&#39;
zsh: read-only variable: name
</code></pre>
<h2>2.4. 删除变量</h2>
<p>使用<code>unset VARIABLENAME</code>删除变量。</p>
<h1>3. 字符串操作</h1>
<h2>3.1. 字符串拼接</h2>
<pre><code class="language-shell">str1=&quot;hello&quot;${your_name}&quot;world&quot;
str2=&quot;hello${your_name}world&quot;
str3=&#39;hello&#39;${your_name}&#39;world&#39;
</code></pre>
<h2>3.2. 字符串长度</h2>
<pre><code class="language-shell">str=&#39;hello&#39;
echo ${&lt;span class=&quot;tag&quot;&gt;#str&lt;/span&gt;}
5
</code></pre>
<h2>3.3. 字符串截取</h2>
<p><code>${string:start:length}</code>,索引从0开始,从start(包含)开始截取共计length长度的字符。</p>
<pre><code class="language-shell">str=&#39;helloworld&#39;
echo ${str:0:5}
hello
</code></pre>
<h2>3.4. 字符串运算符</h2>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>=</code></td>
<td>检测两个字符串是否相等,相等返回true</td>
<td><code>[ &#39;hello&#39; = &#39;hello&#39; ]</code></td>
</tr>
<tr>
<td><code>!=</code></td>
<td>检测两个字符串是否相等,不相等返回true</td>
<td><code>[ &#39;hello&#39; != &#39;ello&#39; ]</code></td>
</tr>
<tr>
<td><code>-z</code></td>
<td>检测字符串长度是否为0,为0返回true</td>
<td><code>[ -z &#39;&#39; ]</code></td>
</tr>
<tr>
<td><code>-n </code></td>
<td>检测字符串长度是否不为0,不为0返回true</td>
<td><code>[ -n &#39;hello&#39; ]</code></td>
</tr>
<tr>
<td><code>$</code></td>
<td>检测字符串是否为空,不为空返回true</td>
<td><code>[ $&#39;hello&#39; ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ &#39;hello&#39; = &#39;hello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ &#39;hello&#39; != &#39;ello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ -z &#39;&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ -n &#39;hello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ $&#39;hello&#39; ];then echo &#39;hello&#39;;fi
str=&#39;hello&#39;
if [ $str ];then echo &#39;hello&#39;;fi
# hello
</code></pre>
<p>注意字符串的等值判断是一个等号<code>&quot;=&quot;</code>,与下文要讲的逻辑运算符使用两个等号<code>&quot;==&quot;</code>做等值判断不一样。</p>
<h1>4. 文件测试运算符</h1>
<table>
<thead>
<tr>
<th>操作符</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>-b file</code></td>
<td>检测文件是否是块设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-c file</code></td>
<td>检测文件是否是字符设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-d file</code></td>
<td>检测文件是否是目录,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-f file</code></td>
<td>检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-g file</code></td>
<td>检测文件是否设置了<code>SGID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-k file</code></td>
<td>检测文件是否设置了粘着位(Sticky Bit),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-p file</code></td>
<td>检测文件是否是有名管道,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-u file</code></td>
<td>检测文件是否设置了<code>SUID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-r file</code></td>
<td>检测文件是否可读,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-w file</code></td>
<td>检测文件是否可写,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-x file</code></td>
<td>检测文件是否可执行,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-s file</code></td>
<td>检测文件是否为空(文件大小是否大于0),不为空返回true。</td>
</tr>
<tr>
<td><code>-e file</code></td>
<td>检测文件(包括目录)是否存在,如果是,则返回true。</td>
</tr>
</tbody></table>
<pre><code class="language-shell">if &lt;a href=&quot;f-home.html&quot; class=&quot;internal-link&quot;&gt; -f &#39;/home&#39; &lt;/a&gt;;then echo &#39;directory&#39;;else echo &#39;file&#39;;fi
# file
if &lt;a href=&quot;d-home.html&quot; class=&quot;internal-link&quot;&gt; -d &#39;/home&#39; &lt;/a&gt;;then echo &#39;directory&#39;;else echo &#39;file&#39;;fi
# directory
if &lt;a href=&quot;e-tmpfake-file.html&quot; class=&quot;internal-link&quot;&gt; -e &#39;/tmp/fake_file&#39; &lt;/a&gt;;then echo &#39;exist&#39;;else echo &#39;not exist&#39;;fi
# not exist
</code></pre>
<h1>5. 数组</h1>
<p><code>shell</code>只支持一维数组,用括号表示,元素通过空格分隔,形如<code>数组名=(值1 值2 ... 值n)</code>。<code>shell</code>数组下标从<code>1</code>开始。</p>
<ul>
<li><code>${数组名[下标]}</code>,读取指索引位置数组元素</li>
<li>使用<code>@</code>或<code>*</code>代替下标,获取数组中所有元素。</li>
<li>使用<code>{&lt;span class=&quot;tag&quot;&gt;#数组名&lt;/span&gt;[@]}</code>或<code>{&lt;span class=&quot;tag&quot;&gt;#数组名&lt;/span&gt;[*]}</code>获取数组元素个数。</li>
</ul>
<pre><code class="language-shell">arr=(value1 value2 value3 value4)
echo ${arr[3]}
# value3
echo ${arr[*]}
# value1 value2 value3 value4
echo ${arr[@]}
# value1 value2 value3 value4
arr[3]=&#39;new_value3&#39;
echo $arr[3]
# new_value3
echo ${&lt;span class=&quot;tag&quot;&gt;#arr&lt;/span&gt;[@]}
# 4
echo &quot;arr[1]的长度为:${&lt;span class=&quot;tag&quot;&gt;#arr&lt;/span&gt;[1]}&quot;
# arr[1]的长度为:6
</code></pre>
<h1>6. 运算符</h1>
<h2>6.1. 赋值运算符</h2>
<pre><code class="language-shell">a=10
b=$a
</code></pre>
<h2>6.2. 算术运算符</h2>
<p>算数运算符支持<code>+,-,*,/,%</code></p>
<h3>6.2.1. expr表示法</h3>
<pre><code class="language-shell">echo `expr 10 + 20`
# 30
echo $(expr 20 / 2)
# 10
echo $(expr 10 \* 20) # 使用expr进行乘法运算时必须使用\进行转义
# 200
</code></pre>
<blockquote>
<p>使用expr表示方法时,表达式和运算符之间必须有空格。</p>
</blockquote>
<h3>6.2.2. <code>$[]</code></h3>
<pre><code class="language-shell">echo $[10%3]
# 1
</code></pre>
<h3>6.2.3. <code>$(())</code></h3>
<pre><code class="language-shell">echo $((10*20))
# 200
</code></pre>
<h2>6.3. 关系运算符</h2>
<p>最常见的关系运算符是:<code>==,!=,&lt;,&gt;,&gt;=,&lt;=</code></p>
<pre><code class="language-shell">echo $[10==10]
# 1
flag=$[20==10]
echo $flag
# 1
echo $[10&gt;=10]
# 1
</code></pre>
<p>如下关系运算符只能使用在条件表达式<code>if、while</code>下,类似<code>flag=[ $a -eq $b ]</code>的直接赋值语句是非法的。关系运算符的条件表达式要放在<strong>一对</strong>方括号中,并且中间需要有空格。也可以使用<code>(())</code>替代<code>[]</code>,此时<code>-eq,-lt,-le</code>之类的需要使用<code>==,&lt;,&lt;=</code>等替换。</p>
<blockquote>
<p><code>[]</code>搭配<code>-eq -ne</code>等使用,<code>(())</code>搭配<code>|| &amp;&amp;</code>等使用。</p>
</blockquote>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>-eq</code></td>
<td>检测两个数是否相等,相等返回true。</td>
<td><code>[ $a -eq $b ]</code></td>
</tr>
<tr>
<td><code>-ne</code></td>
<td>检测两个数是否不相等,不相等返回 true。</td>
<td><code>[ $a -ne $b ]</code></td>
</tr>
<tr>
<td><code>-gt</code></td>
<td>检测左边的数是否大于右边的,如果是,则返回 true。</td>
<td><code>[ $a -gt $b ]</code></td>
</tr>
<tr>
<td><code>-lt</code></td>
<td>检测左边的数是否小于右边的,如果是,则返回 true。</td>
<td><code>[ $a -lt $b ]</code></td>
</tr>
<tr>
<td><code>-ge</code></td>
<td>检测左边的数是否大于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -ge $b ]</code></td>
</tr>
<tr>
<td><code>-le</code></td>
<td>检测左边的数是否小于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -le $b ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ 1 -eq 1 ];then echo &#39;hello&#39;;fi;
# hello
if ((10&gt;=10));then echo &#39;hello&#39;;fi;
# hello
</code></pre>
<h2>6.4. 布尔、逻辑运算符</h2>
<p>布尔、逻辑运算的条件表达式也要放在一对方括号中<code>[]</code>。</p>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>!</code></td>
<td>非运算,表达式为true则返回false,否则返回true。</td>
<td><code>[ ! 10 -eq 0 ]</code></td>
</tr>
<tr>
<td><code>-o</code></td>
<td>或运算,有一个表达式为true则返回true。</td>
<td><code>[ 10 -lt 20 -o 10 -gt 100 ]</code></td>
</tr>
<tr>
<td><code>-a</code></td>
<td>与运算,两个表达式都为true才返回true。</td>
<td><code>[ 10 -lt 20 -a 10 -gt 100 ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ ! 10 -eq 0 ];then echo &#39;hello&#39;;fi
# hello
if [ 10 -ge 10 -a 10 -ge 10 ];then echo &#39;hello&#39;;fi
# hello
if [ 10 -ge 20 -o 10 -ge 0 ];then echo &#39;hello&#39;;fi
# hello
</code></pre>
<p> <code>-o</code>也可以使用<code>||</code>替代,<code>-a</code>也可以使用<code>&amp;&amp;</code>替代,此时需要使用<code>(())</code>或<code>[[]]</code>替代<code>[]</code>。</p>
<pre><code class="language-shell">if &lt;a href=&quot;1010-55.html&quot; class=&quot;internal-link&quot;&gt; 10==10 &amp;&amp; 5==5 &lt;/a&gt;;then echo &#39;hello&#39;;fi
# hello
if ((10==10 &amp;&amp; 5==5));then echo &#39;hello&#39;;fi
# hello
</code></pre>
<h1>7. 传递参数</h1>
<p>在执行 <code>Shell</code>脚本时,向脚本传递参数,脚本内获取参数的格式为:<code>$n</code>。<code>n</code>代表一个数字,<code>1</code>为执行脚本的第一个参数,<code>2</code>为执行脚本的第二个参数,<code>$0</code>为执行的文件名。在为<code>shell</code>脚本传递的参数中如果包含空格,应该使用单引号或者双引号将该参数括起来,以便于脚本将这个参数作为整体来接收。另外,还有几个特殊字符用来处理参数:</p>
<table>
<thead>
<tr>
<th>参数处理</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>$#</code></td>
<td>传递到脚本的参数个数</td>
</tr>
<tr>
<td><code>$*</code></td>
<td>以一个单字符串显示所有向脚本传递的参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$$</code></td>
<td>脚本运行的当前进程ID号</td>
</tr>
<tr>
<td><code>$!</code></td>
<td>后台运行的最后一个进程的ID号</td>
</tr>
<tr>
<td><code>$@</code></td>
<td>与<code>$*</code>相同,但是使用时加引号,并在引号中返回每个参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$-</code></td>
<td>显示Shell使用的当前选项,与set功能相同。</td>
</tr>
<tr>
<td><code>$?</code></td>
<td>显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。</td>
</tr>
</tbody></table>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-bash">set -e
echo &quot;执行的文件名:$0&quot;
echo &quot;参数个数为$#&quot;
echo &quot;第一个参数为:$1&quot;
echo &quot;第二个参数为:$2&quot;
echo &quot;所有参数为:$@&quot;
echo &quot;进程ID号为:$$&quot;
echo &quot;当前shell选项为$-&quot;
echo &quot;上一个命令退出的状态为$?&quot;
</code></pre>
<p>执行结果如下:</p>
<pre><code class="language-shell">$ sh test.sh param1 &quot;param2 with space&quot;
执行的文件名:test.sh
参数个数为2
第一个参数为:param1
第二个参数为:param2 with space
所有参数为:param1 param2 with space
进程ID号为:3700
当前shell选项为ehB
上一个命令退出的状态为0
</code></pre>
<h1>8. 函数</h1>
<p>函数定义通过<code>function_name(){}</code>的形式定义,函数返回值可以显示用return返回,如果不加,将以最后一条命令的运行结果作为返回值,函数返回值只能是数字。函数也可以传递参数,但是函数定义的()中不需要申明。</p>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-shell">sayhello(){
echo &quot;hello&quot;
}
# 注意函数调用只需要函数名,不需要加()
sayhello
sayhellowithparam(){
echo &quot;hello, $1 $2 $3&quot;
return 1
}
sayhellowithparam zhangsan lisi wangwu
echo $?
</code></pre>
<p>输出如下:</p>
<blockquote>
<p>hello<br>hello, zhangsan lisi wangwu<br>1</p>
</blockquote>
<h1>9. 命令替换</h1>
<p>命令替换可以将一个命令的输出作为另外一个命令的参数。</p>
<pre><code class="language-shell"># command1 `command2`
cd `pwd` # 该命令将pwd命令列出的目录作为cd命令的参数,结果仍然是停留在当前目录下
cd `echo $HOME` # 将echo的输出作为cd的参数,即打开用户根目录
</code></pre>
<h1>10. let命令</h1>
<p>let 命令是 BASH 中用于计算的工具,用于执行一个或多个表达式,变量计算中不需要加上 $ 来表示变量。如果表达式中包含了空格或其他特殊字符,则必须引起来。</p>
<ul>
<li>自加操作:<code>let no++</code></li>
<li>自减操作:<code>let no--</code></li>
<li>简写形式 <code>let no+=10</code>,<code>let no-=20</code>,分别等同于<code>let no=no+10</code>,<code>let no=no-20</code></li>
</ul>
<h1>11. 流程控制</h1>
<h2>11.1. if</h2>
<pre><code class="language-shell">if ((10&lt;2));then
echo &quot;10小于2&quot;
elif ((10&gt;20));then
echo &quot;a大于10&quot;
else
echo &quot;10大于2且小于10&quot;
fi
</code></pre>
<h2>11.2. case</h2>
<p><code>case</code>每一种情况以右括号结尾,执行到<code>;;</code>结束</p>
<pre><code class="language-shell">case 10 in
0|1)
echo &quot;a为0或1&quot;
;;
11|12)
echo &quot;a为11或12&quot;
;;
*)
# *用来匹配所有情况
echo &quot;a为10&quot;
;;
esac
</code></pre>
<h2>11.3. while</h2>
<pre><code class="language-shell">count=0
while(($count&lt;5))
do
echo $count
let count++
done
</code></pre>
<h2>11.4. util</h2>
<pre><code class="language-shell">count=0
until(($count&gt;=5))
do
echo $count
let count++
done
</code></pre>
<h2>11.5. for</h2>
<pre><code class="language-shell"># for写法1
for ((count=0;$count&lt;5;count=$count+1))
do
echo $count
done
# for写法2
arr=(0 1 2 3 4)
for count in ${arr[*]}
do
echo $int
done
# for写法3
for int in 0 1 2 3 4
do
echo $int
done
</code></pre>
<h2>11.6. break和continue</h2>
<p>用法与一般编程语言类似,break跳出循环,continue跳出当前循环</p>
<pre><code class="language-shell">for ((count=0;$count&gt;=0;count=$count+1))
do
if (($count&gt;=5));then
break;
fi
echo $count
done
</code></pre>
<h1>12. 输入输出重定向</h1>
<h2>12.1. 输出重定向</h2>
<p><code>command &gt; file</code>将命令输出结果保存的file文件中。<code>&gt;</code>从文件头开始写,会覆盖旧内容,<code>&gt;&gt;</code>将内容追加到文件末尾</p>
<pre><code class="language-shell"># 将who命令的输出保存的users文件中,可以通过cat users查看
who &gt; users
# 将字符串hello world保存到text.txt文件中
echo &quot;hello world&quot; &gt; text.txt
</code></pre>
<h2>12.2. 输入重定向</h2>
<p><code>command &lt; file</code>从file文件获取输入</p>
<pre><code class="language-shell">wc -l /etc/passwd
# 123 /etc/passwd
wc -l &lt; users
# 123
# 第一个例子,会输出文件名;第二个不会,因为它仅仅知道从标准输入读取内容
# command &lt; infile &gt; outfile, 同时替换输入和输出,执行command,从文件infile读取内容,然后将输出写入到outfile中。
wc -l &lt; /etc/passwd &gt; result
cat result
# 123
</code></pre>
<h2>12.3. 文件描述符</h2>
<p>一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件</p>
<ul>
<li>标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。</li>
<li>标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。</li>
<li>标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。</li>
</ul>
<pre><code class="language-shell"># 将标准错误输出重定向到error_trace
cat /tmp/fake_file 2&gt;error_trace
cat error_trace
# cat: /tmp/fake_fule: No such file or directory
# 将标准输出和标准错误输出都重定向到result
cat /tmp/fake_file &amp;&gt;result
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准错误重定向到标准输出
ls /tmp/fake_file &gt; result 2&gt;&amp;1
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准输入重定向到result,将标准错误输出重定向到error_trace
cat /tmp/fake_file 1&gt;result 2&gt;error_trace
</code></pre>
<h2>12.4. Here Document</h2>
<p>将两个<code>EOF</code>之间的内容(document) 作为输入传递给<code>command</code></p>
<pre><code class="language-bash"># command &lt;&lt; EOF
# document
# EOF
cat &lt;&lt; EOF
hello
shinerio
learn shell
EOF
</code></pre>
<blockquote>
<p>结尾的<code>EOF</code>一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和<code>tab</code>缩进。开始的<code>EOF</code>前后的空格会被忽略掉。</p>
</blockquote>
<h2>12.5. /dev/null</h2>
<p>如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null。<code>command &gt; /dev/null</code></p>
<pre><code class="language-shell">cat users &gt; /dev/null
cat users &gt; /dev/null 2&gt;&amp;1
</code></pre>
<h1>13. set命令</h1>
<p>set指令能设置所使用shell的执行方式,可依照不同的需求来做设置。以下只列出常用的选项参数:</p>
<ul>
<li>-e 若指令传回值不等于0,则立即退出shell。</li>
<li>-f 取消使用通配符。</li>
<li>-n 只读取指令,而不实际执行。</li>
<li>-x 执行指令后,会先显示该指令及所下的参数。</li>
</ul>
#39;hello' ];then echo 'hello';fi
str='hello'
if [ $str ];then echo 'hello';fi
# hello
</code></pre>
<p>注意字符串的等值判断是一个等号<code>"="</code>,与下文要讲的逻辑运算符使用两个等号<code>"=="</code>做等值判断不一样。</p>
<h1>4. 文件测试运算符</h1>
<table>
<thead>
<tr>
<th>操作符</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>-b file</code></td>
<td>检测文件是否是块设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-c file</code></td>
<td>检测文件是否是字符设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-d file</code></td>
<td>检测文件是否是目录,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-f file</code></td>
<td>检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-g file</code></td>
<td>检测文件是否设置了<code>SGID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-k file</code></td>
<td>检测文件是否设置了粘着位(Sticky Bit),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-p file</code></td>
<td>检测文件是否是有名管道,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-u file</code></td>
<td>检测文件是否设置了<code>SUID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-r file</code></td>
<td>检测文件是否可读,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-w file</code></td>
<td>检测文件是否可写,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-x file</code></td>
<td>检测文件是否可执行,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-s file</code></td>
<td>检测文件是否为空(文件大小是否大于0),不为空返回true。</td>
</tr>
<tr>
<td><code>-e file</code></td>
<td>检测文件(包括目录)是否存在,如果是,则返回true。</td>
</tr>
</tbody></table>
<pre><code class="language-shell">if <a href="f-home.html" class="internal-link"> -f '/home' </a>;then echo 'directory';else echo 'file';fi
# file
if <a href="d-home.html" class="internal-link"> -d '/home' </a>;then echo 'directory';else echo 'file';fi
# directory
if <a href="e-tmpfake-file.html" class="internal-link"> -e '/tmp/fake_file' </a>;then echo 'exist';else echo 'not exist';fi
# not exist
</code></pre>
<h1>5. 数组</h1>
<p><code>shell</code>只支持一维数组,用括号表示,元素通过空格分隔,形如<code>数组名=(值1 值2 ... 值n)</code>。<code>shell</code>数组下标从<code>1</code>开始。</p>
<ul>
<li><code>${数组名[下标]}</code>,读取指索引位置数组元素</li>
<li>使用<code>@</code>或<code>*</code>代替下标,获取数组中所有元素。</li>
<li>使用<code>{<span class="tag">#数组名</span>[@]}</code>或<code>{<span class="tag">#数组名</span>[*]}</code>获取数组元素个数。</li>
</ul>
<pre><code class="language-shell">arr=(value1 value2 value3 value4)
echo ${arr[3]}
# value3
echo ${arr[*]}
# value1 value2 value3 value4
echo ${arr[@]}
# value1 value2 value3 value4
arr[3]='new_value3'
echo $arr[3]
# new_value3
echo ${<span class="tag">#arr</span>[@]}
# 4
echo "arr[1]的长度为:${<span class="tag">#arr</span>[1]}"
# arr[1]的长度为:6
</code></pre>
<h1>6. 运算符</h1>
<h2>6.1. 赋值运算符</h2>
<pre><code class="language-shell">a=10
b=$a
</code></pre>
<h2>6.2. 算术运算符</h2>
<p>算数运算符支持<code>+,-,*,/,%</code></p>
<h3>6.2.1. expr表示法</h3>
<pre><code class="language-shell">echo `expr 10 + 20`
# 30
echo $(expr 20 / 2)
# 10
echo $(expr 10 \* 20) # 使用expr进行乘法运算时必须使用\进行转义
# 200
</code></pre>
<blockquote>
<p>使用expr表示方法时,表达式和运算符之间必须有空格。</p>
</blockquote>
<h3>6.2.2. <code>$[]</code></h3>
<pre><code class="language-shell">echo $[10%3]
# 1
</code></pre>
<h3>6.2.3. <code>$(())</code></h3>
<pre><code class="language-shell">echo $((10*20))
# 200
</code></pre>
<h2>6.3. 关系运算符</h2>
<p>最常见的关系运算符是:<code>==,!=,<,>,>=,<=</code></p>
<pre><code class="language-shell">echo $[10==10]
# 1
flag=$[20==10]
echo $flag
# 1
echo $[10>=10]
# 1
</code></pre>
<p>如下关系运算符只能使用在条件表达式<code>if、while</code>下,类似<code>flag=[ $a -eq $b ]</code>的直接赋值语句是非法的。关系运算符的条件表达式要放在<strong>一对</strong>方括号中,并且中间需要有空格。也可以使用<code>(())</code>替代<code>[]</code>,此时<code>-eq,-lt,-le</code>之类的需要使用<code>==,<,<=</code>等替换。</p>
<blockquote>
<p><code>[]</code>搭配<code>-eq -ne</code>等使用,<code>(())</code>搭配<code>|| &&</code>等使用。</p>
</blockquote>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>-eq</code></td>
<td>检测两个数是否相等,相等返回true。</td>
<td><code>[ $a -eq $b ]</code></td>
</tr>
<tr>
<td><code>-ne</code></td>
<td>检测两个数是否不相等,不相等返回 true。</td>
<td><code>[ $a -ne $b ]</code></td>
</tr>
<tr>
<td><code>-gt</code></td>
<td>检测左边的数是否大于右边的,如果是,则返回 true。</td>
<td><code>[ $a -gt $b ]</code></td>
</tr>
<tr>
<td><code>-lt</code></td>
<td>检测左边的数是否小于右边的,如果是,则返回 true。</td>
<td><code>[ $a -lt $b ]</code></td>
</tr>
<tr>
<td><code>-ge</code></td>
<td>检测左边的数是否大于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -ge $b ]</code></td>
</tr>
<tr>
<td><code>-le</code></td>
<td>检测左边的数是否小于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -le $b ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ 1 -eq 1 ];then echo 'hello';fi;
# hello
if ((10>=10));then echo 'hello';fi;
# hello
</code></pre>
<h2>6.4. 布尔、逻辑运算符</h2>
<p>布尔、逻辑运算的条件表达式也要放在一对方括号中<code>[]</code>。</p>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>!</code></td>
<td>非运算,表达式为true则返回false,否则返回true。</td>
<td><code>[ ! 10 -eq 0 ]</code></td>
</tr>
<tr>
<td><code>-o</code></td>
<td>或运算,有一个表达式为true则返回true。</td>
<td><code>[ 10 -lt 20 -o 10 -gt 100 ]</code></td>
</tr>
<tr>
<td><code>-a</code></td>
<td>与运算,两个表达式都为true才返回true。</td>
<td><code>[ 10 -lt 20 -a 10 -gt 100 ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ ! 10 -eq 0 ];then echo 'hello';fi
# hello
if [ 10 -ge 10 -a 10 -ge 10 ];then echo 'hello';fi
# hello
if [ 10 -ge 20 -o 10 -ge 0 ];then echo 'hello';fi
# hello
</code></pre>
<p> <code>-o</code>也可以使用<code>||</code>替代,<code>-a</code>也可以使用<code>&&</code>替代,此时需要使用<code>(())</code>或<code>[[]]</code>替代<code>[]</code>。</p>
<pre><code class="language-shell">if <a href="1010-55.html" class="internal-link"> 10==10 && 5==5 </a>;then echo 'hello';fi
# hello
if ((10==10 && 5==5));then echo 'hello';fi
# hello
</code></pre>
<h1>7. 传递参数</h1>
<p>在执行 <code>Shell</code>脚本时,向脚本传递参数,脚本内获取参数的格式为:<code>$n</code>。<code>n</code>代表一个数字,<code>1</code>为执行脚本的第一个参数,<code>2</code>为执行脚本的第二个参数,<code>$0</code>为执行的文件名。在为<code>shell</code>脚本传递的参数中如果包含空格,应该使用单引号或者双引号将该参数括起来,以便于脚本将这个参数作为整体来接收。另外,还有几个特殊字符用来处理参数:</p>
<table>
<thead>
<tr>
<th>参数处理</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>$#</code></td>
<td>传递到脚本的参数个数</td>
</tr>
<tr>
<td><code>$*</code></td>
<td>以一个单字符串显示所有向脚本传递的参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$</code></td>
<td>脚本运行的当前进程ID号</td>
</tr>
<tr>
<td><code>$!</code></td>
<td>后台运行的最后一个进程的ID号</td>
</tr>
<tr>
<td><code>$@</code></td>
<td>与<code>$*</code>相同,但是使用时加引号,并在引号中返回每个参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$-</code></td>
<td>显示Shell使用的当前选项,与set功能相同。</td>
</tr>
<tr>
<td><code>$?</code></td>
<td>显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。</td>
</tr>
</tbody></table>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-bash">set -e
echo "执行的文件名:$0"
echo "参数个数为$#"
echo "第一个参数为:$1"
echo "第二个参数为:$2"
echo "所有参数为:$@"
echo "进程ID号为:$"
echo "当前shell选项为$-"
echo "上一个命令退出的状态为$?"
</code></pre>
<p>执行结果如下:</p>
<pre><code class="language-shell">$ sh test.sh param1 "param2 with space"
执行的文件名:test.sh
参数个数为2
第一个参数为:param1
第二个参数为:param2 with space
所有参数为:param1 param2 with space
进程ID号为:3700
当前shell选项为ehB
上一个命令退出的状态为0
</code></pre>
<h1>8. 函数</h1>
<p>函数定义通过<code>function_name(){}</code>的形式定义,函数返回值可以显示用return返回,如果不加,将以最后一条命令的运行结果作为返回值,函数返回值只能是数字。函数也可以传递参数,但是函数定义的()中不需要申明。</p>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-shell">sayhello(){
echo "hello"
}
# 注意函数调用只需要函数名,不需要加()
sayhello
sayhellowithparam(){
echo "hello, $1 $2 $3"
return 1
}
sayhellowithparam zhangsan lisi wangwu
echo $?
</code></pre>
<p>输出如下:</p>
<blockquote>
<p>hello<br>hello, zhangsan lisi wangwu<br>1</p>
</blockquote>
<h1>9. 命令替换</h1>
<p>命令替换可以将一个命令的输出作为另外一个命令的参数。</p>
<pre><code class="language-shell"># command1 `command2`
cd `pwd` # 该命令将pwd命令列出的目录作为cd命令的参数,结果仍然是停留在当前目录下
cd `echo $HOME` # 将echo的输出作为cd的参数,即打开用户根目录
</code></pre>
<h1>10. let命令</h1>
<p>let 命令是 BASH 中用于计算的工具,用于执行一个或多个表达式,变量计算中不需要加上 $ 来表示变量。如果表达式中包含了空格或其他特殊字符,则必须引起来。</p>
<ul>
<li>自加操作:<code>let no++</code></li>
<li>自减操作:<code>let no--</code></li>
<li>简写形式 <code>let no+=10</code>,<code>let no-=20</code>,分别等同于<code>let no=no+10</code>,<code>let no=no-20</code></li>
</ul>
<h1>11. 流程控制</h1>
<h2>11.1. if</h2>
<pre><code class="language-shell">if ((10<2));then
echo "10小于2"
elif ((10>20));then
echo "a大于10"
else
echo "10大于2且小于10"
fi
</code></pre>
<h2>11.2. case</h2>
<p><code>case</code>每一种情况以右括号结尾,执行到<code>;;</code>结束</p>
<pre><code class="language-shell">case 10 in
0|1)
echo "a为0或1"
;;
11|12)
echo "a为11或12"
;;
*)
# *用来匹配所有情况
echo "a为10"
;;
esac
</code></pre>
<h2>11.3. while</h2>
<pre><code class="language-shell">count=0
while(($count<5))
do
echo $count
let count++
done
</code></pre>
<h2>11.4. util</h2>
<pre><code class="language-shell">count=0
until(($count>=5))
do
echo $count
let count++
done
</code></pre>
<h2>11.5. for</h2>
<pre><code class="language-shell"># for写法1
for ((count=0;$count<5;count=$count+1))
do
echo $count
done
# for写法2
arr=(0 1 2 3 4)
for count in ${arr[*]}
do
echo $int
done
# for写法3
for int in 0 1 2 3 4
do
echo $int
done
</code></pre>
<h2>11.6. break和continue</h2>
<p>用法与一般编程语言类似,break跳出循环,continue跳出当前循环</p>
<pre><code class="language-shell">for ((count=0;$count>=0;count=$count+1))
do
if (($count>=5));then
break;
fi
echo $count
done
</code></pre>
<h1>12. 输入输出重定向</h1>
<h2>12.1. 输出重定向</h2>
<p><code>command > file</code>将命令输出结果保存的file文件中。<code>></code>从文件头开始写,会覆盖旧内容,<code>>></code>将内容追加到文件末尾</p>
<pre><code class="language-shell"># 将who命令的输出保存的users文件中,可以通过cat users查看
who > users
# 将字符串hello world保存到text.txt文件中
echo "hello world" > text.txt
</code></pre>
<h2>12.2. 输入重定向</h2>
<p><code>command < file</code>从file文件获取输入</p>
<pre><code class="language-shell">wc -l /etc/passwd
# 123 /etc/passwd
wc -l < users
# 123
# 第一个例子,会输出文件名;第二个不会,因为它仅仅知道从标准输入读取内容
# command < infile > outfile, 同时替换输入和输出,执行command,从文件infile读取内容,然后将输出写入到outfile中。
wc -l < /etc/passwd > result
cat result
# 123
</code></pre>
<h2>12.3. 文件描述符</h2>
<p>一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件</p>
<ul>
<li>标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。</li>
<li>标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。</li>
<li>标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。</li>
</ul>
<pre><code class="language-shell"># 将标准错误输出重定向到error_trace
cat /tmp/fake_file 2>error_trace
cat error_trace
# cat: /tmp/fake_fule: No such file or directory
# 将标准输出和标准错误输出都重定向到result
cat /tmp/fake_file &>result
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准错误重定向到标准输出
ls /tmp/fake_file > result 2>&1
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准输入重定向到result,将标准错误输出重定向到error_trace
cat /tmp/fake_file 1>result 2>error_trace
</code></pre>
<h2>12.4. Here Document</h2>
<p>将两个<code>EOF</code>之间的内容(document) 作为输入传递给<code>command</code></p>
<pre><code class="language-bash"># command << EOF
# document
# EOF
cat << EOF
hello
shinerio
learn shell
EOF
</code></pre>
<blockquote>
<p>结尾的<code>EOF</code>一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和<code>tab</code>缩进。开始的<code>EOF</code>前后的空格会被忽略掉。</p>
</blockquote>
<h2>12.5. /dev/null</h2>
<p>如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null。<code>command > /dev/null</code></p>
<pre><code class="language-shell">cat users > /dev/null
cat users > /dev/null 2>&1
</code></pre>
<h1>13. set命令</h1>
<p>set指令能设置所使用shell的执行方式,可依照不同的需求来做设置。以下只列出常用的选项参数:</p>
<ul>
<li>-e 若指令传回值不等于0,则立即退出shell。</li>
<li>-f 取消使用通配符。</li>
<li>-n 只读取指令,而不实际执行。</li>
<li>-x 执行指令后,会先显示该指令及所下的参数。</li>
</ul>
</section>
</article>lt;/code></td>
<td>检测字符串是否为空,不为空返回true</td>
<td><code>[ <article>
<header>
<h1>shell编程</h1>
<time datetime="2023-01-24T00:00:00.000Z">2023年1月24日</time>
<div class="tags">
<span class="tag">linux</span>
</div>
</header>
<section class="content">
<p>本文主要介绍shell编程的基本语法以及实际应用中的常见命令。</p>
<h1>1. 注释</h1>
<h2>1.1. 单行注释</h2>
<pre><code class="language-shell"># 这是单行注释
</code></pre>
<h2>1.2. 多行注释</h2>
<pre><code class="language-shell">:<<EOF
多行注释内容
多行注释内容
多行注释内容
EOF
</code></pre>
<p>多行注释<code>EOF</code>也可替换成<code>!</code>或<code>'</code></p>
<pre><code class="language-shell">:<<'
多行注释内容
多行注释内容
多行注释内容
'
:<<!
多行注释内容
多行注释内容
多行注释内容
!
</code></pre>
<h1>2. 变量</h1>
<h2>2.1. 变量定义</h2>
<p>使用<code>VARIABLENAME=VALUE</code>的形式,VALUE如果是字符串的话,可以使用单引号、双引号或者不加引号。单引号内的任何字符都会原样输出,不能进行转义,单引号内不能单独出现一个单引号,但可成对出现,作为字符串拼接使用。双引号内可以有变量,可以出现转义字符。</p>
<h2>2.2. 变量使用</h2>
<p>只需要在变量前加<code>$</code>符号,变量加<code>{}</code>是可选的,方便解释器识别边界。将变量加上<code>{}</code>是一个好习惯,不容易出错。</p>
<pre><code class="language-shell">your_age=25
your_name="shinerio"
your_name=shinerio
your_name='shinerio'
echo $your_age # 输出25
echo $your_name # 输出shinerio
echo "${your_name}hello" <span class="tag">#这里</span>{}必须添加,否则解释器认为是${your_namehello}
str='hello'' # 非法
str='hello'__'world' # 成对出现的单引号做字符拼接
echo $str <span class="tag">#输出hello__world</span>
str1='helloworld${your_age}\nnew line'
str2="helloworld${your_age}\nnew line"
echo $str1 # 输出helloworld${your_age}\nnew line
echo $str2 # 输出helloworld25\nnew line
echo -e $str2 # -e开启转义 \n表示换行 echo默认换行,通过\c强制不换行
<span class="tag">#helloworld25</span>
<span class="tag">#new</span> line
</code></pre>
<h2>2.3. 只读变量</h2>
<p>使用<code>readonly VARIABLENAME</code>设置变量只读,只读变量的值不能更改</p>
<pre><code class="language-shell">readonly name='jack'
name='kelly'
zsh: read-only variable: name
</code></pre>
<h2>2.4. 删除变量</h2>
<p>使用<code>unset VARIABLENAME</code>删除变量。</p>
<h1>3. 字符串操作</h1>
<h2>3.1. 字符串拼接</h2>
<pre><code class="language-shell">str1="hello"${your_name}"world"
str2="hello${your_name}world"
str3='hello'${your_name}'world'
</code></pre>
<h2>3.2. 字符串长度</h2>
<pre><code class="language-shell">str='hello'
echo ${<span class="tag">#str</span>}
5
</code></pre>
<h2>3.3. 字符串截取</h2>
<p><code>${string:start:length}</code>,索引从0开始,从start(包含)开始截取共计length长度的字符。</p>
<pre><code class="language-shell">str='helloworld'
echo ${str:0:5}
hello
</code></pre>
<h2>3.4. 字符串运算符</h2>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>=</code></td>
<td>检测两个字符串是否相等,相等返回true</td>
<td><code>[ 'hello' = 'hello' ]</code></td>
</tr>
<tr>
<td><code>!=</code></td>
<td>检测两个字符串是否相等,不相等返回true</td>
<td><code>[ 'hello' != 'ello' ]</code></td>
</tr>
<tr>
<td><code>-z</code></td>
<td>检测字符串长度是否为0,为0返回true</td>
<td><code>[ -z '' ]</code></td>
</tr>
<tr>
<td><code>-n </code></td>
<td>检测字符串长度是否不为0,不为0返回true</td>
<td><code>[ -n 'hello' ]</code></td>
</tr>
<tr>
<td><code>$</code></td>
<td>检测字符串是否为空,不为空返回true</td>
<td><code>[ <p>本文主要介绍shell编程的基本语法以及实际应用中的常见命令。</p>
<h1>1. 注释</h1>
<h2>1.1. 单行注释</h2>
<pre><code class="language-shell"># 这是单行注释
</code></pre>
<h2>1.2. 多行注释</h2>
<pre><code class="language-shell">:&lt;&lt;EOF
多行注释内容
多行注释内容
多行注释内容
EOF
</code></pre>
<p>多行注释<code>EOF</code>也可替换成<code>!</code>或<code>&#39;</code></p>
<pre><code class="language-shell">:&lt;&lt;&#39;
多行注释内容
多行注释内容
多行注释内容
&#39;
:&lt;&lt;!
多行注释内容
多行注释内容
多行注释内容
!
</code></pre>
<h1>2. 变量</h1>
<h2>2.1. 变量定义</h2>
<p>使用<code>VARIABLENAME=VALUE</code>的形式,VALUE如果是字符串的话,可以使用单引号、双引号或者不加引号。单引号内的任何字符都会原样输出,不能进行转义,单引号内不能单独出现一个单引号,但可成对出现,作为字符串拼接使用。双引号内可以有变量,可以出现转义字符。</p>
<h2>2.2. 变量使用</h2>
<p>只需要在变量前加<code>$</code>符号,变量加<code>{}</code>是可选的,方便解释器识别边界。将变量加上<code>{}</code>是一个好习惯,不容易出错。</p>
<pre><code class="language-shell">your_age=25
your_name=&quot;shinerio&quot;
your_name=shinerio
your_name=&#39;shinerio&#39;
echo $your_age # 输出25
echo $your_name # 输出shinerio
echo &quot;${your_name}hello&quot; &lt;span class=&quot;tag&quot;&gt;#这里&lt;/span&gt;{}必须添加,否则解释器认为是${your_namehello}
str=&#39;hello&#39;&#39; # 非法
str=&#39;hello&#39;__&#39;world&#39; # 成对出现的单引号做字符拼接
echo $str &lt;span class=&quot;tag&quot;&gt;#输出hello__world&lt;/span&gt;
str1=&#39;helloworld${your_age}\nnew line&#39;
str2=&quot;helloworld${your_age}\nnew line&quot;
echo $str1 # 输出helloworld${your_age}\nnew line
echo $str2 # 输出helloworld25\nnew line
echo -e $str2 # -e开启转义 \n表示换行 echo默认换行,通过\c强制不换行
&lt;span class=&quot;tag&quot;&gt;#helloworld25&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;#new&lt;/span&gt; line
</code></pre>
<h2>2.3. 只读变量</h2>
<p>使用<code>readonly VARIABLENAME</code>设置变量只读,只读变量的值不能更改</p>
<pre><code class="language-shell">readonly name=&#39;jack&#39;
name=&#39;kelly&#39;
zsh: read-only variable: name
</code></pre>
<h2>2.4. 删除变量</h2>
<p>使用<code>unset VARIABLENAME</code>删除变量。</p>
<h1>3. 字符串操作</h1>
<h2>3.1. 字符串拼接</h2>
<pre><code class="language-shell">str1=&quot;hello&quot;${your_name}&quot;world&quot;
str2=&quot;hello${your_name}world&quot;
str3=&#39;hello&#39;${your_name}&#39;world&#39;
</code></pre>
<h2>3.2. 字符串长度</h2>
<pre><code class="language-shell">str=&#39;hello&#39;
echo ${&lt;span class=&quot;tag&quot;&gt;#str&lt;/span&gt;}
5
</code></pre>
<h2>3.3. 字符串截取</h2>
<p><code>${string:start:length}</code>,索引从0开始,从start(包含)开始截取共计length长度的字符。</p>
<pre><code class="language-shell">str=&#39;helloworld&#39;
echo ${str:0:5}
hello
</code></pre>
<h2>3.4. 字符串运算符</h2>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>=</code></td>
<td>检测两个字符串是否相等,相等返回true</td>
<td><code>[ &#39;hello&#39; = &#39;hello&#39; ]</code></td>
</tr>
<tr>
<td><code>!=</code></td>
<td>检测两个字符串是否相等,不相等返回true</td>
<td><code>[ &#39;hello&#39; != &#39;ello&#39; ]</code></td>
</tr>
<tr>
<td><code>-z</code></td>
<td>检测字符串长度是否为0,为0返回true</td>
<td><code>[ -z &#39;&#39; ]</code></td>
</tr>
<tr>
<td><code>-n </code></td>
<td>检测字符串长度是否不为0,不为0返回true</td>
<td><code>[ -n &#39;hello&#39; ]</code></td>
</tr>
<tr>
<td><code>$</code></td>
<td>检测字符串是否为空,不为空返回true</td>
<td><code>[ $&#39;hello&#39; ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ &#39;hello&#39; = &#39;hello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ &#39;hello&#39; != &#39;ello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ -z &#39;&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ -n &#39;hello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ $&#39;hello&#39; ];then echo &#39;hello&#39;;fi
str=&#39;hello&#39;
if [ $str ];then echo &#39;hello&#39;;fi
# hello
</code></pre>
<p>注意字符串的等值判断是一个等号<code>&quot;=&quot;</code>,与下文要讲的逻辑运算符使用两个等号<code>&quot;==&quot;</code>做等值判断不一样。</p>
<h1>4. 文件测试运算符</h1>
<table>
<thead>
<tr>
<th>操作符</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>-b file</code></td>
<td>检测文件是否是块设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-c file</code></td>
<td>检测文件是否是字符设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-d file</code></td>
<td>检测文件是否是目录,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-f file</code></td>
<td>检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-g file</code></td>
<td>检测文件是否设置了<code>SGID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-k file</code></td>
<td>检测文件是否设置了粘着位(Sticky Bit),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-p file</code></td>
<td>检测文件是否是有名管道,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-u file</code></td>
<td>检测文件是否设置了<code>SUID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-r file</code></td>
<td>检测文件是否可读,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-w file</code></td>
<td>检测文件是否可写,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-x file</code></td>
<td>检测文件是否可执行,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-s file</code></td>
<td>检测文件是否为空(文件大小是否大于0),不为空返回true。</td>
</tr>
<tr>
<td><code>-e file</code></td>
<td>检测文件(包括目录)是否存在,如果是,则返回true。</td>
</tr>
</tbody></table>
<pre><code class="language-shell">if &lt;a href=&quot;f-home.html&quot; class=&quot;internal-link&quot;&gt; -f &#39;/home&#39; &lt;/a&gt;;then echo &#39;directory&#39;;else echo &#39;file&#39;;fi
# file
if &lt;a href=&quot;d-home.html&quot; class=&quot;internal-link&quot;&gt; -d &#39;/home&#39; &lt;/a&gt;;then echo &#39;directory&#39;;else echo &#39;file&#39;;fi
# directory
if &lt;a href=&quot;e-tmpfake-file.html&quot; class=&quot;internal-link&quot;&gt; -e &#39;/tmp/fake_file&#39; &lt;/a&gt;;then echo &#39;exist&#39;;else echo &#39;not exist&#39;;fi
# not exist
</code></pre>
<h1>5. 数组</h1>
<p><code>shell</code>只支持一维数组,用括号表示,元素通过空格分隔,形如<code>数组名=(值1 值2 ... 值n)</code>。<code>shell</code>数组下标从<code>1</code>开始。</p>
<ul>
<li><code>${数组名[下标]}</code>,读取指索引位置数组元素</li>
<li>使用<code>@</code>或<code>*</code>代替下标,获取数组中所有元素。</li>
<li>使用<code>{&lt;span class=&quot;tag&quot;&gt;#数组名&lt;/span&gt;[@]}</code>或<code>{&lt;span class=&quot;tag&quot;&gt;#数组名&lt;/span&gt;[*]}</code>获取数组元素个数。</li>
</ul>
<pre><code class="language-shell">arr=(value1 value2 value3 value4)
echo ${arr[3]}
# value3
echo ${arr[*]}
# value1 value2 value3 value4
echo ${arr[@]}
# value1 value2 value3 value4
arr[3]=&#39;new_value3&#39;
echo $arr[3]
# new_value3
echo ${&lt;span class=&quot;tag&quot;&gt;#arr&lt;/span&gt;[@]}
# 4
echo &quot;arr[1]的长度为:${&lt;span class=&quot;tag&quot;&gt;#arr&lt;/span&gt;[1]}&quot;
# arr[1]的长度为:6
</code></pre>
<h1>6. 运算符</h1>
<h2>6.1. 赋值运算符</h2>
<pre><code class="language-shell">a=10
b=$a
</code></pre>
<h2>6.2. 算术运算符</h2>
<p>算数运算符支持<code>+,-,*,/,%</code></p>
<h3>6.2.1. expr表示法</h3>
<pre><code class="language-shell">echo `expr 10 + 20`
# 30
echo $(expr 20 / 2)
# 10
echo $(expr 10 \* 20) # 使用expr进行乘法运算时必须使用\进行转义
# 200
</code></pre>
<blockquote>
<p>使用expr表示方法时,表达式和运算符之间必须有空格。</p>
</blockquote>
<h3>6.2.2. <code>$[]</code></h3>
<pre><code class="language-shell">echo $[10%3]
# 1
</code></pre>
<h3>6.2.3. <code>$(())</code></h3>
<pre><code class="language-shell">echo $((10*20))
# 200
</code></pre>
<h2>6.3. 关系运算符</h2>
<p>最常见的关系运算符是:<code>==,!=,&lt;,&gt;,&gt;=,&lt;=</code></p>
<pre><code class="language-shell">echo $[10==10]
# 1
flag=$[20==10]
echo $flag
# 1
echo $[10&gt;=10]
# 1
</code></pre>
<p>如下关系运算符只能使用在条件表达式<code>if、while</code>下,类似<code>flag=[ $a -eq $b ]</code>的直接赋值语句是非法的。关系运算符的条件表达式要放在<strong>一对</strong>方括号中,并且中间需要有空格。也可以使用<code>(())</code>替代<code>[]</code>,此时<code>-eq,-lt,-le</code>之类的需要使用<code>==,&lt;,&lt;=</code>等替换。</p>
<blockquote>
<p><code>[]</code>搭配<code>-eq -ne</code>等使用,<code>(())</code>搭配<code>|| &amp;&amp;</code>等使用。</p>
</blockquote>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>-eq</code></td>
<td>检测两个数是否相等,相等返回true。</td>
<td><code>[ $a -eq $b ]</code></td>
</tr>
<tr>
<td><code>-ne</code></td>
<td>检测两个数是否不相等,不相等返回 true。</td>
<td><code>[ $a -ne $b ]</code></td>
</tr>
<tr>
<td><code>-gt</code></td>
<td>检测左边的数是否大于右边的,如果是,则返回 true。</td>
<td><code>[ $a -gt $b ]</code></td>
</tr>
<tr>
<td><code>-lt</code></td>
<td>检测左边的数是否小于右边的,如果是,则返回 true。</td>
<td><code>[ $a -lt $b ]</code></td>
</tr>
<tr>
<td><code>-ge</code></td>
<td>检测左边的数是否大于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -ge $b ]</code></td>
</tr>
<tr>
<td><code>-le</code></td>
<td>检测左边的数是否小于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -le $b ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ 1 -eq 1 ];then echo &#39;hello&#39;;fi;
# hello
if ((10&gt;=10));then echo &#39;hello&#39;;fi;
# hello
</code></pre>
<h2>6.4. 布尔、逻辑运算符</h2>
<p>布尔、逻辑运算的条件表达式也要放在一对方括号中<code>[]</code>。</p>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>!</code></td>
<td>非运算,表达式为true则返回false,否则返回true。</td>
<td><code>[ ! 10 -eq 0 ]</code></td>
</tr>
<tr>
<td><code>-o</code></td>
<td>或运算,有一个表达式为true则返回true。</td>
<td><code>[ 10 -lt 20 -o 10 -gt 100 ]</code></td>
</tr>
<tr>
<td><code>-a</code></td>
<td>与运算,两个表达式都为true才返回true。</td>
<td><code>[ 10 -lt 20 -a 10 -gt 100 ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ ! 10 -eq 0 ];then echo &#39;hello&#39;;fi
# hello
if [ 10 -ge 10 -a 10 -ge 10 ];then echo &#39;hello&#39;;fi
# hello
if [ 10 -ge 20 -o 10 -ge 0 ];then echo &#39;hello&#39;;fi
# hello
</code></pre>
<p> <code>-o</code>也可以使用<code>||</code>替代,<code>-a</code>也可以使用<code>&amp;&amp;</code>替代,此时需要使用<code>(())</code>或<code>[[]]</code>替代<code>[]</code>。</p>
<pre><code class="language-shell">if &lt;a href=&quot;1010-55.html&quot; class=&quot;internal-link&quot;&gt; 10==10 &amp;&amp; 5==5 &lt;/a&gt;;then echo &#39;hello&#39;;fi
# hello
if ((10==10 &amp;&amp; 5==5));then echo &#39;hello&#39;;fi
# hello
</code></pre>
<h1>7. 传递参数</h1>
<p>在执行 <code>Shell</code>脚本时,向脚本传递参数,脚本内获取参数的格式为:<code>$n</code>。<code>n</code>代表一个数字,<code>1</code>为执行脚本的第一个参数,<code>2</code>为执行脚本的第二个参数,<code>$0</code>为执行的文件名。在为<code>shell</code>脚本传递的参数中如果包含空格,应该使用单引号或者双引号将该参数括起来,以便于脚本将这个参数作为整体来接收。另外,还有几个特殊字符用来处理参数:</p>
<table>
<thead>
<tr>
<th>参数处理</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>$#</code></td>
<td>传递到脚本的参数个数</td>
</tr>
<tr>
<td><code>$*</code></td>
<td>以一个单字符串显示所有向脚本传递的参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$$</code></td>
<td>脚本运行的当前进程ID号</td>
</tr>
<tr>
<td><code>$!</code></td>
<td>后台运行的最后一个进程的ID号</td>
</tr>
<tr>
<td><code>$@</code></td>
<td>与<code>$*</code>相同,但是使用时加引号,并在引号中返回每个参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$-</code></td>
<td>显示Shell使用的当前选项,与set功能相同。</td>
</tr>
<tr>
<td><code>$?</code></td>
<td>显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。</td>
</tr>
</tbody></table>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-bash">set -e
echo &quot;执行的文件名:$0&quot;
echo &quot;参数个数为$#&quot;
echo &quot;第一个参数为:$1&quot;
echo &quot;第二个参数为:$2&quot;
echo &quot;所有参数为:$@&quot;
echo &quot;进程ID号为:$$&quot;
echo &quot;当前shell选项为$-&quot;
echo &quot;上一个命令退出的状态为$?&quot;
</code></pre>
<p>执行结果如下:</p>
<pre><code class="language-shell">$ sh test.sh param1 &quot;param2 with space&quot;
执行的文件名:test.sh
参数个数为2
第一个参数为:param1
第二个参数为:param2 with space
所有参数为:param1 param2 with space
进程ID号为:3700
当前shell选项为ehB
上一个命令退出的状态为0
</code></pre>
<h1>8. 函数</h1>
<p>函数定义通过<code>function_name(){}</code>的形式定义,函数返回值可以显示用return返回,如果不加,将以最后一条命令的运行结果作为返回值,函数返回值只能是数字。函数也可以传递参数,但是函数定义的()中不需要申明。</p>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-shell">sayhello(){
echo &quot;hello&quot;
}
# 注意函数调用只需要函数名,不需要加()
sayhello
sayhellowithparam(){
echo &quot;hello, $1 $2 $3&quot;
return 1
}
sayhellowithparam zhangsan lisi wangwu
echo $?
</code></pre>
<p>输出如下:</p>
<blockquote>
<p>hello<br>hello, zhangsan lisi wangwu<br>1</p>
</blockquote>
<h1>9. 命令替换</h1>
<p>命令替换可以将一个命令的输出作为另外一个命令的参数。</p>
<pre><code class="language-shell"># command1 `command2`
cd `pwd` # 该命令将pwd命令列出的目录作为cd命令的参数,结果仍然是停留在当前目录下
cd `echo $HOME` # 将echo的输出作为cd的参数,即打开用户根目录
</code></pre>
<h1>10. let命令</h1>
<p>let 命令是 BASH 中用于计算的工具,用于执行一个或多个表达式,变量计算中不需要加上 $ 来表示变量。如果表达式中包含了空格或其他特殊字符,则必须引起来。</p>
<ul>
<li>自加操作:<code>let no++</code></li>
<li>自减操作:<code>let no--</code></li>
<li>简写形式 <code>let no+=10</code>,<code>let no-=20</code>,分别等同于<code>let no=no+10</code>,<code>let no=no-20</code></li>
</ul>
<h1>11. 流程控制</h1>
<h2>11.1. if</h2>
<pre><code class="language-shell">if ((10&lt;2));then
echo &quot;10小于2&quot;
elif ((10&gt;20));then
echo &quot;a大于10&quot;
else
echo &quot;10大于2且小于10&quot;
fi
</code></pre>
<h2>11.2. case</h2>
<p><code>case</code>每一种情况以右括号结尾,执行到<code>;;</code>结束</p>
<pre><code class="language-shell">case 10 in
0|1)
echo &quot;a为0或1&quot;
;;
11|12)
echo &quot;a为11或12&quot;
;;
*)
# *用来匹配所有情况
echo &quot;a为10&quot;
;;
esac
</code></pre>
<h2>11.3. while</h2>
<pre><code class="language-shell">count=0
while(($count&lt;5))
do
echo $count
let count++
done
</code></pre>
<h2>11.4. util</h2>
<pre><code class="language-shell">count=0
until(($count&gt;=5))
do
echo $count
let count++
done
</code></pre>
<h2>11.5. for</h2>
<pre><code class="language-shell"># for写法1
for ((count=0;$count&lt;5;count=$count+1))
do
echo $count
done
# for写法2
arr=(0 1 2 3 4)
for count in ${arr[*]}
do
echo $int
done
# for写法3
for int in 0 1 2 3 4
do
echo $int
done
</code></pre>
<h2>11.6. break和continue</h2>
<p>用法与一般编程语言类似,break跳出循环,continue跳出当前循环</p>
<pre><code class="language-shell">for ((count=0;$count&gt;=0;count=$count+1))
do
if (($count&gt;=5));then
break;
fi
echo $count
done
</code></pre>
<h1>12. 输入输出重定向</h1>
<h2>12.1. 输出重定向</h2>
<p><code>command &gt; file</code>将命令输出结果保存的file文件中。<code>&gt;</code>从文件头开始写,会覆盖旧内容,<code>&gt;&gt;</code>将内容追加到文件末尾</p>
<pre><code class="language-shell"># 将who命令的输出保存的users文件中,可以通过cat users查看
who &gt; users
# 将字符串hello world保存到text.txt文件中
echo &quot;hello world&quot; &gt; text.txt
</code></pre>
<h2>12.2. 输入重定向</h2>
<p><code>command &lt; file</code>从file文件获取输入</p>
<pre><code class="language-shell">wc -l /etc/passwd
# 123 /etc/passwd
wc -l &lt; users
# 123
# 第一个例子,会输出文件名;第二个不会,因为它仅仅知道从标准输入读取内容
# command &lt; infile &gt; outfile, 同时替换输入和输出,执行command,从文件infile读取内容,然后将输出写入到outfile中。
wc -l &lt; /etc/passwd &gt; result
cat result
# 123
</code></pre>
<h2>12.3. 文件描述符</h2>
<p>一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件</p>
<ul>
<li>标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。</li>
<li>标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。</li>
<li>标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。</li>
</ul>
<pre><code class="language-shell"># 将标准错误输出重定向到error_trace
cat /tmp/fake_file 2&gt;error_trace
cat error_trace
# cat: /tmp/fake_fule: No such file or directory
# 将标准输出和标准错误输出都重定向到result
cat /tmp/fake_file &amp;&gt;result
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准错误重定向到标准输出
ls /tmp/fake_file &gt; result 2&gt;&amp;1
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准输入重定向到result,将标准错误输出重定向到error_trace
cat /tmp/fake_file 1&gt;result 2&gt;error_trace
</code></pre>
<h2>12.4. Here Document</h2>
<p>将两个<code>EOF</code>之间的内容(document) 作为输入传递给<code>command</code></p>
<pre><code class="language-bash"># command &lt;&lt; EOF
# document
# EOF
cat &lt;&lt; EOF
hello
shinerio
learn shell
EOF
</code></pre>
<blockquote>
<p>结尾的<code>EOF</code>一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和<code>tab</code>缩进。开始的<code>EOF</code>前后的空格会被忽略掉。</p>
</blockquote>
<h2>12.5. /dev/null</h2>
<p>如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null。<code>command &gt; /dev/null</code></p>
<pre><code class="language-shell">cat users &gt; /dev/null
cat users &gt; /dev/null 2&gt;&amp;1
</code></pre>
<h1>13. set命令</h1>
<p>set指令能设置所使用shell的执行方式,可依照不同的需求来做设置。以下只列出常用的选项参数:</p>
<ul>
<li>-e 若指令传回值不等于0,则立即退出shell。</li>
<li>-f 取消使用通配符。</li>
<li>-n 只读取指令,而不实际执行。</li>
<li>-x 执行指令后,会先显示该指令及所下的参数。</li>
</ul>
#39;hello' ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ 'hello' = 'hello' ];then echo 'hello';fi
# hello
if [ 'hello' != 'ello' ];then echo 'hello';fi
# hello
if [ -z '' ];then echo 'hello';fi
# hello
if [ -n 'hello' ];then echo 'hello';fi
# hello
if [ <p>本文主要介绍shell编程的基本语法以及实际应用中的常见命令。</p>
<h1>1. 注释</h1>
<h2>1.1. 单行注释</h2>
<pre><code class="language-shell"># 这是单行注释
</code></pre>
<h2>1.2. 多行注释</h2>
<pre><code class="language-shell">:&lt;&lt;EOF
多行注释内容
多行注释内容
多行注释内容
EOF
</code></pre>
<p>多行注释<code>EOF</code>也可替换成<code>!</code>或<code>&#39;</code></p>
<pre><code class="language-shell">:&lt;&lt;&#39;
多行注释内容
多行注释内容
多行注释内容
&#39;
:&lt;&lt;!
多行注释内容
多行注释内容
多行注释内容
!
</code></pre>
<h1>2. 变量</h1>
<h2>2.1. 变量定义</h2>
<p>使用<code>VARIABLENAME=VALUE</code>的形式,VALUE如果是字符串的话,可以使用单引号、双引号或者不加引号。单引号内的任何字符都会原样输出,不能进行转义,单引号内不能单独出现一个单引号,但可成对出现,作为字符串拼接使用。双引号内可以有变量,可以出现转义字符。</p>
<h2>2.2. 变量使用</h2>
<p>只需要在变量前加<code>$</code>符号,变量加<code>{}</code>是可选的,方便解释器识别边界。将变量加上<code>{}</code>是一个好习惯,不容易出错。</p>
<pre><code class="language-shell">your_age=25
your_name=&quot;shinerio&quot;
your_name=shinerio
your_name=&#39;shinerio&#39;
echo $your_age # 输出25
echo $your_name # 输出shinerio
echo &quot;${your_name}hello&quot; &lt;span class=&quot;tag&quot;&gt;#这里&lt;/span&gt;{}必须添加,否则解释器认为是${your_namehello}
str=&#39;hello&#39;&#39; # 非法
str=&#39;hello&#39;__&#39;world&#39; # 成对出现的单引号做字符拼接
echo $str &lt;span class=&quot;tag&quot;&gt;#输出hello__world&lt;/span&gt;
str1=&#39;helloworld${your_age}\nnew line&#39;
str2=&quot;helloworld${your_age}\nnew line&quot;
echo $str1 # 输出helloworld${your_age}\nnew line
echo $str2 # 输出helloworld25\nnew line
echo -e $str2 # -e开启转义 \n表示换行 echo默认换行,通过\c强制不换行
&lt;span class=&quot;tag&quot;&gt;#helloworld25&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;#new&lt;/span&gt; line
</code></pre>
<h2>2.3. 只读变量</h2>
<p>使用<code>readonly VARIABLENAME</code>设置变量只读,只读变量的值不能更改</p>
<pre><code class="language-shell">readonly name=&#39;jack&#39;
name=&#39;kelly&#39;
zsh: read-only variable: name
</code></pre>
<h2>2.4. 删除变量</h2>
<p>使用<code>unset VARIABLENAME</code>删除变量。</p>
<h1>3. 字符串操作</h1>
<h2>3.1. 字符串拼接</h2>
<pre><code class="language-shell">str1=&quot;hello&quot;${your_name}&quot;world&quot;
str2=&quot;hello${your_name}world&quot;
str3=&#39;hello&#39;${your_name}&#39;world&#39;
</code></pre>
<h2>3.2. 字符串长度</h2>
<pre><code class="language-shell">str=&#39;hello&#39;
echo ${&lt;span class=&quot;tag&quot;&gt;#str&lt;/span&gt;}
5
</code></pre>
<h2>3.3. 字符串截取</h2>
<p><code>${string:start:length}</code>,索引从0开始,从start(包含)开始截取共计length长度的字符。</p>
<pre><code class="language-shell">str=&#39;helloworld&#39;
echo ${str:0:5}
hello
</code></pre>
<h2>3.4. 字符串运算符</h2>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>=</code></td>
<td>检测两个字符串是否相等,相等返回true</td>
<td><code>[ &#39;hello&#39; = &#39;hello&#39; ]</code></td>
</tr>
<tr>
<td><code>!=</code></td>
<td>检测两个字符串是否相等,不相等返回true</td>
<td><code>[ &#39;hello&#39; != &#39;ello&#39; ]</code></td>
</tr>
<tr>
<td><code>-z</code></td>
<td>检测字符串长度是否为0,为0返回true</td>
<td><code>[ -z &#39;&#39; ]</code></td>
</tr>
<tr>
<td><code>-n </code></td>
<td>检测字符串长度是否不为0,不为0返回true</td>
<td><code>[ -n &#39;hello&#39; ]</code></td>
</tr>
<tr>
<td><code>$</code></td>
<td>检测字符串是否为空,不为空返回true</td>
<td><code>[ $&#39;hello&#39; ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ &#39;hello&#39; = &#39;hello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ &#39;hello&#39; != &#39;ello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ -z &#39;&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ -n &#39;hello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ $&#39;hello&#39; ];then echo &#39;hello&#39;;fi
str=&#39;hello&#39;
if [ $str ];then echo &#39;hello&#39;;fi
# hello
</code></pre>
<p>注意字符串的等值判断是一个等号<code>&quot;=&quot;</code>,与下文要讲的逻辑运算符使用两个等号<code>&quot;==&quot;</code>做等值判断不一样。</p>
<h1>4. 文件测试运算符</h1>
<table>
<thead>
<tr>
<th>操作符</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>-b file</code></td>
<td>检测文件是否是块设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-c file</code></td>
<td>检测文件是否是字符设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-d file</code></td>
<td>检测文件是否是目录,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-f file</code></td>
<td>检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-g file</code></td>
<td>检测文件是否设置了<code>SGID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-k file</code></td>
<td>检测文件是否设置了粘着位(Sticky Bit),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-p file</code></td>
<td>检测文件是否是有名管道,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-u file</code></td>
<td>检测文件是否设置了<code>SUID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-r file</code></td>
<td>检测文件是否可读,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-w file</code></td>
<td>检测文件是否可写,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-x file</code></td>
<td>检测文件是否可执行,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-s file</code></td>
<td>检测文件是否为空(文件大小是否大于0),不为空返回true。</td>
</tr>
<tr>
<td><code>-e file</code></td>
<td>检测文件(包括目录)是否存在,如果是,则返回true。</td>
</tr>
</tbody></table>
<pre><code class="language-shell">if &lt;a href=&quot;f-home.html&quot; class=&quot;internal-link&quot;&gt; -f &#39;/home&#39; &lt;/a&gt;;then echo &#39;directory&#39;;else echo &#39;file&#39;;fi
# file
if &lt;a href=&quot;d-home.html&quot; class=&quot;internal-link&quot;&gt; -d &#39;/home&#39; &lt;/a&gt;;then echo &#39;directory&#39;;else echo &#39;file&#39;;fi
# directory
if &lt;a href=&quot;e-tmpfake-file.html&quot; class=&quot;internal-link&quot;&gt; -e &#39;/tmp/fake_file&#39; &lt;/a&gt;;then echo &#39;exist&#39;;else echo &#39;not exist&#39;;fi
# not exist
</code></pre>
<h1>5. 数组</h1>
<p><code>shell</code>只支持一维数组,用括号表示,元素通过空格分隔,形如<code>数组名=(值1 值2 ... 值n)</code>。<code>shell</code>数组下标从<code>1</code>开始。</p>
<ul>
<li><code>${数组名[下标]}</code>,读取指索引位置数组元素</li>
<li>使用<code>@</code>或<code>*</code>代替下标,获取数组中所有元素。</li>
<li>使用<code>{&lt;span class=&quot;tag&quot;&gt;#数组名&lt;/span&gt;[@]}</code>或<code>{&lt;span class=&quot;tag&quot;&gt;#数组名&lt;/span&gt;[*]}</code>获取数组元素个数。</li>
</ul>
<pre><code class="language-shell">arr=(value1 value2 value3 value4)
echo ${arr[3]}
# value3
echo ${arr[*]}
# value1 value2 value3 value4
echo ${arr[@]}
# value1 value2 value3 value4
arr[3]=&#39;new_value3&#39;
echo $arr[3]
# new_value3
echo ${&lt;span class=&quot;tag&quot;&gt;#arr&lt;/span&gt;[@]}
# 4
echo &quot;arr[1]的长度为:${&lt;span class=&quot;tag&quot;&gt;#arr&lt;/span&gt;[1]}&quot;
# arr[1]的长度为:6
</code></pre>
<h1>6. 运算符</h1>
<h2>6.1. 赋值运算符</h2>
<pre><code class="language-shell">a=10
b=$a
</code></pre>
<h2>6.2. 算术运算符</h2>
<p>算数运算符支持<code>+,-,*,/,%</code></p>
<h3>6.2.1. expr表示法</h3>
<pre><code class="language-shell">echo `expr 10 + 20`
# 30
echo $(expr 20 / 2)
# 10
echo $(expr 10 \* 20) # 使用expr进行乘法运算时必须使用\进行转义
# 200
</code></pre>
<blockquote>
<p>使用expr表示方法时,表达式和运算符之间必须有空格。</p>
</blockquote>
<h3>6.2.2. <code>$[]</code></h3>
<pre><code class="language-shell">echo $[10%3]
# 1
</code></pre>
<h3>6.2.3. <code>$(())</code></h3>
<pre><code class="language-shell">echo $((10*20))
# 200
</code></pre>
<h2>6.3. 关系运算符</h2>
<p>最常见的关系运算符是:<code>==,!=,&lt;,&gt;,&gt;=,&lt;=</code></p>
<pre><code class="language-shell">echo $[10==10]
# 1
flag=$[20==10]
echo $flag
# 1
echo $[10&gt;=10]
# 1
</code></pre>
<p>如下关系运算符只能使用在条件表达式<code>if、while</code>下,类似<code>flag=[ $a -eq $b ]</code>的直接赋值语句是非法的。关系运算符的条件表达式要放在<strong>一对</strong>方括号中,并且中间需要有空格。也可以使用<code>(())</code>替代<code>[]</code>,此时<code>-eq,-lt,-le</code>之类的需要使用<code>==,&lt;,&lt;=</code>等替换。</p>
<blockquote>
<p><code>[]</code>搭配<code>-eq -ne</code>等使用,<code>(())</code>搭配<code>|| &amp;&amp;</code>等使用。</p>
</blockquote>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>-eq</code></td>
<td>检测两个数是否相等,相等返回true。</td>
<td><code>[ $a -eq $b ]</code></td>
</tr>
<tr>
<td><code>-ne</code></td>
<td>检测两个数是否不相等,不相等返回 true。</td>
<td><code>[ $a -ne $b ]</code></td>
</tr>
<tr>
<td><code>-gt</code></td>
<td>检测左边的数是否大于右边的,如果是,则返回 true。</td>
<td><code>[ $a -gt $b ]</code></td>
</tr>
<tr>
<td><code>-lt</code></td>
<td>检测左边的数是否小于右边的,如果是,则返回 true。</td>
<td><code>[ $a -lt $b ]</code></td>
</tr>
<tr>
<td><code>-ge</code></td>
<td>检测左边的数是否大于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -ge $b ]</code></td>
</tr>
<tr>
<td><code>-le</code></td>
<td>检测左边的数是否小于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -le $b ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ 1 -eq 1 ];then echo &#39;hello&#39;;fi;
# hello
if ((10&gt;=10));then echo &#39;hello&#39;;fi;
# hello
</code></pre>
<h2>6.4. 布尔、逻辑运算符</h2>
<p>布尔、逻辑运算的条件表达式也要放在一对方括号中<code>[]</code>。</p>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>!</code></td>
<td>非运算,表达式为true则返回false,否则返回true。</td>
<td><code>[ ! 10 -eq 0 ]</code></td>
</tr>
<tr>
<td><code>-o</code></td>
<td>或运算,有一个表达式为true则返回true。</td>
<td><code>[ 10 -lt 20 -o 10 -gt 100 ]</code></td>
</tr>
<tr>
<td><code>-a</code></td>
<td>与运算,两个表达式都为true才返回true。</td>
<td><code>[ 10 -lt 20 -a 10 -gt 100 ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ ! 10 -eq 0 ];then echo &#39;hello&#39;;fi
# hello
if [ 10 -ge 10 -a 10 -ge 10 ];then echo &#39;hello&#39;;fi
# hello
if [ 10 -ge 20 -o 10 -ge 0 ];then echo &#39;hello&#39;;fi
# hello
</code></pre>
<p> <code>-o</code>也可以使用<code>||</code>替代,<code>-a</code>也可以使用<code>&amp;&amp;</code>替代,此时需要使用<code>(())</code>或<code>[[]]</code>替代<code>[]</code>。</p>
<pre><code class="language-shell">if &lt;a href=&quot;1010-55.html&quot; class=&quot;internal-link&quot;&gt; 10==10 &amp;&amp; 5==5 &lt;/a&gt;;then echo &#39;hello&#39;;fi
# hello
if ((10==10 &amp;&amp; 5==5));then echo &#39;hello&#39;;fi
# hello
</code></pre>
<h1>7. 传递参数</h1>
<p>在执行 <code>Shell</code>脚本时,向脚本传递参数,脚本内获取参数的格式为:<code>$n</code>。<code>n</code>代表一个数字,<code>1</code>为执行脚本的第一个参数,<code>2</code>为执行脚本的第二个参数,<code>$0</code>为执行的文件名。在为<code>shell</code>脚本传递的参数中如果包含空格,应该使用单引号或者双引号将该参数括起来,以便于脚本将这个参数作为整体来接收。另外,还有几个特殊字符用来处理参数:</p>
<table>
<thead>
<tr>
<th>参数处理</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>$#</code></td>
<td>传递到脚本的参数个数</td>
</tr>
<tr>
<td><code>$*</code></td>
<td>以一个单字符串显示所有向脚本传递的参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$$</code></td>
<td>脚本运行的当前进程ID号</td>
</tr>
<tr>
<td><code>$!</code></td>
<td>后台运行的最后一个进程的ID号</td>
</tr>
<tr>
<td><code>$@</code></td>
<td>与<code>$*</code>相同,但是使用时加引号,并在引号中返回每个参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$-</code></td>
<td>显示Shell使用的当前选项,与set功能相同。</td>
</tr>
<tr>
<td><code>$?</code></td>
<td>显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。</td>
</tr>
</tbody></table>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-bash">set -e
echo &quot;执行的文件名:$0&quot;
echo &quot;参数个数为$#&quot;
echo &quot;第一个参数为:$1&quot;
echo &quot;第二个参数为:$2&quot;
echo &quot;所有参数为:$@&quot;
echo &quot;进程ID号为:$$&quot;
echo &quot;当前shell选项为$-&quot;
echo &quot;上一个命令退出的状态为$?&quot;
</code></pre>
<p>执行结果如下:</p>
<pre><code class="language-shell">$ sh test.sh param1 &quot;param2 with space&quot;
执行的文件名:test.sh
参数个数为2
第一个参数为:param1
第二个参数为:param2 with space
所有参数为:param1 param2 with space
进程ID号为:3700
当前shell选项为ehB
上一个命令退出的状态为0
</code></pre>
<h1>8. 函数</h1>
<p>函数定义通过<code>function_name(){}</code>的形式定义,函数返回值可以显示用return返回,如果不加,将以最后一条命令的运行结果作为返回值,函数返回值只能是数字。函数也可以传递参数,但是函数定义的()中不需要申明。</p>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-shell">sayhello(){
echo &quot;hello&quot;
}
# 注意函数调用只需要函数名,不需要加()
sayhello
sayhellowithparam(){
echo &quot;hello, $1 $2 $3&quot;
return 1
}
sayhellowithparam zhangsan lisi wangwu
echo $?
</code></pre>
<p>输出如下:</p>
<blockquote>
<p>hello<br>hello, zhangsan lisi wangwu<br>1</p>
</blockquote>
<h1>9. 命令替换</h1>
<p>命令替换可以将一个命令的输出作为另外一个命令的参数。</p>
<pre><code class="language-shell"># command1 `command2`
cd `pwd` # 该命令将pwd命令列出的目录作为cd命令的参数,结果仍然是停留在当前目录下
cd `echo $HOME` # 将echo的输出作为cd的参数,即打开用户根目录
</code></pre>
<h1>10. let命令</h1>
<p>let 命令是 BASH 中用于计算的工具,用于执行一个或多个表达式,变量计算中不需要加上 $ 来表示变量。如果表达式中包含了空格或其他特殊字符,则必须引起来。</p>
<ul>
<li>自加操作:<code>let no++</code></li>
<li>自减操作:<code>let no--</code></li>
<li>简写形式 <code>let no+=10</code>,<code>let no-=20</code>,分别等同于<code>let no=no+10</code>,<code>let no=no-20</code></li>
</ul>
<h1>11. 流程控制</h1>
<h2>11.1. if</h2>
<pre><code class="language-shell">if ((10&lt;2));then
echo &quot;10小于2&quot;
elif ((10&gt;20));then
echo &quot;a大于10&quot;
else
echo &quot;10大于2且小于10&quot;
fi
</code></pre>
<h2>11.2. case</h2>
<p><code>case</code>每一种情况以右括号结尾,执行到<code>;;</code>结束</p>
<pre><code class="language-shell">case 10 in
0|1)
echo &quot;a为0或1&quot;
;;
11|12)
echo &quot;a为11或12&quot;
;;
*)
# *用来匹配所有情况
echo &quot;a为10&quot;
;;
esac
</code></pre>
<h2>11.3. while</h2>
<pre><code class="language-shell">count=0
while(($count&lt;5))
do
echo $count
let count++
done
</code></pre>
<h2>11.4. util</h2>
<pre><code class="language-shell">count=0
until(($count&gt;=5))
do
echo $count
let count++
done
</code></pre>
<h2>11.5. for</h2>
<pre><code class="language-shell"># for写法1
for ((count=0;$count&lt;5;count=$count+1))
do
echo $count
done
# for写法2
arr=(0 1 2 3 4)
for count in ${arr[*]}
do
echo $int
done
# for写法3
for int in 0 1 2 3 4
do
echo $int
done
</code></pre>
<h2>11.6. break和continue</h2>
<p>用法与一般编程语言类似,break跳出循环,continue跳出当前循环</p>
<pre><code class="language-shell">for ((count=0;$count&gt;=0;count=$count+1))
do
if (($count&gt;=5));then
break;
fi
echo $count
done
</code></pre>
<h1>12. 输入输出重定向</h1>
<h2>12.1. 输出重定向</h2>
<p><code>command &gt; file</code>将命令输出结果保存的file文件中。<code>&gt;</code>从文件头开始写,会覆盖旧内容,<code>&gt;&gt;</code>将内容追加到文件末尾</p>
<pre><code class="language-shell"># 将who命令的输出保存的users文件中,可以通过cat users查看
who &gt; users
# 将字符串hello world保存到text.txt文件中
echo &quot;hello world&quot; &gt; text.txt
</code></pre>
<h2>12.2. 输入重定向</h2>
<p><code>command &lt; file</code>从file文件获取输入</p>
<pre><code class="language-shell">wc -l /etc/passwd
# 123 /etc/passwd
wc -l &lt; users
# 123
# 第一个例子,会输出文件名;第二个不会,因为它仅仅知道从标准输入读取内容
# command &lt; infile &gt; outfile, 同时替换输入和输出,执行command,从文件infile读取内容,然后将输出写入到outfile中。
wc -l &lt; /etc/passwd &gt; result
cat result
# 123
</code></pre>
<h2>12.3. 文件描述符</h2>
<p>一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件</p>
<ul>
<li>标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。</li>
<li>标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。</li>
<li>标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。</li>
</ul>
<pre><code class="language-shell"># 将标准错误输出重定向到error_trace
cat /tmp/fake_file 2&gt;error_trace
cat error_trace
# cat: /tmp/fake_fule: No such file or directory
# 将标准输出和标准错误输出都重定向到result
cat /tmp/fake_file &amp;&gt;result
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准错误重定向到标准输出
ls /tmp/fake_file &gt; result 2&gt;&amp;1
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准输入重定向到result,将标准错误输出重定向到error_trace
cat /tmp/fake_file 1&gt;result 2&gt;error_trace
</code></pre>
<h2>12.4. Here Document</h2>
<p>将两个<code>EOF</code>之间的内容(document) 作为输入传递给<code>command</code></p>
<pre><code class="language-bash"># command &lt;&lt; EOF
# document
# EOF
cat &lt;&lt; EOF
hello
shinerio
learn shell
EOF
</code></pre>
<blockquote>
<p>结尾的<code>EOF</code>一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和<code>tab</code>缩进。开始的<code>EOF</code>前后的空格会被忽略掉。</p>
</blockquote>
<h2>12.5. /dev/null</h2>
<p>如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null。<code>command &gt; /dev/null</code></p>
<pre><code class="language-shell">cat users &gt; /dev/null
cat users &gt; /dev/null 2&gt;&amp;1
</code></pre>
<h1>13. set命令</h1>
<p>set指令能设置所使用shell的执行方式,可依照不同的需求来做设置。以下只列出常用的选项参数:</p>
<ul>
<li>-e 若指令传回值不等于0,则立即退出shell。</li>
<li>-f 取消使用通配符。</li>
<li>-n 只读取指令,而不实际执行。</li>
<li>-x 执行指令后,会先显示该指令及所下的参数。</li>
</ul>
#39;hello' ];then echo 'hello';fi
str='hello'
if [ $str ];then echo 'hello';fi
# hello
</code></pre>
<p>注意字符串的等值判断是一个等号<code>"="</code>,与下文要讲的逻辑运算符使用两个等号<code>"=="</code>做等值判断不一样。</p>
<h1>4. 文件测试运算符</h1>
<table>
<thead>
<tr>
<th>操作符</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>-b file</code></td>
<td>检测文件是否是块设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-c file</code></td>
<td>检测文件是否是字符设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-d file</code></td>
<td>检测文件是否是目录,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-f file</code></td>
<td>检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-g file</code></td>
<td>检测文件是否设置了<code>SGID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-k file</code></td>
<td>检测文件是否设置了粘着位(Sticky Bit),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-p file</code></td>
<td>检测文件是否是有名管道,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-u file</code></td>
<td>检测文件是否设置了<code>SUID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-r file</code></td>
<td>检测文件是否可读,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-w file</code></td>
<td>检测文件是否可写,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-x file</code></td>
<td>检测文件是否可执行,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-s file</code></td>
<td>检测文件是否为空(文件大小是否大于0),不为空返回true。</td>
</tr>
<tr>
<td><code>-e file</code></td>
<td>检测文件(包括目录)是否存在,如果是,则返回true。</td>
</tr>
</tbody></table>
<pre><code class="language-shell">if <a href="f-home.html" class="internal-link"> -f '/home' </a>;then echo 'directory';else echo 'file';fi
# file
if <a href="d-home.html" class="internal-link"> -d '/home' </a>;then echo 'directory';else echo 'file';fi
# directory
if <a href="e-tmpfake-file.html" class="internal-link"> -e '/tmp/fake_file' </a>;then echo 'exist';else echo 'not exist';fi
# not exist
</code></pre>
<h1>5. 数组</h1>
<p><code>shell</code>只支持一维数组,用括号表示,元素通过空格分隔,形如<code>数组名=(值1 值2 ... 值n)</code>。<code>shell</code>数组下标从<code>1</code>开始。</p>
<ul>
<li><code>${数组名[下标]}</code>,读取指索引位置数组元素</li>
<li>使用<code>@</code>或<code>*</code>代替下标,获取数组中所有元素。</li>
<li>使用<code>{<span class="tag">#数组名</span>[@]}</code>或<code>{<span class="tag">#数组名</span>[*]}</code>获取数组元素个数。</li>
</ul>
<pre><code class="language-shell">arr=(value1 value2 value3 value4)
echo ${arr[3]}
# value3
echo ${arr[*]}
# value1 value2 value3 value4
echo ${arr[@]}
# value1 value2 value3 value4
arr[3]='new_value3'
echo $arr[3]
# new_value3
echo ${<span class="tag">#arr</span>[@]}
# 4
echo "arr[1]的长度为:${<span class="tag">#arr</span>[1]}"
# arr[1]的长度为:6
</code></pre>
<h1>6. 运算符</h1>
<h2>6.1. 赋值运算符</h2>
<pre><code class="language-shell">a=10
b=$a
</code></pre>
<h2>6.2. 算术运算符</h2>
<p>算数运算符支持<code>+,-,*,/,%</code></p>
<h3>6.2.1. expr表示法</h3>
<pre><code class="language-shell">echo `expr 10 + 20`
# 30
echo $(expr 20 / 2)
# 10
echo $(expr 10 \* 20) # 使用expr进行乘法运算时必须使用\进行转义
# 200
</code></pre>
<blockquote>
<p>使用expr表示方法时,表达式和运算符之间必须有空格。</p>
</blockquote>
<h3>6.2.2. <code>$[]</code></h3>
<pre><code class="language-shell">echo $[10%3]
# 1
</code></pre>
<h3>6.2.3. <code>$(())</code></h3>
<pre><code class="language-shell">echo $((10*20))
# 200
</code></pre>
<h2>6.3. 关系运算符</h2>
<p>最常见的关系运算符是:<code>==,!=,<,>,>=,<=</code></p>
<pre><code class="language-shell">echo $[10==10]
# 1
flag=$[20==10]
echo $flag
# 1
echo $[10>=10]
# 1
</code></pre>
<p>如下关系运算符只能使用在条件表达式<code>if、while</code>下,类似<code>flag=[ $a -eq $b ]</code>的直接赋值语句是非法的。关系运算符的条件表达式要放在<strong>一对</strong>方括号中,并且中间需要有空格。也可以使用<code>(())</code>替代<code>[]</code>,此时<code>-eq,-lt,-le</code>之类的需要使用<code>==,<,<=</code>等替换。</p>
<blockquote>
<p><code>[]</code>搭配<code>-eq -ne</code>等使用,<code>(())</code>搭配<code>|| &&</code>等使用。</p>
</blockquote>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>-eq</code></td>
<td>检测两个数是否相等,相等返回true。</td>
<td><code>[ $a -eq $b ]</code></td>
</tr>
<tr>
<td><code>-ne</code></td>
<td>检测两个数是否不相等,不相等返回 true。</td>
<td><code>[ $a -ne $b ]</code></td>
</tr>
<tr>
<td><code>-gt</code></td>
<td>检测左边的数是否大于右边的,如果是,则返回 true。</td>
<td><code>[ $a -gt $b ]</code></td>
</tr>
<tr>
<td><code>-lt</code></td>
<td>检测左边的数是否小于右边的,如果是,则返回 true。</td>
<td><code>[ $a -lt $b ]</code></td>
</tr>
<tr>
<td><code>-ge</code></td>
<td>检测左边的数是否大于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -ge $b ]</code></td>
</tr>
<tr>
<td><code>-le</code></td>
<td>检测左边的数是否小于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -le $b ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ 1 -eq 1 ];then echo 'hello';fi;
# hello
if ((10>=10));then echo 'hello';fi;
# hello
</code></pre>
<h2>6.4. 布尔、逻辑运算符</h2>
<p>布尔、逻辑运算的条件表达式也要放在一对方括号中<code>[]</code>。</p>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>!</code></td>
<td>非运算,表达式为true则返回false,否则返回true。</td>
<td><code>[ ! 10 -eq 0 ]</code></td>
</tr>
<tr>
<td><code>-o</code></td>
<td>或运算,有一个表达式为true则返回true。</td>
<td><code>[ 10 -lt 20 -o 10 -gt 100 ]</code></td>
</tr>
<tr>
<td><code>-a</code></td>
<td>与运算,两个表达式都为true才返回true。</td>
<td><code>[ 10 -lt 20 -a 10 -gt 100 ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ ! 10 -eq 0 ];then echo 'hello';fi
# hello
if [ 10 -ge 10 -a 10 -ge 10 ];then echo 'hello';fi
# hello
if [ 10 -ge 20 -o 10 -ge 0 ];then echo 'hello';fi
# hello
</code></pre>
<p> <code>-o</code>也可以使用<code>||</code>替代,<code>-a</code>也可以使用<code>&&</code>替代,此时需要使用<code>(())</code>或<code>[[]]</code>替代<code>[]</code>。</p>
<pre><code class="language-shell">if <a href="1010-55.html" class="internal-link"> 10==10 && 5==5 </a>;then echo 'hello';fi
# hello
if ((10==10 && 5==5));then echo 'hello';fi
# hello
</code></pre>
<h1>7. 传递参数</h1>
<p>在执行 <code>Shell</code>脚本时,向脚本传递参数,脚本内获取参数的格式为:<code>$n</code>。<code>n</code>代表一个数字,<code>1</code>为执行脚本的第一个参数,<code>2</code>为执行脚本的第二个参数,<code>$0</code>为执行的文件名。在为<code>shell</code>脚本传递的参数中如果包含空格,应该使用单引号或者双引号将该参数括起来,以便于脚本将这个参数作为整体来接收。另外,还有几个特殊字符用来处理参数:</p>
<table>
<thead>
<tr>
<th>参数处理</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>$#</code></td>
<td>传递到脚本的参数个数</td>
</tr>
<tr>
<td><code>$*</code></td>
<td>以一个单字符串显示所有向脚本传递的参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$</code></td>
<td>脚本运行的当前进程ID号</td>
</tr>
<tr>
<td><code>$!</code></td>
<td>后台运行的最后一个进程的ID号</td>
</tr>
<tr>
<td><code>$@</code></td>
<td>与<code>$*</code>相同,但是使用时加引号,并在引号中返回每个参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$-</code></td>
<td>显示Shell使用的当前选项,与set功能相同。</td>
</tr>
<tr>
<td><code>$?</code></td>
<td>显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。</td>
</tr>
</tbody></table>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-bash">set -e
echo "执行的文件名:$0"
echo "参数个数为$#"
echo "第一个参数为:$1"
echo "第二个参数为:$2"
echo "所有参数为:$@"
echo "进程ID号为:$"
echo "当前shell选项为$-"
echo "上一个命令退出的状态为$?"
</code></pre>
<p>执行结果如下:</p>
<pre><code class="language-shell">$ sh test.sh param1 "param2 with space"
执行的文件名:test.sh
参数个数为2
第一个参数为:param1
第二个参数为:param2 with space
所有参数为:param1 param2 with space
进程ID号为:3700
当前shell选项为ehB
上一个命令退出的状态为0
</code></pre>
<h1>8. 函数</h1>
<p>函数定义通过<code>function_name(){}</code>的形式定义,函数返回值可以显示用return返回,如果不加,将以最后一条命令的运行结果作为返回值,函数返回值只能是数字。函数也可以传递参数,但是函数定义的()中不需要申明。</p>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-shell">sayhello(){
echo "hello"
}
# 注意函数调用只需要函数名,不需要加()
sayhello
sayhellowithparam(){
echo "hello, $1 $2 $3"
return 1
}
sayhellowithparam zhangsan lisi wangwu
echo $?
</code></pre>
<p>输出如下:</p>
<blockquote>
<p>hello<br>hello, zhangsan lisi wangwu<br>1</p>
</blockquote>
<h1>9. 命令替换</h1>
<p>命令替换可以将一个命令的输出作为另外一个命令的参数。</p>
<pre><code class="language-shell"># command1 `command2`
cd `pwd` # 该命令将pwd命令列出的目录作为cd命令的参数,结果仍然是停留在当前目录下
cd `echo $HOME` # 将echo的输出作为cd的参数,即打开用户根目录
</code></pre>
<h1>10. let命令</h1>
<p>let 命令是 BASH 中用于计算的工具,用于执行一个或多个表达式,变量计算中不需要加上 $ 来表示变量。如果表达式中包含了空格或其他特殊字符,则必须引起来。</p>
<ul>
<li>自加操作:<code>let no++</code></li>
<li>自减操作:<code>let no--</code></li>
<li>简写形式 <code>let no+=10</code>,<code>let no-=20</code>,分别等同于<code>let no=no+10</code>,<code>let no=no-20</code></li>
</ul>
<h1>11. 流程控制</h1>
<h2>11.1. if</h2>
<pre><code class="language-shell">if ((10<2));then
echo "10小于2"
elif ((10>20));then
echo "a大于10"
else
echo "10大于2且小于10"
fi
</code></pre>
<h2>11.2. case</h2>
<p><code>case</code>每一种情况以右括号结尾,执行到<code>;;</code>结束</p>
<pre><code class="language-shell">case 10 in
0|1)
echo "a为0或1"
;;
11|12)
echo "a为11或12"
;;
*)
# *用来匹配所有情况
echo "a为10"
;;
esac
</code></pre>
<h2>11.3. while</h2>
<pre><code class="language-shell">count=0
while(($count<5))
do
echo $count
let count++
done
</code></pre>
<h2>11.4. util</h2>
<pre><code class="language-shell">count=0
until(($count>=5))
do
echo $count
let count++
done
</code></pre>
<h2>11.5. for</h2>
<pre><code class="language-shell"># for写法1
for ((count=0;$count<5;count=$count+1))
do
echo $count
done
# for写法2
arr=(0 1 2 3 4)
for count in ${arr[*]}
do
echo $int
done
# for写法3
for int in 0 1 2 3 4
do
echo $int
done
</code></pre>
<h2>11.6. break和continue</h2>
<p>用法与一般编程语言类似,break跳出循环,continue跳出当前循环</p>
<pre><code class="language-shell">for ((count=0;$count>=0;count=$count+1))
do
if (($count>=5));then
break;
fi
echo $count
done
</code></pre>
<h1>12. 输入输出重定向</h1>
<h2>12.1. 输出重定向</h2>
<p><code>command > file</code>将命令输出结果保存的file文件中。<code>></code>从文件头开始写,会覆盖旧内容,<code>>></code>将内容追加到文件末尾</p>
<pre><code class="language-shell"># 将who命令的输出保存的users文件中,可以通过cat users查看
who > users
# 将字符串hello world保存到text.txt文件中
echo "hello world" > text.txt
</code></pre>
<h2>12.2. 输入重定向</h2>
<p><code>command < file</code>从file文件获取输入</p>
<pre><code class="language-shell">wc -l /etc/passwd
# 123 /etc/passwd
wc -l < users
# 123
# 第一个例子,会输出文件名;第二个不会,因为它仅仅知道从标准输入读取内容
# command < infile > outfile, 同时替换输入和输出,执行command,从文件infile读取内容,然后将输出写入到outfile中。
wc -l < /etc/passwd > result
cat result
# 123
</code></pre>
<h2>12.3. 文件描述符</h2>
<p>一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件</p>
<ul>
<li>标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。</li>
<li>标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。</li>
<li>标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。</li>
</ul>
<pre><code class="language-shell"># 将标准错误输出重定向到error_trace
cat /tmp/fake_file 2>error_trace
cat error_trace
# cat: /tmp/fake_fule: No such file or directory
# 将标准输出和标准错误输出都重定向到result
cat /tmp/fake_file &>result
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准错误重定向到标准输出
ls /tmp/fake_file > result 2>&1
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准输入重定向到result,将标准错误输出重定向到error_trace
cat /tmp/fake_file 1>result 2>error_trace
</code></pre>
<h2>12.4. Here Document</h2>
<p>将两个<code>EOF</code>之间的内容(document) 作为输入传递给<code>command</code></p>
<pre><code class="language-bash"># command << EOF
# document
# EOF
cat << EOF
hello
shinerio
learn shell
EOF
</code></pre>
<blockquote>
<p>结尾的<code>EOF</code>一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和<code>tab</code>缩进。开始的<code>EOF</code>前后的空格会被忽略掉。</p>
</blockquote>
<h2>12.5. /dev/null</h2>
<p>如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null。<code>command > /dev/null</code></p>
<pre><code class="language-shell">cat users > /dev/null
cat users > /dev/null 2>&1
</code></pre>
<h1>13. set命令</h1>
<p>set指令能设置所使用shell的执行方式,可依照不同的需求来做设置。以下只列出常用的选项参数:</p>
<ul>
<li>-e 若指令传回值不等于0,则立即退出shell。</li>
<li>-f 取消使用通配符。</li>
<li>-n 只读取指令,而不实际执行。</li>
<li>-x 执行指令后,会先显示该指令及所下的参数。</li>
</ul>
</section>
</article>amp;#39;hello' ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ 'hello' = 'hello' ];then echo 'hello';fi
# hello
if [ 'hello' != 'ello' ];then echo 'hello';fi
# hello
if [ -z '' ];then echo 'hello';fi
# hello
if [ -n 'hello' ];then echo 'hello';fi
# hello
if [ <article>
<header>
<h1>shell编程</h1>
<time datetime="2023-01-24T00:00:00.000Z">2023年1月24日</time>
<div class="tags">
<span class="tag">linux</span>
</div>
</header>
<section class="content">
<p>本文主要介绍shell编程的基本语法以及实际应用中的常见命令。</p>
<h1>1. 注释</h1>
<h2>1.1. 单行注释</h2>
<pre><code class="language-shell"># 这是单行注释
</code></pre>
<h2>1.2. 多行注释</h2>
<pre><code class="language-shell">:<<EOF
多行注释内容
多行注释内容
多行注释内容
EOF
</code></pre>
<p>多行注释<code>EOF</code>也可替换成<code>!</code>或<code>'</code></p>
<pre><code class="language-shell">:<<'
多行注释内容
多行注释内容
多行注释内容
'
:<<!
多行注释内容
多行注释内容
多行注释内容
!
</code></pre>
<h1>2. 变量</h1>
<h2>2.1. 变量定义</h2>
<p>使用<code>VARIABLENAME=VALUE</code>的形式,VALUE如果是字符串的话,可以使用单引号、双引号或者不加引号。单引号内的任何字符都会原样输出,不能进行转义,单引号内不能单独出现一个单引号,但可成对出现,作为字符串拼接使用。双引号内可以有变量,可以出现转义字符。</p>
<h2>2.2. 变量使用</h2>
<p>只需要在变量前加<code>$</code>符号,变量加<code>{}</code>是可选的,方便解释器识别边界。将变量加上<code>{}</code>是一个好习惯,不容易出错。</p>
<pre><code class="language-shell">your_age=25
your_name="shinerio"
your_name=shinerio
your_name='shinerio'
echo $your_age # 输出25
echo $your_name # 输出shinerio
echo "${your_name}hello" <span class="tag">#这里</span>{}必须添加,否则解释器认为是${your_namehello}
str='hello'' # 非法
str='hello'__'world' # 成对出现的单引号做字符拼接
echo $str <span class="tag">#输出hello__world</span>
str1='helloworld${your_age}\nnew line'
str2="helloworld${your_age}\nnew line"
echo $str1 # 输出helloworld${your_age}\nnew line
echo $str2 # 输出helloworld25\nnew line
echo -e $str2 # -e开启转义 \n表示换行 echo默认换行,通过\c强制不换行
<span class="tag">#helloworld25</span>
<span class="tag">#new</span> line
</code></pre>
<h2>2.3. 只读变量</h2>
<p>使用<code>readonly VARIABLENAME</code>设置变量只读,只读变量的值不能更改</p>
<pre><code class="language-shell">readonly name='jack'
name='kelly'
zsh: read-only variable: name
</code></pre>
<h2>2.4. 删除变量</h2>
<p>使用<code>unset VARIABLENAME</code>删除变量。</p>
<h1>3. 字符串操作</h1>
<h2>3.1. 字符串拼接</h2>
<pre><code class="language-shell">str1="hello"${your_name}"world"
str2="hello${your_name}world"
str3='hello'${your_name}'world'
</code></pre>
<h2>3.2. 字符串长度</h2>
<pre><code class="language-shell">str='hello'
echo ${<span class="tag">#str</span>}
5
</code></pre>
<h2>3.3. 字符串截取</h2>
<p><code>${string:start:length}</code>,索引从0开始,从start(包含)开始截取共计length长度的字符。</p>
<pre><code class="language-shell">str='helloworld'
echo ${str:0:5}
hello
</code></pre>
<h2>3.4. 字符串运算符</h2>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>=</code></td>
<td>检测两个字符串是否相等,相等返回true</td>
<td><code>[ 'hello' = 'hello' ]</code></td>
</tr>
<tr>
<td><code>!=</code></td>
<td>检测两个字符串是否相等,不相等返回true</td>
<td><code>[ 'hello' != 'ello' ]</code></td>
</tr>
<tr>
<td><code>-z</code></td>
<td>检测字符串长度是否为0,为0返回true</td>
<td><code>[ -z '' ]</code></td>
</tr>
<tr>
<td><code>-n </code></td>
<td>检测字符串长度是否不为0,不为0返回true</td>
<td><code>[ -n 'hello' ]</code></td>
</tr>
<tr>
<td><code>$</code></td>
<td>检测字符串是否为空,不为空返回true</td>
<td><code>[ <p>本文主要介绍shell编程的基本语法以及实际应用中的常见命令。</p>
<h1>1. 注释</h1>
<h2>1.1. 单行注释</h2>
<pre><code class="language-shell"># 这是单行注释
</code></pre>
<h2>1.2. 多行注释</h2>
<pre><code class="language-shell">:&lt;&lt;EOF
多行注释内容
多行注释内容
多行注释内容
EOF
</code></pre>
<p>多行注释<code>EOF</code>也可替换成<code>!</code>或<code>&#39;</code></p>
<pre><code class="language-shell">:&lt;&lt;&#39;
多行注释内容
多行注释内容
多行注释内容
&#39;
:&lt;&lt;!
多行注释内容
多行注释内容
多行注释内容
!
</code></pre>
<h1>2. 变量</h1>
<h2>2.1. 变量定义</h2>
<p>使用<code>VARIABLENAME=VALUE</code>的形式,VALUE如果是字符串的话,可以使用单引号、双引号或者不加引号。单引号内的任何字符都会原样输出,不能进行转义,单引号内不能单独出现一个单引号,但可成对出现,作为字符串拼接使用。双引号内可以有变量,可以出现转义字符。</p>
<h2>2.2. 变量使用</h2>
<p>只需要在变量前加<code>$</code>符号,变量加<code>{}</code>是可选的,方便解释器识别边界。将变量加上<code>{}</code>是一个好习惯,不容易出错。</p>
<pre><code class="language-shell">your_age=25
your_name=&quot;shinerio&quot;
your_name=shinerio
your_name=&#39;shinerio&#39;
echo $your_age # 输出25
echo $your_name # 输出shinerio
echo &quot;${your_name}hello&quot; &lt;span class=&quot;tag&quot;&gt;#这里&lt;/span&gt;{}必须添加,否则解释器认为是${your_namehello}
str=&#39;hello&#39;&#39; # 非法
str=&#39;hello&#39;__&#39;world&#39; # 成对出现的单引号做字符拼接
echo $str &lt;span class=&quot;tag&quot;&gt;#输出hello__world&lt;/span&gt;
str1=&#39;helloworld${your_age}\nnew line&#39;
str2=&quot;helloworld${your_age}\nnew line&quot;
echo $str1 # 输出helloworld${your_age}\nnew line
echo $str2 # 输出helloworld25\nnew line
echo -e $str2 # -e开启转义 \n表示换行 echo默认换行,通过\c强制不换行
&lt;span class=&quot;tag&quot;&gt;#helloworld25&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;#new&lt;/span&gt; line
</code></pre>
<h2>2.3. 只读变量</h2>
<p>使用<code>readonly VARIABLENAME</code>设置变量只读,只读变量的值不能更改</p>
<pre><code class="language-shell">readonly name=&#39;jack&#39;
name=&#39;kelly&#39;
zsh: read-only variable: name
</code></pre>
<h2>2.4. 删除变量</h2>
<p>使用<code>unset VARIABLENAME</code>删除变量。</p>
<h1>3. 字符串操作</h1>
<h2>3.1. 字符串拼接</h2>
<pre><code class="language-shell">str1=&quot;hello&quot;${your_name}&quot;world&quot;
str2=&quot;hello${your_name}world&quot;
str3=&#39;hello&#39;${your_name}&#39;world&#39;
</code></pre>
<h2>3.2. 字符串长度</h2>
<pre><code class="language-shell">str=&#39;hello&#39;
echo ${&lt;span class=&quot;tag&quot;&gt;#str&lt;/span&gt;}
5
</code></pre>
<h2>3.3. 字符串截取</h2>
<p><code>${string:start:length}</code>,索引从0开始,从start(包含)开始截取共计length长度的字符。</p>
<pre><code class="language-shell">str=&#39;helloworld&#39;
echo ${str:0:5}
hello
</code></pre>
<h2>3.4. 字符串运算符</h2>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>=</code></td>
<td>检测两个字符串是否相等,相等返回true</td>
<td><code>[ &#39;hello&#39; = &#39;hello&#39; ]</code></td>
</tr>
<tr>
<td><code>!=</code></td>
<td>检测两个字符串是否相等,不相等返回true</td>
<td><code>[ &#39;hello&#39; != &#39;ello&#39; ]</code></td>
</tr>
<tr>
<td><code>-z</code></td>
<td>检测字符串长度是否为0,为0返回true</td>
<td><code>[ -z &#39;&#39; ]</code></td>
</tr>
<tr>
<td><code>-n </code></td>
<td>检测字符串长度是否不为0,不为0返回true</td>
<td><code>[ -n &#39;hello&#39; ]</code></td>
</tr>
<tr>
<td><code>$</code></td>
<td>检测字符串是否为空,不为空返回true</td>
<td><code>[ $&#39;hello&#39; ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ &#39;hello&#39; = &#39;hello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ &#39;hello&#39; != &#39;ello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ -z &#39;&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ -n &#39;hello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ $&#39;hello&#39; ];then echo &#39;hello&#39;;fi
str=&#39;hello&#39;
if [ $str ];then echo &#39;hello&#39;;fi
# hello
</code></pre>
<p>注意字符串的等值判断是一个等号<code>&quot;=&quot;</code>,与下文要讲的逻辑运算符使用两个等号<code>&quot;==&quot;</code>做等值判断不一样。</p>
<h1>4. 文件测试运算符</h1>
<table>
<thead>
<tr>
<th>操作符</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>-b file</code></td>
<td>检测文件是否是块设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-c file</code></td>
<td>检测文件是否是字符设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-d file</code></td>
<td>检测文件是否是目录,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-f file</code></td>
<td>检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-g file</code></td>
<td>检测文件是否设置了<code>SGID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-k file</code></td>
<td>检测文件是否设置了粘着位(Sticky Bit),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-p file</code></td>
<td>检测文件是否是有名管道,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-u file</code></td>
<td>检测文件是否设置了<code>SUID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-r file</code></td>
<td>检测文件是否可读,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-w file</code></td>
<td>检测文件是否可写,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-x file</code></td>
<td>检测文件是否可执行,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-s file</code></td>
<td>检测文件是否为空(文件大小是否大于0),不为空返回true。</td>
</tr>
<tr>
<td><code>-e file</code></td>
<td>检测文件(包括目录)是否存在,如果是,则返回true。</td>
</tr>
</tbody></table>
<pre><code class="language-shell">if &lt;a href=&quot;f-home.html&quot; class=&quot;internal-link&quot;&gt; -f &#39;/home&#39; &lt;/a&gt;;then echo &#39;directory&#39;;else echo &#39;file&#39;;fi
# file
if &lt;a href=&quot;d-home.html&quot; class=&quot;internal-link&quot;&gt; -d &#39;/home&#39; &lt;/a&gt;;then echo &#39;directory&#39;;else echo &#39;file&#39;;fi
# directory
if &lt;a href=&quot;e-tmpfake-file.html&quot; class=&quot;internal-link&quot;&gt; -e &#39;/tmp/fake_file&#39; &lt;/a&gt;;then echo &#39;exist&#39;;else echo &#39;not exist&#39;;fi
# not exist
</code></pre>
<h1>5. 数组</h1>
<p><code>shell</code>只支持一维数组,用括号表示,元素通过空格分隔,形如<code>数组名=(值1 值2 ... 值n)</code>。<code>shell</code>数组下标从<code>1</code>开始。</p>
<ul>
<li><code>${数组名[下标]}</code>,读取指索引位置数组元素</li>
<li>使用<code>@</code>或<code>*</code>代替下标,获取数组中所有元素。</li>
<li>使用<code>{&lt;span class=&quot;tag&quot;&gt;#数组名&lt;/span&gt;[@]}</code>或<code>{&lt;span class=&quot;tag&quot;&gt;#数组名&lt;/span&gt;[*]}</code>获取数组元素个数。</li>
</ul>
<pre><code class="language-shell">arr=(value1 value2 value3 value4)
echo ${arr[3]}
# value3
echo ${arr[*]}
# value1 value2 value3 value4
echo ${arr[@]}
# value1 value2 value3 value4
arr[3]=&#39;new_value3&#39;
echo $arr[3]
# new_value3
echo ${&lt;span class=&quot;tag&quot;&gt;#arr&lt;/span&gt;[@]}
# 4
echo &quot;arr[1]的长度为:${&lt;span class=&quot;tag&quot;&gt;#arr&lt;/span&gt;[1]}&quot;
# arr[1]的长度为:6
</code></pre>
<h1>6. 运算符</h1>
<h2>6.1. 赋值运算符</h2>
<pre><code class="language-shell">a=10
b=$a
</code></pre>
<h2>6.2. 算术运算符</h2>
<p>算数运算符支持<code>+,-,*,/,%</code></p>
<h3>6.2.1. expr表示法</h3>
<pre><code class="language-shell">echo `expr 10 + 20`
# 30
echo $(expr 20 / 2)
# 10
echo $(expr 10 \* 20) # 使用expr进行乘法运算时必须使用\进行转义
# 200
</code></pre>
<blockquote>
<p>使用expr表示方法时,表达式和运算符之间必须有空格。</p>
</blockquote>
<h3>6.2.2. <code>$[]</code></h3>
<pre><code class="language-shell">echo $[10%3]
# 1
</code></pre>
<h3>6.2.3. <code>$(())</code></h3>
<pre><code class="language-shell">echo $((10*20))
# 200
</code></pre>
<h2>6.3. 关系运算符</h2>
<p>最常见的关系运算符是:<code>==,!=,&lt;,&gt;,&gt;=,&lt;=</code></p>
<pre><code class="language-shell">echo $[10==10]
# 1
flag=$[20==10]
echo $flag
# 1
echo $[10&gt;=10]
# 1
</code></pre>
<p>如下关系运算符只能使用在条件表达式<code>if、while</code>下,类似<code>flag=[ $a -eq $b ]</code>的直接赋值语句是非法的。关系运算符的条件表达式要放在<strong>一对</strong>方括号中,并且中间需要有空格。也可以使用<code>(())</code>替代<code>[]</code>,此时<code>-eq,-lt,-le</code>之类的需要使用<code>==,&lt;,&lt;=</code>等替换。</p>
<blockquote>
<p><code>[]</code>搭配<code>-eq -ne</code>等使用,<code>(())</code>搭配<code>|| &amp;&amp;</code>等使用。</p>
</blockquote>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>-eq</code></td>
<td>检测两个数是否相等,相等返回true。</td>
<td><code>[ $a -eq $b ]</code></td>
</tr>
<tr>
<td><code>-ne</code></td>
<td>检测两个数是否不相等,不相等返回 true。</td>
<td><code>[ $a -ne $b ]</code></td>
</tr>
<tr>
<td><code>-gt</code></td>
<td>检测左边的数是否大于右边的,如果是,则返回 true。</td>
<td><code>[ $a -gt $b ]</code></td>
</tr>
<tr>
<td><code>-lt</code></td>
<td>检测左边的数是否小于右边的,如果是,则返回 true。</td>
<td><code>[ $a -lt $b ]</code></td>
</tr>
<tr>
<td><code>-ge</code></td>
<td>检测左边的数是否大于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -ge $b ]</code></td>
</tr>
<tr>
<td><code>-le</code></td>
<td>检测左边的数是否小于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -le $b ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ 1 -eq 1 ];then echo &#39;hello&#39;;fi;
# hello
if ((10&gt;=10));then echo &#39;hello&#39;;fi;
# hello
</code></pre>
<h2>6.4. 布尔、逻辑运算符</h2>
<p>布尔、逻辑运算的条件表达式也要放在一对方括号中<code>[]</code>。</p>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>!</code></td>
<td>非运算,表达式为true则返回false,否则返回true。</td>
<td><code>[ ! 10 -eq 0 ]</code></td>
</tr>
<tr>
<td><code>-o</code></td>
<td>或运算,有一个表达式为true则返回true。</td>
<td><code>[ 10 -lt 20 -o 10 -gt 100 ]</code></td>
</tr>
<tr>
<td><code>-a</code></td>
<td>与运算,两个表达式都为true才返回true。</td>
<td><code>[ 10 -lt 20 -a 10 -gt 100 ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ ! 10 -eq 0 ];then echo &#39;hello&#39;;fi
# hello
if [ 10 -ge 10 -a 10 -ge 10 ];then echo &#39;hello&#39;;fi
# hello
if [ 10 -ge 20 -o 10 -ge 0 ];then echo &#39;hello&#39;;fi
# hello
</code></pre>
<p> <code>-o</code>也可以使用<code>||</code>替代,<code>-a</code>也可以使用<code>&amp;&amp;</code>替代,此时需要使用<code>(())</code>或<code>[[]]</code>替代<code>[]</code>。</p>
<pre><code class="language-shell">if &lt;a href=&quot;1010-55.html&quot; class=&quot;internal-link&quot;&gt; 10==10 &amp;&amp; 5==5 &lt;/a&gt;;then echo &#39;hello&#39;;fi
# hello
if ((10==10 &amp;&amp; 5==5));then echo &#39;hello&#39;;fi
# hello
</code></pre>
<h1>7. 传递参数</h1>
<p>在执行 <code>Shell</code>脚本时,向脚本传递参数,脚本内获取参数的格式为:<code>$n</code>。<code>n</code>代表一个数字,<code>1</code>为执行脚本的第一个参数,<code>2</code>为执行脚本的第二个参数,<code>$0</code>为执行的文件名。在为<code>shell</code>脚本传递的参数中如果包含空格,应该使用单引号或者双引号将该参数括起来,以便于脚本将这个参数作为整体来接收。另外,还有几个特殊字符用来处理参数:</p>
<table>
<thead>
<tr>
<th>参数处理</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>$#</code></td>
<td>传递到脚本的参数个数</td>
</tr>
<tr>
<td><code>$*</code></td>
<td>以一个单字符串显示所有向脚本传递的参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$$</code></td>
<td>脚本运行的当前进程ID号</td>
</tr>
<tr>
<td><code>$!</code></td>
<td>后台运行的最后一个进程的ID号</td>
</tr>
<tr>
<td><code>$@</code></td>
<td>与<code>$*</code>相同,但是使用时加引号,并在引号中返回每个参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$-</code></td>
<td>显示Shell使用的当前选项,与set功能相同。</td>
</tr>
<tr>
<td><code>$?</code></td>
<td>显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。</td>
</tr>
</tbody></table>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-bash">set -e
echo &quot;执行的文件名:$0&quot;
echo &quot;参数个数为$#&quot;
echo &quot;第一个参数为:$1&quot;
echo &quot;第二个参数为:$2&quot;
echo &quot;所有参数为:$@&quot;
echo &quot;进程ID号为:$$&quot;
echo &quot;当前shell选项为$-&quot;
echo &quot;上一个命令退出的状态为$?&quot;
</code></pre>
<p>执行结果如下:</p>
<pre><code class="language-shell">$ sh test.sh param1 &quot;param2 with space&quot;
执行的文件名:test.sh
参数个数为2
第一个参数为:param1
第二个参数为:param2 with space
所有参数为:param1 param2 with space
进程ID号为:3700
当前shell选项为ehB
上一个命令退出的状态为0
</code></pre>
<h1>8. 函数</h1>
<p>函数定义通过<code>function_name(){}</code>的形式定义,函数返回值可以显示用return返回,如果不加,将以最后一条命令的运行结果作为返回值,函数返回值只能是数字。函数也可以传递参数,但是函数定义的()中不需要申明。</p>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-shell">sayhello(){
echo &quot;hello&quot;
}
# 注意函数调用只需要函数名,不需要加()
sayhello
sayhellowithparam(){
echo &quot;hello, $1 $2 $3&quot;
return 1
}
sayhellowithparam zhangsan lisi wangwu
echo $?
</code></pre>
<p>输出如下:</p>
<blockquote>
<p>hello<br>hello, zhangsan lisi wangwu<br>1</p>
</blockquote>
<h1>9. 命令替换</h1>
<p>命令替换可以将一个命令的输出作为另外一个命令的参数。</p>
<pre><code class="language-shell"># command1 `command2`
cd `pwd` # 该命令将pwd命令列出的目录作为cd命令的参数,结果仍然是停留在当前目录下
cd `echo $HOME` # 将echo的输出作为cd的参数,即打开用户根目录
</code></pre>
<h1>10. let命令</h1>
<p>let 命令是 BASH 中用于计算的工具,用于执行一个或多个表达式,变量计算中不需要加上 $ 来表示变量。如果表达式中包含了空格或其他特殊字符,则必须引起来。</p>
<ul>
<li>自加操作:<code>let no++</code></li>
<li>自减操作:<code>let no--</code></li>
<li>简写形式 <code>let no+=10</code>,<code>let no-=20</code>,分别等同于<code>let no=no+10</code>,<code>let no=no-20</code></li>
</ul>
<h1>11. 流程控制</h1>
<h2>11.1. if</h2>
<pre><code class="language-shell">if ((10&lt;2));then
echo &quot;10小于2&quot;
elif ((10&gt;20));then
echo &quot;a大于10&quot;
else
echo &quot;10大于2且小于10&quot;
fi
</code></pre>
<h2>11.2. case</h2>
<p><code>case</code>每一种情况以右括号结尾,执行到<code>;;</code>结束</p>
<pre><code class="language-shell">case 10 in
0|1)
echo &quot;a为0或1&quot;
;;
11|12)
echo &quot;a为11或12&quot;
;;
*)
# *用来匹配所有情况
echo &quot;a为10&quot;
;;
esac
</code></pre>
<h2>11.3. while</h2>
<pre><code class="language-shell">count=0
while(($count&lt;5))
do
echo $count
let count++
done
</code></pre>
<h2>11.4. util</h2>
<pre><code class="language-shell">count=0
until(($count&gt;=5))
do
echo $count
let count++
done
</code></pre>
<h2>11.5. for</h2>
<pre><code class="language-shell"># for写法1
for ((count=0;$count&lt;5;count=$count+1))
do
echo $count
done
# for写法2
arr=(0 1 2 3 4)
for count in ${arr[*]}
do
echo $int
done
# for写法3
for int in 0 1 2 3 4
do
echo $int
done
</code></pre>
<h2>11.6. break和continue</h2>
<p>用法与一般编程语言类似,break跳出循环,continue跳出当前循环</p>
<pre><code class="language-shell">for ((count=0;$count&gt;=0;count=$count+1))
do
if (($count&gt;=5));then
break;
fi
echo $count
done
</code></pre>
<h1>12. 输入输出重定向</h1>
<h2>12.1. 输出重定向</h2>
<p><code>command &gt; file</code>将命令输出结果保存的file文件中。<code>&gt;</code>从文件头开始写,会覆盖旧内容,<code>&gt;&gt;</code>将内容追加到文件末尾</p>
<pre><code class="language-shell"># 将who命令的输出保存的users文件中,可以通过cat users查看
who &gt; users
# 将字符串hello world保存到text.txt文件中
echo &quot;hello world&quot; &gt; text.txt
</code></pre>
<h2>12.2. 输入重定向</h2>
<p><code>command &lt; file</code>从file文件获取输入</p>
<pre><code class="language-shell">wc -l /etc/passwd
# 123 /etc/passwd
wc -l &lt; users
# 123
# 第一个例子,会输出文件名;第二个不会,因为它仅仅知道从标准输入读取内容
# command &lt; infile &gt; outfile, 同时替换输入和输出,执行command,从文件infile读取内容,然后将输出写入到outfile中。
wc -l &lt; /etc/passwd &gt; result
cat result
# 123
</code></pre>
<h2>12.3. 文件描述符</h2>
<p>一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件</p>
<ul>
<li>标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。</li>
<li>标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。</li>
<li>标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。</li>
</ul>
<pre><code class="language-shell"># 将标准错误输出重定向到error_trace
cat /tmp/fake_file 2&gt;error_trace
cat error_trace
# cat: /tmp/fake_fule: No such file or directory
# 将标准输出和标准错误输出都重定向到result
cat /tmp/fake_file &amp;&gt;result
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准错误重定向到标准输出
ls /tmp/fake_file &gt; result 2&gt;&amp;1
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准输入重定向到result,将标准错误输出重定向到error_trace
cat /tmp/fake_file 1&gt;result 2&gt;error_trace
</code></pre>
<h2>12.4. Here Document</h2>
<p>将两个<code>EOF</code>之间的内容(document) 作为输入传递给<code>command</code></p>
<pre><code class="language-bash"># command &lt;&lt; EOF
# document
# EOF
cat &lt;&lt; EOF
hello
shinerio
learn shell
EOF
</code></pre>
<blockquote>
<p>结尾的<code>EOF</code>一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和<code>tab</code>缩进。开始的<code>EOF</code>前后的空格会被忽略掉。</p>
</blockquote>
<h2>12.5. /dev/null</h2>
<p>如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null。<code>command &gt; /dev/null</code></p>
<pre><code class="language-shell">cat users &gt; /dev/null
cat users &gt; /dev/null 2&gt;&amp;1
</code></pre>
<h1>13. set命令</h1>
<p>set指令能设置所使用shell的执行方式,可依照不同的需求来做设置。以下只列出常用的选项参数:</p>
<ul>
<li>-e 若指令传回值不等于0,则立即退出shell。</li>
<li>-f 取消使用通配符。</li>
<li>-n 只读取指令,而不实际执行。</li>
<li>-x 执行指令后,会先显示该指令及所下的参数。</li>
</ul>
#39;hello' ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ 'hello' = 'hello' ];then echo 'hello';fi
# hello
if [ 'hello' != 'ello' ];then echo 'hello';fi
# hello
if [ -z '' ];then echo 'hello';fi
# hello
if [ -n 'hello' ];then echo 'hello';fi
# hello
if [ <p>本文主要介绍shell编程的基本语法以及实际应用中的常见命令。</p>
<h1>1. 注释</h1>
<h2>1.1. 单行注释</h2>
<pre><code class="language-shell"># 这是单行注释
</code></pre>
<h2>1.2. 多行注释</h2>
<pre><code class="language-shell">:&lt;&lt;EOF
多行注释内容
多行注释内容
多行注释内容
EOF
</code></pre>
<p>多行注释<code>EOF</code>也可替换成<code>!</code>或<code>&#39;</code></p>
<pre><code class="language-shell">:&lt;&lt;&#39;
多行注释内容
多行注释内容
多行注释内容
&#39;
:&lt;&lt;!
多行注释内容
多行注释内容
多行注释内容
!
</code></pre>
<h1>2. 变量</h1>
<h2>2.1. 变量定义</h2>
<p>使用<code>VARIABLENAME=VALUE</code>的形式,VALUE如果是字符串的话,可以使用单引号、双引号或者不加引号。单引号内的任何字符都会原样输出,不能进行转义,单引号内不能单独出现一个单引号,但可成对出现,作为字符串拼接使用。双引号内可以有变量,可以出现转义字符。</p>
<h2>2.2. 变量使用</h2>
<p>只需要在变量前加<code>$</code>符号,变量加<code>{}</code>是可选的,方便解释器识别边界。将变量加上<code>{}</code>是一个好习惯,不容易出错。</p>
<pre><code class="language-shell">your_age=25
your_name=&quot;shinerio&quot;
your_name=shinerio
your_name=&#39;shinerio&#39;
echo $your_age # 输出25
echo $your_name # 输出shinerio
echo &quot;${your_name}hello&quot; &lt;span class=&quot;tag&quot;&gt;#这里&lt;/span&gt;{}必须添加,否则解释器认为是${your_namehello}
str=&#39;hello&#39;&#39; # 非法
str=&#39;hello&#39;__&#39;world&#39; # 成对出现的单引号做字符拼接
echo $str &lt;span class=&quot;tag&quot;&gt;#输出hello__world&lt;/span&gt;
str1=&#39;helloworld${your_age}\nnew line&#39;
str2=&quot;helloworld${your_age}\nnew line&quot;
echo $str1 # 输出helloworld${your_age}\nnew line
echo $str2 # 输出helloworld25\nnew line
echo -e $str2 # -e开启转义 \n表示换行 echo默认换行,通过\c强制不换行
&lt;span class=&quot;tag&quot;&gt;#helloworld25&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;#new&lt;/span&gt; line
</code></pre>
<h2>2.3. 只读变量</h2>
<p>使用<code>readonly VARIABLENAME</code>设置变量只读,只读变量的值不能更改</p>
<pre><code class="language-shell">readonly name=&#39;jack&#39;
name=&#39;kelly&#39;
zsh: read-only variable: name
</code></pre>
<h2>2.4. 删除变量</h2>
<p>使用<code>unset VARIABLENAME</code>删除变量。</p>
<h1>3. 字符串操作</h1>
<h2>3.1. 字符串拼接</h2>
<pre><code class="language-shell">str1=&quot;hello&quot;${your_name}&quot;world&quot;
str2=&quot;hello${your_name}world&quot;
str3=&#39;hello&#39;${your_name}&#39;world&#39;
</code></pre>
<h2>3.2. 字符串长度</h2>
<pre><code class="language-shell">str=&#39;hello&#39;
echo ${&lt;span class=&quot;tag&quot;&gt;#str&lt;/span&gt;}
5
</code></pre>
<h2>3.3. 字符串截取</h2>
<p><code>${string:start:length}</code>,索引从0开始,从start(包含)开始截取共计length长度的字符。</p>
<pre><code class="language-shell">str=&#39;helloworld&#39;
echo ${str:0:5}
hello
</code></pre>
<h2>3.4. 字符串运算符</h2>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>=</code></td>
<td>检测两个字符串是否相等,相等返回true</td>
<td><code>[ &#39;hello&#39; = &#39;hello&#39; ]</code></td>
</tr>
<tr>
<td><code>!=</code></td>
<td>检测两个字符串是否相等,不相等返回true</td>
<td><code>[ &#39;hello&#39; != &#39;ello&#39; ]</code></td>
</tr>
<tr>
<td><code>-z</code></td>
<td>检测字符串长度是否为0,为0返回true</td>
<td><code>[ -z &#39;&#39; ]</code></td>
</tr>
<tr>
<td><code>-n </code></td>
<td>检测字符串长度是否不为0,不为0返回true</td>
<td><code>[ -n &#39;hello&#39; ]</code></td>
</tr>
<tr>
<td><code>$</code></td>
<td>检测字符串是否为空,不为空返回true</td>
<td><code>[ $&#39;hello&#39; ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ &#39;hello&#39; = &#39;hello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ &#39;hello&#39; != &#39;ello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ -z &#39;&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ -n &#39;hello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ $&#39;hello&#39; ];then echo &#39;hello&#39;;fi
str=&#39;hello&#39;
if [ $str ];then echo &#39;hello&#39;;fi
# hello
</code></pre>
<p>注意字符串的等值判断是一个等号<code>&quot;=&quot;</code>,与下文要讲的逻辑运算符使用两个等号<code>&quot;==&quot;</code>做等值判断不一样。</p>
<h1>4. 文件测试运算符</h1>
<table>
<thead>
<tr>
<th>操作符</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>-b file</code></td>
<td>检测文件是否是块设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-c file</code></td>
<td>检测文件是否是字符设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-d file</code></td>
<td>检测文件是否是目录,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-f file</code></td>
<td>检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-g file</code></td>
<td>检测文件是否设置了<code>SGID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-k file</code></td>
<td>检测文件是否设置了粘着位(Sticky Bit),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-p file</code></td>
<td>检测文件是否是有名管道,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-u file</code></td>
<td>检测文件是否设置了<code>SUID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-r file</code></td>
<td>检测文件是否可读,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-w file</code></td>
<td>检测文件是否可写,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-x file</code></td>
<td>检测文件是否可执行,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-s file</code></td>
<td>检测文件是否为空(文件大小是否大于0),不为空返回true。</td>
</tr>
<tr>
<td><code>-e file</code></td>
<td>检测文件(包括目录)是否存在,如果是,则返回true。</td>
</tr>
</tbody></table>
<pre><code class="language-shell">if &lt;a href=&quot;f-home.html&quot; class=&quot;internal-link&quot;&gt; -f &#39;/home&#39; &lt;/a&gt;;then echo &#39;directory&#39;;else echo &#39;file&#39;;fi
# file
if &lt;a href=&quot;d-home.html&quot; class=&quot;internal-link&quot;&gt; -d &#39;/home&#39; &lt;/a&gt;;then echo &#39;directory&#39;;else echo &#39;file&#39;;fi
# directory
if &lt;a href=&quot;e-tmpfake-file.html&quot; class=&quot;internal-link&quot;&gt; -e &#39;/tmp/fake_file&#39; &lt;/a&gt;;then echo &#39;exist&#39;;else echo &#39;not exist&#39;;fi
# not exist
</code></pre>
<h1>5. 数组</h1>
<p><code>shell</code>只支持一维数组,用括号表示,元素通过空格分隔,形如<code>数组名=(值1 值2 ... 值n)</code>。<code>shell</code>数组下标从<code>1</code>开始。</p>
<ul>
<li><code>${数组名[下标]}</code>,读取指索引位置数组元素</li>
<li>使用<code>@</code>或<code>*</code>代替下标,获取数组中所有元素。</li>
<li>使用<code>{&lt;span class=&quot;tag&quot;&gt;#数组名&lt;/span&gt;[@]}</code>或<code>{&lt;span class=&quot;tag&quot;&gt;#数组名&lt;/span&gt;[*]}</code>获取数组元素个数。</li>
</ul>
<pre><code class="language-shell">arr=(value1 value2 value3 value4)
echo ${arr[3]}
# value3
echo ${arr[*]}
# value1 value2 value3 value4
echo ${arr[@]}
# value1 value2 value3 value4
arr[3]=&#39;new_value3&#39;
echo $arr[3]
# new_value3
echo ${&lt;span class=&quot;tag&quot;&gt;#arr&lt;/span&gt;[@]}
# 4
echo &quot;arr[1]的长度为:${&lt;span class=&quot;tag&quot;&gt;#arr&lt;/span&gt;[1]}&quot;
# arr[1]的长度为:6
</code></pre>
<h1>6. 运算符</h1>
<h2>6.1. 赋值运算符</h2>
<pre><code class="language-shell">a=10
b=$a
</code></pre>
<h2>6.2. 算术运算符</h2>
<p>算数运算符支持<code>+,-,*,/,%</code></p>
<h3>6.2.1. expr表示法</h3>
<pre><code class="language-shell">echo `expr 10 + 20`
# 30
echo $(expr 20 / 2)
# 10
echo $(expr 10 \* 20) # 使用expr进行乘法运算时必须使用\进行转义
# 200
</code></pre>
<blockquote>
<p>使用expr表示方法时,表达式和运算符之间必须有空格。</p>
</blockquote>
<h3>6.2.2. <code>$[]</code></h3>
<pre><code class="language-shell">echo $[10%3]
# 1
</code></pre>
<h3>6.2.3. <code>$(())</code></h3>
<pre><code class="language-shell">echo $((10*20))
# 200
</code></pre>
<h2>6.3. 关系运算符</h2>
<p>最常见的关系运算符是:<code>==,!=,&lt;,&gt;,&gt;=,&lt;=</code></p>
<pre><code class="language-shell">echo $[10==10]
# 1
flag=$[20==10]
echo $flag
# 1
echo $[10&gt;=10]
# 1
</code></pre>
<p>如下关系运算符只能使用在条件表达式<code>if、while</code>下,类似<code>flag=[ $a -eq $b ]</code>的直接赋值语句是非法的。关系运算符的条件表达式要放在<strong>一对</strong>方括号中,并且中间需要有空格。也可以使用<code>(())</code>替代<code>[]</code>,此时<code>-eq,-lt,-le</code>之类的需要使用<code>==,&lt;,&lt;=</code>等替换。</p>
<blockquote>
<p><code>[]</code>搭配<code>-eq -ne</code>等使用,<code>(())</code>搭配<code>|| &amp;&amp;</code>等使用。</p>
</blockquote>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>-eq</code></td>
<td>检测两个数是否相等,相等返回true。</td>
<td><code>[ $a -eq $b ]</code></td>
</tr>
<tr>
<td><code>-ne</code></td>
<td>检测两个数是否不相等,不相等返回 true。</td>
<td><code>[ $a -ne $b ]</code></td>
</tr>
<tr>
<td><code>-gt</code></td>
<td>检测左边的数是否大于右边的,如果是,则返回 true。</td>
<td><code>[ $a -gt $b ]</code></td>
</tr>
<tr>
<td><code>-lt</code></td>
<td>检测左边的数是否小于右边的,如果是,则返回 true。</td>
<td><code>[ $a -lt $b ]</code></td>
</tr>
<tr>
<td><code>-ge</code></td>
<td>检测左边的数是否大于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -ge $b ]</code></td>
</tr>
<tr>
<td><code>-le</code></td>
<td>检测左边的数是否小于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -le $b ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ 1 -eq 1 ];then echo &#39;hello&#39;;fi;
# hello
if ((10&gt;=10));then echo &#39;hello&#39;;fi;
# hello
</code></pre>
<h2>6.4. 布尔、逻辑运算符</h2>
<p>布尔、逻辑运算的条件表达式也要放在一对方括号中<code>[]</code>。</p>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>!</code></td>
<td>非运算,表达式为true则返回false,否则返回true。</td>
<td><code>[ ! 10 -eq 0 ]</code></td>
</tr>
<tr>
<td><code>-o</code></td>
<td>或运算,有一个表达式为true则返回true。</td>
<td><code>[ 10 -lt 20 -o 10 -gt 100 ]</code></td>
</tr>
<tr>
<td><code>-a</code></td>
<td>与运算,两个表达式都为true才返回true。</td>
<td><code>[ 10 -lt 20 -a 10 -gt 100 ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ ! 10 -eq 0 ];then echo &#39;hello&#39;;fi
# hello
if [ 10 -ge 10 -a 10 -ge 10 ];then echo &#39;hello&#39;;fi
# hello
if [ 10 -ge 20 -o 10 -ge 0 ];then echo &#39;hello&#39;;fi
# hello
</code></pre>
<p> <code>-o</code>也可以使用<code>||</code>替代,<code>-a</code>也可以使用<code>&amp;&amp;</code>替代,此时需要使用<code>(())</code>或<code>[[]]</code>替代<code>[]</code>。</p>
<pre><code class="language-shell">if &lt;a href=&quot;1010-55.html&quot; class=&quot;internal-link&quot;&gt; 10==10 &amp;&amp; 5==5 &lt;/a&gt;;then echo &#39;hello&#39;;fi
# hello
if ((10==10 &amp;&amp; 5==5));then echo &#39;hello&#39;;fi
# hello
</code></pre>
<h1>7. 传递参数</h1>
<p>在执行 <code>Shell</code>脚本时,向脚本传递参数,脚本内获取参数的格式为:<code>$n</code>。<code>n</code>代表一个数字,<code>1</code>为执行脚本的第一个参数,<code>2</code>为执行脚本的第二个参数,<code>$0</code>为执行的文件名。在为<code>shell</code>脚本传递的参数中如果包含空格,应该使用单引号或者双引号将该参数括起来,以便于脚本将这个参数作为整体来接收。另外,还有几个特殊字符用来处理参数:</p>
<table>
<thead>
<tr>
<th>参数处理</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>$#</code></td>
<td>传递到脚本的参数个数</td>
</tr>
<tr>
<td><code>$*</code></td>
<td>以一个单字符串显示所有向脚本传递的参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$$</code></td>
<td>脚本运行的当前进程ID号</td>
</tr>
<tr>
<td><code>$!</code></td>
<td>后台运行的最后一个进程的ID号</td>
</tr>
<tr>
<td><code>$@</code></td>
<td>与<code>$*</code>相同,但是使用时加引号,并在引号中返回每个参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$-</code></td>
<td>显示Shell使用的当前选项,与set功能相同。</td>
</tr>
<tr>
<td><code>$?</code></td>
<td>显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。</td>
</tr>
</tbody></table>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-bash">set -e
echo &quot;执行的文件名:$0&quot;
echo &quot;参数个数为$#&quot;
echo &quot;第一个参数为:$1&quot;
echo &quot;第二个参数为:$2&quot;
echo &quot;所有参数为:$@&quot;
echo &quot;进程ID号为:$$&quot;
echo &quot;当前shell选项为$-&quot;
echo &quot;上一个命令退出的状态为$?&quot;
</code></pre>
<p>执行结果如下:</p>
<pre><code class="language-shell">$ sh test.sh param1 &quot;param2 with space&quot;
执行的文件名:test.sh
参数个数为2
第一个参数为:param1
第二个参数为:param2 with space
所有参数为:param1 param2 with space
进程ID号为:3700
当前shell选项为ehB
上一个命令退出的状态为0
</code></pre>
<h1>8. 函数</h1>
<p>函数定义通过<code>function_name(){}</code>的形式定义,函数返回值可以显示用return返回,如果不加,将以最后一条命令的运行结果作为返回值,函数返回值只能是数字。函数也可以传递参数,但是函数定义的()中不需要申明。</p>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-shell">sayhello(){
echo &quot;hello&quot;
}
# 注意函数调用只需要函数名,不需要加()
sayhello
sayhellowithparam(){
echo &quot;hello, $1 $2 $3&quot;
return 1
}
sayhellowithparam zhangsan lisi wangwu
echo $?
</code></pre>
<p>输出如下:</p>
<blockquote>
<p>hello<br>hello, zhangsan lisi wangwu<br>1</p>
</blockquote>
<h1>9. 命令替换</h1>
<p>命令替换可以将一个命令的输出作为另外一个命令的参数。</p>
<pre><code class="language-shell"># command1 `command2`
cd `pwd` # 该命令将pwd命令列出的目录作为cd命令的参数,结果仍然是停留在当前目录下
cd `echo $HOME` # 将echo的输出作为cd的参数,即打开用户根目录
</code></pre>
<h1>10. let命令</h1>
<p>let 命令是 BASH 中用于计算的工具,用于执行一个或多个表达式,变量计算中不需要加上 $ 来表示变量。如果表达式中包含了空格或其他特殊字符,则必须引起来。</p>
<ul>
<li>自加操作:<code>let no++</code></li>
<li>自减操作:<code>let no--</code></li>
<li>简写形式 <code>let no+=10</code>,<code>let no-=20</code>,分别等同于<code>let no=no+10</code>,<code>let no=no-20</code></li>
</ul>
<h1>11. 流程控制</h1>
<h2>11.1. if</h2>
<pre><code class="language-shell">if ((10&lt;2));then
echo &quot;10小于2&quot;
elif ((10&gt;20));then
echo &quot;a大于10&quot;
else
echo &quot;10大于2且小于10&quot;
fi
</code></pre>
<h2>11.2. case</h2>
<p><code>case</code>每一种情况以右括号结尾,执行到<code>;;</code>结束</p>
<pre><code class="language-shell">case 10 in
0|1)
echo &quot;a为0或1&quot;
;;
11|12)
echo &quot;a为11或12&quot;
;;
*)
# *用来匹配所有情况
echo &quot;a为10&quot;
;;
esac
</code></pre>
<h2>11.3. while</h2>
<pre><code class="language-shell">count=0
while(($count&lt;5))
do
echo $count
let count++
done
</code></pre>
<h2>11.4. util</h2>
<pre><code class="language-shell">count=0
until(($count&gt;=5))
do
echo $count
let count++
done
</code></pre>
<h2>11.5. for</h2>
<pre><code class="language-shell"># for写法1
for ((count=0;$count&lt;5;count=$count+1))
do
echo $count
done
# for写法2
arr=(0 1 2 3 4)
for count in ${arr[*]}
do
echo $int
done
# for写法3
for int in 0 1 2 3 4
do
echo $int
done
</code></pre>
<h2>11.6. break和continue</h2>
<p>用法与一般编程语言类似,break跳出循环,continue跳出当前循环</p>
<pre><code class="language-shell">for ((count=0;$count&gt;=0;count=$count+1))
do
if (($count&gt;=5));then
break;
fi
echo $count
done
</code></pre>
<h1>12. 输入输出重定向</h1>
<h2>12.1. 输出重定向</h2>
<p><code>command &gt; file</code>将命令输出结果保存的file文件中。<code>&gt;</code>从文件头开始写,会覆盖旧内容,<code>&gt;&gt;</code>将内容追加到文件末尾</p>
<pre><code class="language-shell"># 将who命令的输出保存的users文件中,可以通过cat users查看
who &gt; users
# 将字符串hello world保存到text.txt文件中
echo &quot;hello world&quot; &gt; text.txt
</code></pre>
<h2>12.2. 输入重定向</h2>
<p><code>command &lt; file</code>从file文件获取输入</p>
<pre><code class="language-shell">wc -l /etc/passwd
# 123 /etc/passwd
wc -l &lt; users
# 123
# 第一个例子,会输出文件名;第二个不会,因为它仅仅知道从标准输入读取内容
# command &lt; infile &gt; outfile, 同时替换输入和输出,执行command,从文件infile读取内容,然后将输出写入到outfile中。
wc -l &lt; /etc/passwd &gt; result
cat result
# 123
</code></pre>
<h2>12.3. 文件描述符</h2>
<p>一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件</p>
<ul>
<li>标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。</li>
<li>标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。</li>
<li>标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。</li>
</ul>
<pre><code class="language-shell"># 将标准错误输出重定向到error_trace
cat /tmp/fake_file 2&gt;error_trace
cat error_trace
# cat: /tmp/fake_fule: No such file or directory
# 将标准输出和标准错误输出都重定向到result
cat /tmp/fake_file &amp;&gt;result
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准错误重定向到标准输出
ls /tmp/fake_file &gt; result 2&gt;&amp;1
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准输入重定向到result,将标准错误输出重定向到error_trace
cat /tmp/fake_file 1&gt;result 2&gt;error_trace
</code></pre>
<h2>12.4. Here Document</h2>
<p>将两个<code>EOF</code>之间的内容(document) 作为输入传递给<code>command</code></p>
<pre><code class="language-bash"># command &lt;&lt; EOF
# document
# EOF
cat &lt;&lt; EOF
hello
shinerio
learn shell
EOF
</code></pre>
<blockquote>
<p>结尾的<code>EOF</code>一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和<code>tab</code>缩进。开始的<code>EOF</code>前后的空格会被忽略掉。</p>
</blockquote>
<h2>12.5. /dev/null</h2>
<p>如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null。<code>command &gt; /dev/null</code></p>
<pre><code class="language-shell">cat users &gt; /dev/null
cat users &gt; /dev/null 2&gt;&amp;1
</code></pre>
<h1>13. set命令</h1>
<p>set指令能设置所使用shell的执行方式,可依照不同的需求来做设置。以下只列出常用的选项参数:</p>
<ul>
<li>-e 若指令传回值不等于0,则立即退出shell。</li>
<li>-f 取消使用通配符。</li>
<li>-n 只读取指令,而不实际执行。</li>
<li>-x 执行指令后,会先显示该指令及所下的参数。</li>
</ul>
#39;hello' ];then echo 'hello';fi
str='hello'
if [ $str ];then echo 'hello';fi
# hello
</code></pre>
<p>注意字符串的等值判断是一个等号<code>"="</code>,与下文要讲的逻辑运算符使用两个等号<code>"=="</code>做等值判断不一样。</p>
<h1>4. 文件测试运算符</h1>
<table>
<thead>
<tr>
<th>操作符</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>-b file</code></td>
<td>检测文件是否是块设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-c file</code></td>
<td>检测文件是否是字符设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-d file</code></td>
<td>检测文件是否是目录,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-f file</code></td>
<td>检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-g file</code></td>
<td>检测文件是否设置了<code>SGID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-k file</code></td>
<td>检测文件是否设置了粘着位(Sticky Bit),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-p file</code></td>
<td>检测文件是否是有名管道,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-u file</code></td>
<td>检测文件是否设置了<code>SUID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-r file</code></td>
<td>检测文件是否可读,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-w file</code></td>
<td>检测文件是否可写,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-x file</code></td>
<td>检测文件是否可执行,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-s file</code></td>
<td>检测文件是否为空(文件大小是否大于0),不为空返回true。</td>
</tr>
<tr>
<td><code>-e file</code></td>
<td>检测文件(包括目录)是否存在,如果是,则返回true。</td>
</tr>
</tbody></table>
<pre><code class="language-shell">if <a href="f-home.html" class="internal-link"> -f '/home' </a>;then echo 'directory';else echo 'file';fi
# file
if <a href="d-home.html" class="internal-link"> -d '/home' </a>;then echo 'directory';else echo 'file';fi
# directory
if <a href="e-tmpfake-file.html" class="internal-link"> -e '/tmp/fake_file' </a>;then echo 'exist';else echo 'not exist';fi
# not exist
</code></pre>
<h1>5. 数组</h1>
<p><code>shell</code>只支持一维数组,用括号表示,元素通过空格分隔,形如<code>数组名=(值1 值2 ... 值n)</code>。<code>shell</code>数组下标从<code>1</code>开始。</p>
<ul>
<li><code>${数组名[下标]}</code>,读取指索引位置数组元素</li>
<li>使用<code>@</code>或<code>*</code>代替下标,获取数组中所有元素。</li>
<li>使用<code>{<span class="tag">#数组名</span>[@]}</code>或<code>{<span class="tag">#数组名</span>[*]}</code>获取数组元素个数。</li>
</ul>
<pre><code class="language-shell">arr=(value1 value2 value3 value4)
echo ${arr[3]}
# value3
echo ${arr[*]}
# value1 value2 value3 value4
echo ${arr[@]}
# value1 value2 value3 value4
arr[3]='new_value3'
echo $arr[3]
# new_value3
echo ${<span class="tag">#arr</span>[@]}
# 4
echo "arr[1]的长度为:${<span class="tag">#arr</span>[1]}"
# arr[1]的长度为:6
</code></pre>
<h1>6. 运算符</h1>
<h2>6.1. 赋值运算符</h2>
<pre><code class="language-shell">a=10
b=$a
</code></pre>
<h2>6.2. 算术运算符</h2>
<p>算数运算符支持<code>+,-,*,/,%</code></p>
<h3>6.2.1. expr表示法</h3>
<pre><code class="language-shell">echo `expr 10 + 20`
# 30
echo $(expr 20 / 2)
# 10
echo $(expr 10 \* 20) # 使用expr进行乘法运算时必须使用\进行转义
# 200
</code></pre>
<blockquote>
<p>使用expr表示方法时,表达式和运算符之间必须有空格。</p>
</blockquote>
<h3>6.2.2. <code>$[]</code></h3>
<pre><code class="language-shell">echo $[10%3]
# 1
</code></pre>
<h3>6.2.3. <code>$(())</code></h3>
<pre><code class="language-shell">echo $((10*20))
# 200
</code></pre>
<h2>6.3. 关系运算符</h2>
<p>最常见的关系运算符是:<code>==,!=,<,>,>=,<=</code></p>
<pre><code class="language-shell">echo $[10==10]
# 1
flag=$[20==10]
echo $flag
# 1
echo $[10>=10]
# 1
</code></pre>
<p>如下关系运算符只能使用在条件表达式<code>if、while</code>下,类似<code>flag=[ $a -eq $b ]</code>的直接赋值语句是非法的。关系运算符的条件表达式要放在<strong>一对</strong>方括号中,并且中间需要有空格。也可以使用<code>(())</code>替代<code>[]</code>,此时<code>-eq,-lt,-le</code>之类的需要使用<code>==,<,<=</code>等替换。</p>
<blockquote>
<p><code>[]</code>搭配<code>-eq -ne</code>等使用,<code>(())</code>搭配<code>|| &&</code>等使用。</p>
</blockquote>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>-eq</code></td>
<td>检测两个数是否相等,相等返回true。</td>
<td><code>[ $a -eq $b ]</code></td>
</tr>
<tr>
<td><code>-ne</code></td>
<td>检测两个数是否不相等,不相等返回 true。</td>
<td><code>[ $a -ne $b ]</code></td>
</tr>
<tr>
<td><code>-gt</code></td>
<td>检测左边的数是否大于右边的,如果是,则返回 true。</td>
<td><code>[ $a -gt $b ]</code></td>
</tr>
<tr>
<td><code>-lt</code></td>
<td>检测左边的数是否小于右边的,如果是,则返回 true。</td>
<td><code>[ $a -lt $b ]</code></td>
</tr>
<tr>
<td><code>-ge</code></td>
<td>检测左边的数是否大于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -ge $b ]</code></td>
</tr>
<tr>
<td><code>-le</code></td>
<td>检测左边的数是否小于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -le $b ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ 1 -eq 1 ];then echo 'hello';fi;
# hello
if ((10>=10));then echo 'hello';fi;
# hello
</code></pre>
<h2>6.4. 布尔、逻辑运算符</h2>
<p>布尔、逻辑运算的条件表达式也要放在一对方括号中<code>[]</code>。</p>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>!</code></td>
<td>非运算,表达式为true则返回false,否则返回true。</td>
<td><code>[ ! 10 -eq 0 ]</code></td>
</tr>
<tr>
<td><code>-o</code></td>
<td>或运算,有一个表达式为true则返回true。</td>
<td><code>[ 10 -lt 20 -o 10 -gt 100 ]</code></td>
</tr>
<tr>
<td><code>-a</code></td>
<td>与运算,两个表达式都为true才返回true。</td>
<td><code>[ 10 -lt 20 -a 10 -gt 100 ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ ! 10 -eq 0 ];then echo 'hello';fi
# hello
if [ 10 -ge 10 -a 10 -ge 10 ];then echo 'hello';fi
# hello
if [ 10 -ge 20 -o 10 -ge 0 ];then echo 'hello';fi
# hello
</code></pre>
<p> <code>-o</code>也可以使用<code>||</code>替代,<code>-a</code>也可以使用<code>&&</code>替代,此时需要使用<code>(())</code>或<code>[[]]</code>替代<code>[]</code>。</p>
<pre><code class="language-shell">if <a href="1010-55.html" class="internal-link"> 10==10 && 5==5 </a>;then echo 'hello';fi
# hello
if ((10==10 && 5==5));then echo 'hello';fi
# hello
</code></pre>
<h1>7. 传递参数</h1>
<p>在执行 <code>Shell</code>脚本时,向脚本传递参数,脚本内获取参数的格式为:<code>$n</code>。<code>n</code>代表一个数字,<code>1</code>为执行脚本的第一个参数,<code>2</code>为执行脚本的第二个参数,<code>$0</code>为执行的文件名。在为<code>shell</code>脚本传递的参数中如果包含空格,应该使用单引号或者双引号将该参数括起来,以便于脚本将这个参数作为整体来接收。另外,还有几个特殊字符用来处理参数:</p>
<table>
<thead>
<tr>
<th>参数处理</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>$#</code></td>
<td>传递到脚本的参数个数</td>
</tr>
<tr>
<td><code>$*</code></td>
<td>以一个单字符串显示所有向脚本传递的参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$</code></td>
<td>脚本运行的当前进程ID号</td>
</tr>
<tr>
<td><code>$!</code></td>
<td>后台运行的最后一个进程的ID号</td>
</tr>
<tr>
<td><code>$@</code></td>
<td>与<code>$*</code>相同,但是使用时加引号,并在引号中返回每个参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$-</code></td>
<td>显示Shell使用的当前选项,与set功能相同。</td>
</tr>
<tr>
<td><code>$?</code></td>
<td>显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。</td>
</tr>
</tbody></table>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-bash">set -e
echo "执行的文件名:$0"
echo "参数个数为$#"
echo "第一个参数为:$1"
echo "第二个参数为:$2"
echo "所有参数为:$@"
echo "进程ID号为:$"
echo "当前shell选项为$-"
echo "上一个命令退出的状态为$?"
</code></pre>
<p>执行结果如下:</p>
<pre><code class="language-shell">$ sh test.sh param1 "param2 with space"
执行的文件名:test.sh
参数个数为2
第一个参数为:param1
第二个参数为:param2 with space
所有参数为:param1 param2 with space
进程ID号为:3700
当前shell选项为ehB
上一个命令退出的状态为0
</code></pre>
<h1>8. 函数</h1>
<p>函数定义通过<code>function_name(){}</code>的形式定义,函数返回值可以显示用return返回,如果不加,将以最后一条命令的运行结果作为返回值,函数返回值只能是数字。函数也可以传递参数,但是函数定义的()中不需要申明。</p>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-shell">sayhello(){
echo "hello"
}
# 注意函数调用只需要函数名,不需要加()
sayhello
sayhellowithparam(){
echo "hello, $1 $2 $3"
return 1
}
sayhellowithparam zhangsan lisi wangwu
echo $?
</code></pre>
<p>输出如下:</p>
<blockquote>
<p>hello<br>hello, zhangsan lisi wangwu<br>1</p>
</blockquote>
<h1>9. 命令替换</h1>
<p>命令替换可以将一个命令的输出作为另外一个命令的参数。</p>
<pre><code class="language-shell"># command1 `command2`
cd `pwd` # 该命令将pwd命令列出的目录作为cd命令的参数,结果仍然是停留在当前目录下
cd `echo $HOME` # 将echo的输出作为cd的参数,即打开用户根目录
</code></pre>
<h1>10. let命令</h1>
<p>let 命令是 BASH 中用于计算的工具,用于执行一个或多个表达式,变量计算中不需要加上 $ 来表示变量。如果表达式中包含了空格或其他特殊字符,则必须引起来。</p>
<ul>
<li>自加操作:<code>let no++</code></li>
<li>自减操作:<code>let no--</code></li>
<li>简写形式 <code>let no+=10</code>,<code>let no-=20</code>,分别等同于<code>let no=no+10</code>,<code>let no=no-20</code></li>
</ul>
<h1>11. 流程控制</h1>
<h2>11.1. if</h2>
<pre><code class="language-shell">if ((10<2));then
echo "10小于2"
elif ((10>20));then
echo "a大于10"
else
echo "10大于2且小于10"
fi
</code></pre>
<h2>11.2. case</h2>
<p><code>case</code>每一种情况以右括号结尾,执行到<code>;;</code>结束</p>
<pre><code class="language-shell">case 10 in
0|1)
echo "a为0或1"
;;
11|12)
echo "a为11或12"
;;
*)
# *用来匹配所有情况
echo "a为10"
;;
esac
</code></pre>
<h2>11.3. while</h2>
<pre><code class="language-shell">count=0
while(($count<5))
do
echo $count
let count++
done
</code></pre>
<h2>11.4. util</h2>
<pre><code class="language-shell">count=0
until(($count>=5))
do
echo $count
let count++
done
</code></pre>
<h2>11.5. for</h2>
<pre><code class="language-shell"># for写法1
for ((count=0;$count<5;count=$count+1))
do
echo $count
done
# for写法2
arr=(0 1 2 3 4)
for count in ${arr[*]}
do
echo $int
done
# for写法3
for int in 0 1 2 3 4
do
echo $int
done
</code></pre>
<h2>11.6. break和continue</h2>
<p>用法与一般编程语言类似,break跳出循环,continue跳出当前循环</p>
<pre><code class="language-shell">for ((count=0;$count>=0;count=$count+1))
do
if (($count>=5));then
break;
fi
echo $count
done
</code></pre>
<h1>12. 输入输出重定向</h1>
<h2>12.1. 输出重定向</h2>
<p><code>command > file</code>将命令输出结果保存的file文件中。<code>></code>从文件头开始写,会覆盖旧内容,<code>>></code>将内容追加到文件末尾</p>
<pre><code class="language-shell"># 将who命令的输出保存的users文件中,可以通过cat users查看
who > users
# 将字符串hello world保存到text.txt文件中
echo "hello world" > text.txt
</code></pre>
<h2>12.2. 输入重定向</h2>
<p><code>command < file</code>从file文件获取输入</p>
<pre><code class="language-shell">wc -l /etc/passwd
# 123 /etc/passwd
wc -l < users
# 123
# 第一个例子,会输出文件名;第二个不会,因为它仅仅知道从标准输入读取内容
# command < infile > outfile, 同时替换输入和输出,执行command,从文件infile读取内容,然后将输出写入到outfile中。
wc -l < /etc/passwd > result
cat result
# 123
</code></pre>
<h2>12.3. 文件描述符</h2>
<p>一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件</p>
<ul>
<li>标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。</li>
<li>标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。</li>
<li>标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。</li>
</ul>
<pre><code class="language-shell"># 将标准错误输出重定向到error_trace
cat /tmp/fake_file 2>error_trace
cat error_trace
# cat: /tmp/fake_fule: No such file or directory
# 将标准输出和标准错误输出都重定向到result
cat /tmp/fake_file &>result
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准错误重定向到标准输出
ls /tmp/fake_file > result 2>&1
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准输入重定向到result,将标准错误输出重定向到error_trace
cat /tmp/fake_file 1>result 2>error_trace
</code></pre>
<h2>12.4. Here Document</h2>
<p>将两个<code>EOF</code>之间的内容(document) 作为输入传递给<code>command</code></p>
<pre><code class="language-bash"># command << EOF
# document
# EOF
cat << EOF
hello
shinerio
learn shell
EOF
</code></pre>
<blockquote>
<p>结尾的<code>EOF</code>一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和<code>tab</code>缩进。开始的<code>EOF</code>前后的空格会被忽略掉。</p>
</blockquote>
<h2>12.5. /dev/null</h2>
<p>如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null。<code>command > /dev/null</code></p>
<pre><code class="language-shell">cat users > /dev/null
cat users > /dev/null 2>&1
</code></pre>
<h1>13. set命令</h1>
<p>set指令能设置所使用shell的执行方式,可依照不同的需求来做设置。以下只列出常用的选项参数:</p>
<ul>
<li>-e 若指令传回值不等于0,则立即退出shell。</li>
<li>-f 取消使用通配符。</li>
<li>-n 只读取指令,而不实际执行。</li>
<li>-x 执行指令后,会先显示该指令及所下的参数。</li>
</ul>
</section>
</article>amp;#39;hello' ];then echo 'hello';fi
str='hello'
if [ $str ];then echo 'hello';fi
# hello
</code></pre>
<p>注意字符串的等值判断是一个等号<code>"="</code>,与下文要讲的逻辑运算符使用两个等号<code>"=="</code>做等值判断不一样。</p>
<h1>4. 文件测试运算符</h1>
<table>
<thead>
<tr>
<th>操作符</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>-b file</code></td>
<td>检测文件是否是块设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-c file</code></td>
<td>检测文件是否是字符设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-d file</code></td>
<td>检测文件是否是目录,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-f file</code></td>
<td>检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-g file</code></td>
<td>检测文件是否设置了<code>SGID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-k file</code></td>
<td>检测文件是否设置了粘着位(Sticky Bit),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-p file</code></td>
<td>检测文件是否是有名管道,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-u file</code></td>
<td>检测文件是否设置了<code>SUID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-r file</code></td>
<td>检测文件是否可读,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-w file</code></td>
<td>检测文件是否可写,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-x file</code></td>
<td>检测文件是否可执行,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-s file</code></td>
<td>检测文件是否为空(文件大小是否大于0),不为空返回true。</td>
</tr>
<tr>
<td><code>-e file</code></td>
<td>检测文件(包括目录)是否存在,如果是,则返回true。</td>
</tr>
</tbody></table>
<pre><code class="language-shell">if <a href="f-home.html" class="internal-link"> -f '/home' </a>;then echo 'directory';else echo 'file';fi
# file
if <a href="d-home.html" class="internal-link"> -d '/home' </a>;then echo 'directory';else echo 'file';fi
# directory
if <a href="e-tmpfake-file.html" class="internal-link"> -e '/tmp/fake_file' </a>;then echo 'exist';else echo 'not exist';fi
# not exist
</code></pre>
<h1>5. 数组</h1>
<p><code>shell</code>只支持一维数组,用括号表示,元素通过空格分隔,形如<code>数组名=(值1 值2 ... 值n)</code>。<code>shell</code>数组下标从<code>1</code>开始。</p>
<ul>
<li><code>${数组名[下标]}</code>,读取指索引位置数组元素</li>
<li>使用<code>@</code>或<code>*</code>代替下标,获取数组中所有元素。</li>
<li>使用<code>{<span class="tag">#数组名</span>[@]}</code>或<code>{<span class="tag">#数组名</span>[*]}</code>获取数组元素个数。</li>
</ul>
<pre><code class="language-shell">arr=(value1 value2 value3 value4)
echo ${arr[3]}
# value3
echo ${arr[*]}
# value1 value2 value3 value4
echo ${arr[@]}
# value1 value2 value3 value4
arr[3]='new_value3'
echo $arr[3]
# new_value3
echo ${<span class="tag">#arr</span>[@]}
# 4
echo "arr[1]的长度为:${<span class="tag">#arr</span>[1]}"
# arr[1]的长度为:6
</code></pre>
<h1>6. 运算符</h1>
<h2>6.1. 赋值运算符</h2>
<pre><code class="language-shell">a=10
b=$a
</code></pre>
<h2>6.2. 算术运算符</h2>
<p>算数运算符支持<code>+,-,*,/,%</code></p>
<h3>6.2.1. expr表示法</h3>
<pre><code class="language-shell">echo `expr 10 + 20`
# 30
echo $(expr 20 / 2)
# 10
echo $(expr 10 \* 20) # 使用expr进行乘法运算时必须使用\进行转义
# 200
</code></pre>
<blockquote>
<p>使用expr表示方法时,表达式和运算符之间必须有空格。</p>
</blockquote>
<h3>6.2.2. <code>$[]</code></h3>
<pre><code class="language-shell">echo $[10%3]
# 1
</code></pre>
<h3>6.2.3. <code>$(())</code></h3>
<pre><code class="language-shell">echo $((10*20))
# 200
</code></pre>
<h2>6.3. 关系运算符</h2>
<p>最常见的关系运算符是:<code>==,!=,<,>,>=,<=</code></p>
<pre><code class="language-shell">echo $[10==10]
# 1
flag=$[20==10]
echo $flag
# 1
echo $[10>=10]
# 1
</code></pre>
<p>如下关系运算符只能使用在条件表达式<code>if、while</code>下,类似<code>flag=[ $a -eq $b ]</code>的直接赋值语句是非法的。关系运算符的条件表达式要放在<strong>一对</strong>方括号中,并且中间需要有空格。也可以使用<code>(())</code>替代<code>[]</code>,此时<code>-eq,-lt,-le</code>之类的需要使用<code>==,<,<=</code>等替换。</p>
<blockquote>
<p><code>[]</code>搭配<code>-eq -ne</code>等使用,<code>(())</code>搭配<code>|| &&</code>等使用。</p>
</blockquote>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>-eq</code></td>
<td>检测两个数是否相等,相等返回true。</td>
<td><code>[ $a -eq $b ]</code></td>
</tr>
<tr>
<td><code>-ne</code></td>
<td>检测两个数是否不相等,不相等返回 true。</td>
<td><code>[ $a -ne $b ]</code></td>
</tr>
<tr>
<td><code>-gt</code></td>
<td>检测左边的数是否大于右边的,如果是,则返回 true。</td>
<td><code>[ $a -gt $b ]</code></td>
</tr>
<tr>
<td><code>-lt</code></td>
<td>检测左边的数是否小于右边的,如果是,则返回 true。</td>
<td><code>[ $a -lt $b ]</code></td>
</tr>
<tr>
<td><code>-ge</code></td>
<td>检测左边的数是否大于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -ge $b ]</code></td>
</tr>
<tr>
<td><code>-le</code></td>
<td>检测左边的数是否小于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -le $b ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ 1 -eq 1 ];then echo 'hello';fi;
# hello
if ((10>=10));then echo 'hello';fi;
# hello
</code></pre>
<h2>6.4. 布尔、逻辑运算符</h2>
<p>布尔、逻辑运算的条件表达式也要放在一对方括号中<code>[]</code>。</p>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>!</code></td>
<td>非运算,表达式为true则返回false,否则返回true。</td>
<td><code>[ ! 10 -eq 0 ]</code></td>
</tr>
<tr>
<td><code>-o</code></td>
<td>或运算,有一个表达式为true则返回true。</td>
<td><code>[ 10 -lt 20 -o 10 -gt 100 ]</code></td>
</tr>
<tr>
<td><code>-a</code></td>
<td>与运算,两个表达式都为true才返回true。</td>
<td><code>[ 10 -lt 20 -a 10 -gt 100 ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ ! 10 -eq 0 ];then echo 'hello';fi
# hello
if [ 10 -ge 10 -a 10 -ge 10 ];then echo 'hello';fi
# hello
if [ 10 -ge 20 -o 10 -ge 0 ];then echo 'hello';fi
# hello
</code></pre>
<p> <code>-o</code>也可以使用<code>||</code>替代,<code>-a</code>也可以使用<code>&&</code>替代,此时需要使用<code>(())</code>或<code>[[]]</code>替代<code>[]</code>。</p>
<pre><code class="language-shell">if <a href="1010-55.html" class="internal-link"> 10==10 && 5==5 </a>;then echo 'hello';fi
# hello
if ((10==10 && 5==5));then echo 'hello';fi
# hello
</code></pre>
<h1>7. 传递参数</h1>
<p>在执行 <code>Shell</code>脚本时,向脚本传递参数,脚本内获取参数的格式为:<code>$n</code>。<code>n</code>代表一个数字,<code>1</code>为执行脚本的第一个参数,<code>2</code>为执行脚本的第二个参数,<code>$0</code>为执行的文件名。在为<code>shell</code>脚本传递的参数中如果包含空格,应该使用单引号或者双引号将该参数括起来,以便于脚本将这个参数作为整体来接收。另外,还有几个特殊字符用来处理参数:</p>
<table>
<thead>
<tr>
<th>参数处理</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>$#</code></td>
<td>传递到脚本的参数个数</td>
</tr>
<tr>
<td><code>$*</code></td>
<td>以一个单字符串显示所有向脚本传递的参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$</code></td>
<td>脚本运行的当前进程ID号</td>
</tr>
<tr>
<td><code>$!</code></td>
<td>后台运行的最后一个进程的ID号</td>
</tr>
<tr>
<td><code>$@</code></td>
<td>与<code>$*</code>相同,但是使用时加引号,并在引号中返回每个参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$-</code></td>
<td>显示Shell使用的当前选项,与set功能相同。</td>
</tr>
<tr>
<td><code>$?</code></td>
<td>显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。</td>
</tr>
</tbody></table>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-bash">set -e
echo "执行的文件名:$0"
echo "参数个数为$#"
echo "第一个参数为:$1"
echo "第二个参数为:$2"
echo "所有参数为:$@"
echo "进程ID号为:$"
echo "当前shell选项为$-"
echo "上一个命令退出的状态为$?"
</code></pre>
<p>执行结果如下:</p>
<pre><code class="language-shell">$ sh test.sh param1 "param2 with space"
执行的文件名:test.sh
参数个数为2
第一个参数为:param1
第二个参数为:param2 with space
所有参数为:param1 param2 with space
进程ID号为:3700
当前shell选项为ehB
上一个命令退出的状态为0
</code></pre>
<h1>8. 函数</h1>
<p>函数定义通过<code>function_name(){}</code>的形式定义,函数返回值可以显示用return返回,如果不加,将以最后一条命令的运行结果作为返回值,函数返回值只能是数字。函数也可以传递参数,但是函数定义的()中不需要申明。</p>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-shell">sayhello(){
echo "hello"
}
# 注意函数调用只需要函数名,不需要加()
sayhello
sayhellowithparam(){
echo "hello, $1 $2 $3"
return 1
}
sayhellowithparam zhangsan lisi wangwu
echo $?
</code></pre>
<p>输出如下:</p>
<blockquote>
<p>hello<br>hello, zhangsan lisi wangwu<br>1</p>
</blockquote>
<h1>9. 命令替换</h1>
<p>命令替换可以将一个命令的输出作为另外一个命令的参数。</p>
<pre><code class="language-shell"># command1 `command2`
cd `pwd` # 该命令将pwd命令列出的目录作为cd命令的参数,结果仍然是停留在当前目录下
cd `echo $HOME` # 将echo的输出作为cd的参数,即打开用户根目录
</code></pre>
<h1>10. let命令</h1>
<p>let 命令是 BASH 中用于计算的工具,用于执行一个或多个表达式,变量计算中不需要加上 $ 来表示变量。如果表达式中包含了空格或其他特殊字符,则必须引起来。</p>
<ul>
<li>自加操作:<code>let no++</code></li>
<li>自减操作:<code>let no--</code></li>
<li>简写形式 <code>let no+=10</code>,<code>let no-=20</code>,分别等同于<code>let no=no+10</code>,<code>let no=no-20</code></li>
</ul>
<h1>11. 流程控制</h1>
<h2>11.1. if</h2>
<pre><code class="language-shell">if ((10<2));then
echo "10小于2"
elif ((10>20));then
echo "a大于10"
else
echo "10大于2且小于10"
fi
</code></pre>
<h2>11.2. case</h2>
<p><code>case</code>每一种情况以右括号结尾,执行到<code>;;</code>结束</p>
<pre><code class="language-shell">case 10 in
0|1)
echo "a为0或1"
;;
11|12)
echo "a为11或12"
;;
*)
# *用来匹配所有情况
echo "a为10"
;;
esac
</code></pre>
<h2>11.3. while</h2>
<pre><code class="language-shell">count=0
while(($count<5))
do
echo $count
let count++
done
</code></pre>
<h2>11.4. util</h2>
<pre><code class="language-shell">count=0
until(($count>=5))
do
echo $count
let count++
done
</code></pre>
<h2>11.5. for</h2>
<pre><code class="language-shell"># for写法1
for ((count=0;$count<5;count=$count+1))
do
echo $count
done
# for写法2
arr=(0 1 2 3 4)
for count in ${arr[*]}
do
echo $int
done
# for写法3
for int in 0 1 2 3 4
do
echo $int
done
</code></pre>
<h2>11.6. break和continue</h2>
<p>用法与一般编程语言类似,break跳出循环,continue跳出当前循环</p>
<pre><code class="language-shell">for ((count=0;$count>=0;count=$count+1))
do
if (($count>=5));then
break;
fi
echo $count
done
</code></pre>
<h1>12. 输入输出重定向</h1>
<h2>12.1. 输出重定向</h2>
<p><code>command > file</code>将命令输出结果保存的file文件中。<code>></code>从文件头开始写,会覆盖旧内容,<code>>></code>将内容追加到文件末尾</p>
<pre><code class="language-shell"># 将who命令的输出保存的users文件中,可以通过cat users查看
who > users
# 将字符串hello world保存到text.txt文件中
echo "hello world" > text.txt
</code></pre>
<h2>12.2. 输入重定向</h2>
<p><code>command < file</code>从file文件获取输入</p>
<pre><code class="language-shell">wc -l /etc/passwd
# 123 /etc/passwd
wc -l < users
# 123
# 第一个例子,会输出文件名;第二个不会,因为它仅仅知道从标准输入读取内容
# command < infile > outfile, 同时替换输入和输出,执行command,从文件infile读取内容,然后将输出写入到outfile中。
wc -l < /etc/passwd > result
cat result
# 123
</code></pre>
<h2>12.3. 文件描述符</h2>
<p>一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件</p>
<ul>
<li>标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。</li>
<li>标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。</li>
<li>标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。</li>
</ul>
<pre><code class="language-shell"># 将标准错误输出重定向到error_trace
cat /tmp/fake_file 2>error_trace
cat error_trace
# cat: /tmp/fake_fule: No such file or directory
# 将标准输出和标准错误输出都重定向到result
cat /tmp/fake_file &>result
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准错误重定向到标准输出
ls /tmp/fake_file > result 2>&1
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准输入重定向到result,将标准错误输出重定向到error_trace
cat /tmp/fake_file 1>result 2>error_trace
</code></pre>
<h2>12.4. Here Document</h2>
<p>将两个<code>EOF</code>之间的内容(document) 作为输入传递给<code>command</code></p>
<pre><code class="language-bash"># command << EOF
# document
# EOF
cat << EOF
hello
shinerio
learn shell
EOF
</code></pre>
<blockquote>
<p>结尾的<code>EOF</code>一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和<code>tab</code>缩进。开始的<code>EOF</code>前后的空格会被忽略掉。</p>
</blockquote>
<h2>12.5. /dev/null</h2>
<p>如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null。<code>command > /dev/null</code></p>
<pre><code class="language-shell">cat users > /dev/null
cat users > /dev/null 2>&1
</code></pre>
<h1>13. set命令</h1>
<p>set指令能设置所使用shell的执行方式,可依照不同的需求来做设置。以下只列出常用的选项参数:</p>
<ul>
<li>-e 若指令传回值不等于0,则立即退出shell。</li>
<li>-f 取消使用通配符。</li>
<li>-n 只读取指令,而不实际执行。</li>
<li>-x 执行指令后,会先显示该指令及所下的参数。</li>
</ul>
#39;hello' ] |
if [ 'hello' = 'hello' ];then echo 'hello';fi
# hello
if [ 'hello' != 'ello' ];then echo 'hello';fi
# hello
if [ -z '' ];then echo 'hello';fi
# hello
if [ -n 'hello' ];then echo 'hello';fi
# hello
if [ <p>本文主要介绍shell编程的基本语法以及实际应用中的常见命令。</p>
<h1>1. 注释</h1>
<h2>1.1. 单行注释</h2>
<pre><code class="language-shell"># 这是单行注释
</code></pre>
<h2>1.2. 多行注释</h2>
<pre><code class="language-shell">:<<EOF
多行注释内容
多行注释内容
多行注释内容
EOF
</code></pre>
<p>多行注释<code>EOF</code>也可替换成<code>!</code>或<code>'</code></p>
<pre><code class="language-shell">:<<'
多行注释内容
多行注释内容
多行注释内容
'
:<<!
多行注释内容
多行注释内容
多行注释内容
!
</code></pre>
<h1>2. 变量</h1>
<h2>2.1. 变量定义</h2>
<p>使用<code>VARIABLENAME=VALUE</code>的形式,VALUE如果是字符串的话,可以使用单引号、双引号或者不加引号。单引号内的任何字符都会原样输出,不能进行转义,单引号内不能单独出现一个单引号,但可成对出现,作为字符串拼接使用。双引号内可以有变量,可以出现转义字符。</p>
<h2>2.2. 变量使用</h2>
<p>只需要在变量前加<code><article>
<header>
<h1>shell编程</h1>
<time datetime="2023-01-24T00:00:00.000Z">2023年1月24日</time>
<div class="tags">
<span class="tag">linux</span>
</div>
</header>
<section class="content">
<p>本文主要介绍shell编程的基本语法以及实际应用中的常见命令。</p>
<h1>1. 注释</h1>
<h2>1.1. 单行注释</h2>
<pre><code class="language-shell"># 这是单行注释
</code></pre>
<h2>1.2. 多行注释</h2>
<pre><code class="language-shell">:<<EOF
多行注释内容
多行注释内容
多行注释内容
EOF
</code></pre>
<p>多行注释<code>EOF</code>也可替换成<code>!</code>或<code>'</code></p>
<pre><code class="language-shell">:<<'
多行注释内容
多行注释内容
多行注释内容
'
:<<!
多行注释内容
多行注释内容
多行注释内容
!
</code></pre>
<h1>2. 变量</h1>
<h2>2.1. 变量定义</h2>
<p>使用<code>VARIABLENAME=VALUE</code>的形式,VALUE如果是字符串的话,可以使用单引号、双引号或者不加引号。单引号内的任何字符都会原样输出,不能进行转义,单引号内不能单独出现一个单引号,但可成对出现,作为字符串拼接使用。双引号内可以有变量,可以出现转义字符。</p>
<h2>2.2. 变量使用</h2>
<p>只需要在变量前加<code>$</code>符号,变量加<code>{}</code>是可选的,方便解释器识别边界。将变量加上<code>{}</code>是一个好习惯,不容易出错。</p>
<pre><code class="language-shell">your_age=25
your_name="shinerio"
your_name=shinerio
your_name='shinerio'
echo $your_age # 输出25
echo $your_name # 输出shinerio
echo "${your_name}hello" <span class="tag">#这里</span>{}必须添加,否则解释器认为是${your_namehello}
str='hello'' # 非法
str='hello'__'world' # 成对出现的单引号做字符拼接
echo $str <span class="tag">#输出hello__world</span>
str1='helloworld${your_age}\nnew line'
str2="helloworld${your_age}\nnew line"
echo $str1 # 输出helloworld${your_age}\nnew line
echo $str2 # 输出helloworld25\nnew line
echo -e $str2 # -e开启转义 \n表示换行 echo默认换行,通过\c强制不换行
<span class="tag">#helloworld25</span>
<span class="tag">#new</span> line
</code></pre>
<h2>2.3. 只读变量</h2>
<p>使用<code>readonly VARIABLENAME</code>设置变量只读,只读变量的值不能更改</p>
<pre><code class="language-shell">readonly name='jack'
name='kelly'
zsh: read-only variable: name
</code></pre>
<h2>2.4. 删除变量</h2>
<p>使用<code>unset VARIABLENAME</code>删除变量。</p>
<h1>3. 字符串操作</h1>
<h2>3.1. 字符串拼接</h2>
<pre><code class="language-shell">str1="hello"${your_name}"world"
str2="hello${your_name}world"
str3='hello'${your_name}'world'
</code></pre>
<h2>3.2. 字符串长度</h2>
<pre><code class="language-shell">str='hello'
echo ${<span class="tag">#str</span>}
5
</code></pre>
<h2>3.3. 字符串截取</h2>
<p><code>${string:start:length}</code>,索引从0开始,从start(包含)开始截取共计length长度的字符。</p>
<pre><code class="language-shell">str='helloworld'
echo ${str:0:5}
hello
</code></pre>
<h2>3.4. 字符串运算符</h2>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>=</code></td>
<td>检测两个字符串是否相等,相等返回true</td>
<td><code>[ 'hello' = 'hello' ]</code></td>
</tr>
<tr>
<td><code>!=</code></td>
<td>检测两个字符串是否相等,不相等返回true</td>
<td><code>[ 'hello' != 'ello' ]</code></td>
</tr>
<tr>
<td><code>-z</code></td>
<td>检测字符串长度是否为0,为0返回true</td>
<td><code>[ -z '' ]</code></td>
</tr>
<tr>
<td><code>-n </code></td>
<td>检测字符串长度是否不为0,不为0返回true</td>
<td><code>[ -n 'hello' ]</code></td>
</tr>
<tr>
<td><code>$</code></td>
<td>检测字符串是否为空,不为空返回true</td>
<td><code>[ <p>本文主要介绍shell编程的基本语法以及实际应用中的常见命令。</p>
<h1>1. 注释</h1>
<h2>1.1. 单行注释</h2>
<pre><code class="language-shell"># 这是单行注释
</code></pre>
<h2>1.2. 多行注释</h2>
<pre><code class="language-shell">:&lt;&lt;EOF
多行注释内容
多行注释内容
多行注释内容
EOF
</code></pre>
<p>多行注释<code>EOF</code>也可替换成<code>!</code>或<code>&#39;</code></p>
<pre><code class="language-shell">:&lt;&lt;&#39;
多行注释内容
多行注释内容
多行注释内容
&#39;
:&lt;&lt;!
多行注释内容
多行注释内容
多行注释内容
!
</code></pre>
<h1>2. 变量</h1>
<h2>2.1. 变量定义</h2>
<p>使用<code>VARIABLENAME=VALUE</code>的形式,VALUE如果是字符串的话,可以使用单引号、双引号或者不加引号。单引号内的任何字符都会原样输出,不能进行转义,单引号内不能单独出现一个单引号,但可成对出现,作为字符串拼接使用。双引号内可以有变量,可以出现转义字符。</p>
<h2>2.2. 变量使用</h2>
<p>只需要在变量前加<code>$</code>符号,变量加<code>{}</code>是可选的,方便解释器识别边界。将变量加上<code>{}</code>是一个好习惯,不容易出错。</p>
<pre><code class="language-shell">your_age=25
your_name=&quot;shinerio&quot;
your_name=shinerio
your_name=&#39;shinerio&#39;
echo $your_age # 输出25
echo $your_name # 输出shinerio
echo &quot;${your_name}hello&quot; &lt;span class=&quot;tag&quot;&gt;#这里&lt;/span&gt;{}必须添加,否则解释器认为是${your_namehello}
str=&#39;hello&#39;&#39; # 非法
str=&#39;hello&#39;__&#39;world&#39; # 成对出现的单引号做字符拼接
echo $str &lt;span class=&quot;tag&quot;&gt;#输出hello__world&lt;/span&gt;
str1=&#39;helloworld${your_age}\nnew line&#39;
str2=&quot;helloworld${your_age}\nnew line&quot;
echo $str1 # 输出helloworld${your_age}\nnew line
echo $str2 # 输出helloworld25\nnew line
echo -e $str2 # -e开启转义 \n表示换行 echo默认换行,通过\c强制不换行
&lt;span class=&quot;tag&quot;&gt;#helloworld25&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;#new&lt;/span&gt; line
</code></pre>
<h2>2.3. 只读变量</h2>
<p>使用<code>readonly VARIABLENAME</code>设置变量只读,只读变量的值不能更改</p>
<pre><code class="language-shell">readonly name=&#39;jack&#39;
name=&#39;kelly&#39;
zsh: read-only variable: name
</code></pre>
<h2>2.4. 删除变量</h2>
<p>使用<code>unset VARIABLENAME</code>删除变量。</p>
<h1>3. 字符串操作</h1>
<h2>3.1. 字符串拼接</h2>
<pre><code class="language-shell">str1=&quot;hello&quot;${your_name}&quot;world&quot;
str2=&quot;hello${your_name}world&quot;
str3=&#39;hello&#39;${your_name}&#39;world&#39;
</code></pre>
<h2>3.2. 字符串长度</h2>
<pre><code class="language-shell">str=&#39;hello&#39;
echo ${&lt;span class=&quot;tag&quot;&gt;#str&lt;/span&gt;}
5
</code></pre>
<h2>3.3. 字符串截取</h2>
<p><code>${string:start:length}</code>,索引从0开始,从start(包含)开始截取共计length长度的字符。</p>
<pre><code class="language-shell">str=&#39;helloworld&#39;
echo ${str:0:5}
hello
</code></pre>
<h2>3.4. 字符串运算符</h2>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>=</code></td>
<td>检测两个字符串是否相等,相等返回true</td>
<td><code>[ &#39;hello&#39; = &#39;hello&#39; ]</code></td>
</tr>
<tr>
<td><code>!=</code></td>
<td>检测两个字符串是否相等,不相等返回true</td>
<td><code>[ &#39;hello&#39; != &#39;ello&#39; ]</code></td>
</tr>
<tr>
<td><code>-z</code></td>
<td>检测字符串长度是否为0,为0返回true</td>
<td><code>[ -z &#39;&#39; ]</code></td>
</tr>
<tr>
<td><code>-n </code></td>
<td>检测字符串长度是否不为0,不为0返回true</td>
<td><code>[ -n &#39;hello&#39; ]</code></td>
</tr>
<tr>
<td><code>$</code></td>
<td>检测字符串是否为空,不为空返回true</td>
<td><code>[ $&#39;hello&#39; ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ &#39;hello&#39; = &#39;hello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ &#39;hello&#39; != &#39;ello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ -z &#39;&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ -n &#39;hello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ $&#39;hello&#39; ];then echo &#39;hello&#39;;fi
str=&#39;hello&#39;
if [ $str ];then echo &#39;hello&#39;;fi
# hello
</code></pre>
<p>注意字符串的等值判断是一个等号<code>&quot;=&quot;</code>,与下文要讲的逻辑运算符使用两个等号<code>&quot;==&quot;</code>做等值判断不一样。</p>
<h1>4. 文件测试运算符</h1>
<table>
<thead>
<tr>
<th>操作符</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>-b file</code></td>
<td>检测文件是否是块设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-c file</code></td>
<td>检测文件是否是字符设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-d file</code></td>
<td>检测文件是否是目录,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-f file</code></td>
<td>检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-g file</code></td>
<td>检测文件是否设置了<code>SGID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-k file</code></td>
<td>检测文件是否设置了粘着位(Sticky Bit),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-p file</code></td>
<td>检测文件是否是有名管道,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-u file</code></td>
<td>检测文件是否设置了<code>SUID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-r file</code></td>
<td>检测文件是否可读,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-w file</code></td>
<td>检测文件是否可写,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-x file</code></td>
<td>检测文件是否可执行,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-s file</code></td>
<td>检测文件是否为空(文件大小是否大于0),不为空返回true。</td>
</tr>
<tr>
<td><code>-e file</code></td>
<td>检测文件(包括目录)是否存在,如果是,则返回true。</td>
</tr>
</tbody></table>
<pre><code class="language-shell">if &lt;a href=&quot;f-home.html&quot; class=&quot;internal-link&quot;&gt; -f &#39;/home&#39; &lt;/a&gt;;then echo &#39;directory&#39;;else echo &#39;file&#39;;fi
# file
if &lt;a href=&quot;d-home.html&quot; class=&quot;internal-link&quot;&gt; -d &#39;/home&#39; &lt;/a&gt;;then echo &#39;directory&#39;;else echo &#39;file&#39;;fi
# directory
if &lt;a href=&quot;e-tmpfake-file.html&quot; class=&quot;internal-link&quot;&gt; -e &#39;/tmp/fake_file&#39; &lt;/a&gt;;then echo &#39;exist&#39;;else echo &#39;not exist&#39;;fi
# not exist
</code></pre>
<h1>5. 数组</h1>
<p><code>shell</code>只支持一维数组,用括号表示,元素通过空格分隔,形如<code>数组名=(值1 值2 ... 值n)</code>。<code>shell</code>数组下标从<code>1</code>开始。</p>
<ul>
<li><code>${数组名[下标]}</code>,读取指索引位置数组元素</li>
<li>使用<code>@</code>或<code>*</code>代替下标,获取数组中所有元素。</li>
<li>使用<code>{&lt;span class=&quot;tag&quot;&gt;#数组名&lt;/span&gt;[@]}</code>或<code>{&lt;span class=&quot;tag&quot;&gt;#数组名&lt;/span&gt;[*]}</code>获取数组元素个数。</li>
</ul>
<pre><code class="language-shell">arr=(value1 value2 value3 value4)
echo ${arr[3]}
# value3
echo ${arr[*]}
# value1 value2 value3 value4
echo ${arr[@]}
# value1 value2 value3 value4
arr[3]=&#39;new_value3&#39;
echo $arr[3]
# new_value3
echo ${&lt;span class=&quot;tag&quot;&gt;#arr&lt;/span&gt;[@]}
# 4
echo &quot;arr[1]的长度为:${&lt;span class=&quot;tag&quot;&gt;#arr&lt;/span&gt;[1]}&quot;
# arr[1]的长度为:6
</code></pre>
<h1>6. 运算符</h1>
<h2>6.1. 赋值运算符</h2>
<pre><code class="language-shell">a=10
b=$a
</code></pre>
<h2>6.2. 算术运算符</h2>
<p>算数运算符支持<code>+,-,*,/,%</code></p>
<h3>6.2.1. expr表示法</h3>
<pre><code class="language-shell">echo `expr 10 + 20`
# 30
echo $(expr 20 / 2)
# 10
echo $(expr 10 \* 20) # 使用expr进行乘法运算时必须使用\进行转义
# 200
</code></pre>
<blockquote>
<p>使用expr表示方法时,表达式和运算符之间必须有空格。</p>
</blockquote>
<h3>6.2.2. <code>$[]</code></h3>
<pre><code class="language-shell">echo $[10%3]
# 1
</code></pre>
<h3>6.2.3. <code>$(())</code></h3>
<pre><code class="language-shell">echo $((10*20))
# 200
</code></pre>
<h2>6.3. 关系运算符</h2>
<p>最常见的关系运算符是:<code>==,!=,&lt;,&gt;,&gt;=,&lt;=</code></p>
<pre><code class="language-shell">echo $[10==10]
# 1
flag=$[20==10]
echo $flag
# 1
echo $[10&gt;=10]
# 1
</code></pre>
<p>如下关系运算符只能使用在条件表达式<code>if、while</code>下,类似<code>flag=[ $a -eq $b ]</code>的直接赋值语句是非法的。关系运算符的条件表达式要放在<strong>一对</strong>方括号中,并且中间需要有空格。也可以使用<code>(())</code>替代<code>[]</code>,此时<code>-eq,-lt,-le</code>之类的需要使用<code>==,&lt;,&lt;=</code>等替换。</p>
<blockquote>
<p><code>[]</code>搭配<code>-eq -ne</code>等使用,<code>(())</code>搭配<code>|| &amp;&amp;</code>等使用。</p>
</blockquote>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>-eq</code></td>
<td>检测两个数是否相等,相等返回true。</td>
<td><code>[ $a -eq $b ]</code></td>
</tr>
<tr>
<td><code>-ne</code></td>
<td>检测两个数是否不相等,不相等返回 true。</td>
<td><code>[ $a -ne $b ]</code></td>
</tr>
<tr>
<td><code>-gt</code></td>
<td>检测左边的数是否大于右边的,如果是,则返回 true。</td>
<td><code>[ $a -gt $b ]</code></td>
</tr>
<tr>
<td><code>-lt</code></td>
<td>检测左边的数是否小于右边的,如果是,则返回 true。</td>
<td><code>[ $a -lt $b ]</code></td>
</tr>
<tr>
<td><code>-ge</code></td>
<td>检测左边的数是否大于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -ge $b ]</code></td>
</tr>
<tr>
<td><code>-le</code></td>
<td>检测左边的数是否小于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -le $b ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ 1 -eq 1 ];then echo &#39;hello&#39;;fi;
# hello
if ((10&gt;=10));then echo &#39;hello&#39;;fi;
# hello
</code></pre>
<h2>6.4. 布尔、逻辑运算符</h2>
<p>布尔、逻辑运算的条件表达式也要放在一对方括号中<code>[]</code>。</p>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>!</code></td>
<td>非运算,表达式为true则返回false,否则返回true。</td>
<td><code>[ ! 10 -eq 0 ]</code></td>
</tr>
<tr>
<td><code>-o</code></td>
<td>或运算,有一个表达式为true则返回true。</td>
<td><code>[ 10 -lt 20 -o 10 -gt 100 ]</code></td>
</tr>
<tr>
<td><code>-a</code></td>
<td>与运算,两个表达式都为true才返回true。</td>
<td><code>[ 10 -lt 20 -a 10 -gt 100 ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ ! 10 -eq 0 ];then echo &#39;hello&#39;;fi
# hello
if [ 10 -ge 10 -a 10 -ge 10 ];then echo &#39;hello&#39;;fi
# hello
if [ 10 -ge 20 -o 10 -ge 0 ];then echo &#39;hello&#39;;fi
# hello
</code></pre>
<p> <code>-o</code>也可以使用<code>||</code>替代,<code>-a</code>也可以使用<code>&amp;&amp;</code>替代,此时需要使用<code>(())</code>或<code>[[]]</code>替代<code>[]</code>。</p>
<pre><code class="language-shell">if &lt;a href=&quot;1010-55.html&quot; class=&quot;internal-link&quot;&gt; 10==10 &amp;&amp; 5==5 &lt;/a&gt;;then echo &#39;hello&#39;;fi
# hello
if ((10==10 &amp;&amp; 5==5));then echo &#39;hello&#39;;fi
# hello
</code></pre>
<h1>7. 传递参数</h1>
<p>在执行 <code>Shell</code>脚本时,向脚本传递参数,脚本内获取参数的格式为:<code>$n</code>。<code>n</code>代表一个数字,<code>1</code>为执行脚本的第一个参数,<code>2</code>为执行脚本的第二个参数,<code>$0</code>为执行的文件名。在为<code>shell</code>脚本传递的参数中如果包含空格,应该使用单引号或者双引号将该参数括起来,以便于脚本将这个参数作为整体来接收。另外,还有几个特殊字符用来处理参数:</p>
<table>
<thead>
<tr>
<th>参数处理</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>$#</code></td>
<td>传递到脚本的参数个数</td>
</tr>
<tr>
<td><code>$*</code></td>
<td>以一个单字符串显示所有向脚本传递的参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$$</code></td>
<td>脚本运行的当前进程ID号</td>
</tr>
<tr>
<td><code>$!</code></td>
<td>后台运行的最后一个进程的ID号</td>
</tr>
<tr>
<td><code>$@</code></td>
<td>与<code>$*</code>相同,但是使用时加引号,并在引号中返回每个参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$-</code></td>
<td>显示Shell使用的当前选项,与set功能相同。</td>
</tr>
<tr>
<td><code>$?</code></td>
<td>显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。</td>
</tr>
</tbody></table>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-bash">set -e
echo &quot;执行的文件名:$0&quot;
echo &quot;参数个数为$#&quot;
echo &quot;第一个参数为:$1&quot;
echo &quot;第二个参数为:$2&quot;
echo &quot;所有参数为:$@&quot;
echo &quot;进程ID号为:$$&quot;
echo &quot;当前shell选项为$-&quot;
echo &quot;上一个命令退出的状态为$?&quot;
</code></pre>
<p>执行结果如下:</p>
<pre><code class="language-shell">$ sh test.sh param1 &quot;param2 with space&quot;
执行的文件名:test.sh
参数个数为2
第一个参数为:param1
第二个参数为:param2 with space
所有参数为:param1 param2 with space
进程ID号为:3700
当前shell选项为ehB
上一个命令退出的状态为0
</code></pre>
<h1>8. 函数</h1>
<p>函数定义通过<code>function_name(){}</code>的形式定义,函数返回值可以显示用return返回,如果不加,将以最后一条命令的运行结果作为返回值,函数返回值只能是数字。函数也可以传递参数,但是函数定义的()中不需要申明。</p>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-shell">sayhello(){
echo &quot;hello&quot;
}
# 注意函数调用只需要函数名,不需要加()
sayhello
sayhellowithparam(){
echo &quot;hello, $1 $2 $3&quot;
return 1
}
sayhellowithparam zhangsan lisi wangwu
echo $?
</code></pre>
<p>输出如下:</p>
<blockquote>
<p>hello<br>hello, zhangsan lisi wangwu<br>1</p>
</blockquote>
<h1>9. 命令替换</h1>
<p>命令替换可以将一个命令的输出作为另外一个命令的参数。</p>
<pre><code class="language-shell"># command1 `command2`
cd `pwd` # 该命令将pwd命令列出的目录作为cd命令的参数,结果仍然是停留在当前目录下
cd `echo $HOME` # 将echo的输出作为cd的参数,即打开用户根目录
</code></pre>
<h1>10. let命令</h1>
<p>let 命令是 BASH 中用于计算的工具,用于执行一个或多个表达式,变量计算中不需要加上 $ 来表示变量。如果表达式中包含了空格或其他特殊字符,则必须引起来。</p>
<ul>
<li>自加操作:<code>let no++</code></li>
<li>自减操作:<code>let no--</code></li>
<li>简写形式 <code>let no+=10</code>,<code>let no-=20</code>,分别等同于<code>let no=no+10</code>,<code>let no=no-20</code></li>
</ul>
<h1>11. 流程控制</h1>
<h2>11.1. if</h2>
<pre><code class="language-shell">if ((10&lt;2));then
echo &quot;10小于2&quot;
elif ((10&gt;20));then
echo &quot;a大于10&quot;
else
echo &quot;10大于2且小于10&quot;
fi
</code></pre>
<h2>11.2. case</h2>
<p><code>case</code>每一种情况以右括号结尾,执行到<code>;;</code>结束</p>
<pre><code class="language-shell">case 10 in
0|1)
echo &quot;a为0或1&quot;
;;
11|12)
echo &quot;a为11或12&quot;
;;
*)
# *用来匹配所有情况
echo &quot;a为10&quot;
;;
esac
</code></pre>
<h2>11.3. while</h2>
<pre><code class="language-shell">count=0
while(($count&lt;5))
do
echo $count
let count++
done
</code></pre>
<h2>11.4. util</h2>
<pre><code class="language-shell">count=0
until(($count&gt;=5))
do
echo $count
let count++
done
</code></pre>
<h2>11.5. for</h2>
<pre><code class="language-shell"># for写法1
for ((count=0;$count&lt;5;count=$count+1))
do
echo $count
done
# for写法2
arr=(0 1 2 3 4)
for count in ${arr[*]}
do
echo $int
done
# for写法3
for int in 0 1 2 3 4
do
echo $int
done
</code></pre>
<h2>11.6. break和continue</h2>
<p>用法与一般编程语言类似,break跳出循环,continue跳出当前循环</p>
<pre><code class="language-shell">for ((count=0;$count&gt;=0;count=$count+1))
do
if (($count&gt;=5));then
break;
fi
echo $count
done
</code></pre>
<h1>12. 输入输出重定向</h1>
<h2>12.1. 输出重定向</h2>
<p><code>command &gt; file</code>将命令输出结果保存的file文件中。<code>&gt;</code>从文件头开始写,会覆盖旧内容,<code>&gt;&gt;</code>将内容追加到文件末尾</p>
<pre><code class="language-shell"># 将who命令的输出保存的users文件中,可以通过cat users查看
who &gt; users
# 将字符串hello world保存到text.txt文件中
echo &quot;hello world&quot; &gt; text.txt
</code></pre>
<h2>12.2. 输入重定向</h2>
<p><code>command &lt; file</code>从file文件获取输入</p>
<pre><code class="language-shell">wc -l /etc/passwd
# 123 /etc/passwd
wc -l &lt; users
# 123
# 第一个例子,会输出文件名;第二个不会,因为它仅仅知道从标准输入读取内容
# command &lt; infile &gt; outfile, 同时替换输入和输出,执行command,从文件infile读取内容,然后将输出写入到outfile中。
wc -l &lt; /etc/passwd &gt; result
cat result
# 123
</code></pre>
<h2>12.3. 文件描述符</h2>
<p>一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件</p>
<ul>
<li>标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。</li>
<li>标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。</li>
<li>标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。</li>
</ul>
<pre><code class="language-shell"># 将标准错误输出重定向到error_trace
cat /tmp/fake_file 2&gt;error_trace
cat error_trace
# cat: /tmp/fake_fule: No such file or directory
# 将标准输出和标准错误输出都重定向到result
cat /tmp/fake_file &amp;&gt;result
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准错误重定向到标准输出
ls /tmp/fake_file &gt; result 2&gt;&amp;1
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准输入重定向到result,将标准错误输出重定向到error_trace
cat /tmp/fake_file 1&gt;result 2&gt;error_trace
</code></pre>
<h2>12.4. Here Document</h2>
<p>将两个<code>EOF</code>之间的内容(document) 作为输入传递给<code>command</code></p>
<pre><code class="language-bash"># command &lt;&lt; EOF
# document
# EOF
cat &lt;&lt; EOF
hello
shinerio
learn shell
EOF
</code></pre>
<blockquote>
<p>结尾的<code>EOF</code>一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和<code>tab</code>缩进。开始的<code>EOF</code>前后的空格会被忽略掉。</p>
</blockquote>
<h2>12.5. /dev/null</h2>
<p>如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null。<code>command &gt; /dev/null</code></p>
<pre><code class="language-shell">cat users &gt; /dev/null
cat users &gt; /dev/null 2&gt;&amp;1
</code></pre>
<h1>13. set命令</h1>
<p>set指令能设置所使用shell的执行方式,可依照不同的需求来做设置。以下只列出常用的选项参数:</p>
<ul>
<li>-e 若指令传回值不等于0,则立即退出shell。</li>
<li>-f 取消使用通配符。</li>
<li>-n 只读取指令,而不实际执行。</li>
<li>-x 执行指令后,会先显示该指令及所下的参数。</li>
</ul>
#39;hello' ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ 'hello' = 'hello' ];then echo 'hello';fi
# hello
if [ 'hello' != 'ello' ];then echo 'hello';fi
# hello
if [ -z '' ];then echo 'hello';fi
# hello
if [ -n 'hello' ];then echo 'hello';fi
# hello
if [ <p>本文主要介绍shell编程的基本语法以及实际应用中的常见命令。</p>
<h1>1. 注释</h1>
<h2>1.1. 单行注释</h2>
<pre><code class="language-shell"># 这是单行注释
</code></pre>
<h2>1.2. 多行注释</h2>
<pre><code class="language-shell">:&lt;&lt;EOF
多行注释内容
多行注释内容
多行注释内容
EOF
</code></pre>
<p>多行注释<code>EOF</code>也可替换成<code>!</code>或<code>&#39;</code></p>
<pre><code class="language-shell">:&lt;&lt;&#39;
多行注释内容
多行注释内容
多行注释内容
&#39;
:&lt;&lt;!
多行注释内容
多行注释内容
多行注释内容
!
</code></pre>
<h1>2. 变量</h1>
<h2>2.1. 变量定义</h2>
<p>使用<code>VARIABLENAME=VALUE</code>的形式,VALUE如果是字符串的话,可以使用单引号、双引号或者不加引号。单引号内的任何字符都会原样输出,不能进行转义,单引号内不能单独出现一个单引号,但可成对出现,作为字符串拼接使用。双引号内可以有变量,可以出现转义字符。</p>
<h2>2.2. 变量使用</h2>
<p>只需要在变量前加<code>$</code>符号,变量加<code>{}</code>是可选的,方便解释器识别边界。将变量加上<code>{}</code>是一个好习惯,不容易出错。</p>
<pre><code class="language-shell">your_age=25
your_name=&quot;shinerio&quot;
your_name=shinerio
your_name=&#39;shinerio&#39;
echo $your_age # 输出25
echo $your_name # 输出shinerio
echo &quot;${your_name}hello&quot; &lt;span class=&quot;tag&quot;&gt;#这里&lt;/span&gt;{}必须添加,否则解释器认为是${your_namehello}
str=&#39;hello&#39;&#39; # 非法
str=&#39;hello&#39;__&#39;world&#39; # 成对出现的单引号做字符拼接
echo $str &lt;span class=&quot;tag&quot;&gt;#输出hello__world&lt;/span&gt;
str1=&#39;helloworld${your_age}\nnew line&#39;
str2=&quot;helloworld${your_age}\nnew line&quot;
echo $str1 # 输出helloworld${your_age}\nnew line
echo $str2 # 输出helloworld25\nnew line
echo -e $str2 # -e开启转义 \n表示换行 echo默认换行,通过\c强制不换行
&lt;span class=&quot;tag&quot;&gt;#helloworld25&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;#new&lt;/span&gt; line
</code></pre>
<h2>2.3. 只读变量</h2>
<p>使用<code>readonly VARIABLENAME</code>设置变量只读,只读变量的值不能更改</p>
<pre><code class="language-shell">readonly name=&#39;jack&#39;
name=&#39;kelly&#39;
zsh: read-only variable: name
</code></pre>
<h2>2.4. 删除变量</h2>
<p>使用<code>unset VARIABLENAME</code>删除变量。</p>
<h1>3. 字符串操作</h1>
<h2>3.1. 字符串拼接</h2>
<pre><code class="language-shell">str1=&quot;hello&quot;${your_name}&quot;world&quot;
str2=&quot;hello${your_name}world&quot;
str3=&#39;hello&#39;${your_name}&#39;world&#39;
</code></pre>
<h2>3.2. 字符串长度</h2>
<pre><code class="language-shell">str=&#39;hello&#39;
echo ${&lt;span class=&quot;tag&quot;&gt;#str&lt;/span&gt;}
5
</code></pre>
<h2>3.3. 字符串截取</h2>
<p><code>${string:start:length}</code>,索引从0开始,从start(包含)开始截取共计length长度的字符。</p>
<pre><code class="language-shell">str=&#39;helloworld&#39;
echo ${str:0:5}
hello
</code></pre>
<h2>3.4. 字符串运算符</h2>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>=</code></td>
<td>检测两个字符串是否相等,相等返回true</td>
<td><code>[ &#39;hello&#39; = &#39;hello&#39; ]</code></td>
</tr>
<tr>
<td><code>!=</code></td>
<td>检测两个字符串是否相等,不相等返回true</td>
<td><code>[ &#39;hello&#39; != &#39;ello&#39; ]</code></td>
</tr>
<tr>
<td><code>-z</code></td>
<td>检测字符串长度是否为0,为0返回true</td>
<td><code>[ -z &#39;&#39; ]</code></td>
</tr>
<tr>
<td><code>-n </code></td>
<td>检测字符串长度是否不为0,不为0返回true</td>
<td><code>[ -n &#39;hello&#39; ]</code></td>
</tr>
<tr>
<td><code>$</code></td>
<td>检测字符串是否为空,不为空返回true</td>
<td><code>[ $&#39;hello&#39; ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ &#39;hello&#39; = &#39;hello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ &#39;hello&#39; != &#39;ello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ -z &#39;&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ -n &#39;hello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ $&#39;hello&#39; ];then echo &#39;hello&#39;;fi
str=&#39;hello&#39;
if [ $str ];then echo &#39;hello&#39;;fi
# hello
</code></pre>
<p>注意字符串的等值判断是一个等号<code>&quot;=&quot;</code>,与下文要讲的逻辑运算符使用两个等号<code>&quot;==&quot;</code>做等值判断不一样。</p>
<h1>4. 文件测试运算符</h1>
<table>
<thead>
<tr>
<th>操作符</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>-b file</code></td>
<td>检测文件是否是块设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-c file</code></td>
<td>检测文件是否是字符设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-d file</code></td>
<td>检测文件是否是目录,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-f file</code></td>
<td>检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-g file</code></td>
<td>检测文件是否设置了<code>SGID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-k file</code></td>
<td>检测文件是否设置了粘着位(Sticky Bit),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-p file</code></td>
<td>检测文件是否是有名管道,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-u file</code></td>
<td>检测文件是否设置了<code>SUID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-r file</code></td>
<td>检测文件是否可读,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-w file</code></td>
<td>检测文件是否可写,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-x file</code></td>
<td>检测文件是否可执行,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-s file</code></td>
<td>检测文件是否为空(文件大小是否大于0),不为空返回true。</td>
</tr>
<tr>
<td><code>-e file</code></td>
<td>检测文件(包括目录)是否存在,如果是,则返回true。</td>
</tr>
</tbody></table>
<pre><code class="language-shell">if &lt;a href=&quot;f-home.html&quot; class=&quot;internal-link&quot;&gt; -f &#39;/home&#39; &lt;/a&gt;;then echo &#39;directory&#39;;else echo &#39;file&#39;;fi
# file
if &lt;a href=&quot;d-home.html&quot; class=&quot;internal-link&quot;&gt; -d &#39;/home&#39; &lt;/a&gt;;then echo &#39;directory&#39;;else echo &#39;file&#39;;fi
# directory
if &lt;a href=&quot;e-tmpfake-file.html&quot; class=&quot;internal-link&quot;&gt; -e &#39;/tmp/fake_file&#39; &lt;/a&gt;;then echo &#39;exist&#39;;else echo &#39;not exist&#39;;fi
# not exist
</code></pre>
<h1>5. 数组</h1>
<p><code>shell</code>只支持一维数组,用括号表示,元素通过空格分隔,形如<code>数组名=(值1 值2 ... 值n)</code>。<code>shell</code>数组下标从<code>1</code>开始。</p>
<ul>
<li><code>${数组名[下标]}</code>,读取指索引位置数组元素</li>
<li>使用<code>@</code>或<code>*</code>代替下标,获取数组中所有元素。</li>
<li>使用<code>{&lt;span class=&quot;tag&quot;&gt;#数组名&lt;/span&gt;[@]}</code>或<code>{&lt;span class=&quot;tag&quot;&gt;#数组名&lt;/span&gt;[*]}</code>获取数组元素个数。</li>
</ul>
<pre><code class="language-shell">arr=(value1 value2 value3 value4)
echo ${arr[3]}
# value3
echo ${arr[*]}
# value1 value2 value3 value4
echo ${arr[@]}
# value1 value2 value3 value4
arr[3]=&#39;new_value3&#39;
echo $arr[3]
# new_value3
echo ${&lt;span class=&quot;tag&quot;&gt;#arr&lt;/span&gt;[@]}
# 4
echo &quot;arr[1]的长度为:${&lt;span class=&quot;tag&quot;&gt;#arr&lt;/span&gt;[1]}&quot;
# arr[1]的长度为:6
</code></pre>
<h1>6. 运算符</h1>
<h2>6.1. 赋值运算符</h2>
<pre><code class="language-shell">a=10
b=$a
</code></pre>
<h2>6.2. 算术运算符</h2>
<p>算数运算符支持<code>+,-,*,/,%</code></p>
<h3>6.2.1. expr表示法</h3>
<pre><code class="language-shell">echo `expr 10 + 20`
# 30
echo $(expr 20 / 2)
# 10
echo $(expr 10 \* 20) # 使用expr进行乘法运算时必须使用\进行转义
# 200
</code></pre>
<blockquote>
<p>使用expr表示方法时,表达式和运算符之间必须有空格。</p>
</blockquote>
<h3>6.2.2. <code>$[]</code></h3>
<pre><code class="language-shell">echo $[10%3]
# 1
</code></pre>
<h3>6.2.3. <code>$(())</code></h3>
<pre><code class="language-shell">echo $((10*20))
# 200
</code></pre>
<h2>6.3. 关系运算符</h2>
<p>最常见的关系运算符是:<code>==,!=,&lt;,&gt;,&gt;=,&lt;=</code></p>
<pre><code class="language-shell">echo $[10==10]
# 1
flag=$[20==10]
echo $flag
# 1
echo $[10&gt;=10]
# 1
</code></pre>
<p>如下关系运算符只能使用在条件表达式<code>if、while</code>下,类似<code>flag=[ $a -eq $b ]</code>的直接赋值语句是非法的。关系运算符的条件表达式要放在<strong>一对</strong>方括号中,并且中间需要有空格。也可以使用<code>(())</code>替代<code>[]</code>,此时<code>-eq,-lt,-le</code>之类的需要使用<code>==,&lt;,&lt;=</code>等替换。</p>
<blockquote>
<p><code>[]</code>搭配<code>-eq -ne</code>等使用,<code>(())</code>搭配<code>|| &amp;&amp;</code>等使用。</p>
</blockquote>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>-eq</code></td>
<td>检测两个数是否相等,相等返回true。</td>
<td><code>[ $a -eq $b ]</code></td>
</tr>
<tr>
<td><code>-ne</code></td>
<td>检测两个数是否不相等,不相等返回 true。</td>
<td><code>[ $a -ne $b ]</code></td>
</tr>
<tr>
<td><code>-gt</code></td>
<td>检测左边的数是否大于右边的,如果是,则返回 true。</td>
<td><code>[ $a -gt $b ]</code></td>
</tr>
<tr>
<td><code>-lt</code></td>
<td>检测左边的数是否小于右边的,如果是,则返回 true。</td>
<td><code>[ $a -lt $b ]</code></td>
</tr>
<tr>
<td><code>-ge</code></td>
<td>检测左边的数是否大于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -ge $b ]</code></td>
</tr>
<tr>
<td><code>-le</code></td>
<td>检测左边的数是否小于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -le $b ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ 1 -eq 1 ];then echo &#39;hello&#39;;fi;
# hello
if ((10&gt;=10));then echo &#39;hello&#39;;fi;
# hello
</code></pre>
<h2>6.4. 布尔、逻辑运算符</h2>
<p>布尔、逻辑运算的条件表达式也要放在一对方括号中<code>[]</code>。</p>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>!</code></td>
<td>非运算,表达式为true则返回false,否则返回true。</td>
<td><code>[ ! 10 -eq 0 ]</code></td>
</tr>
<tr>
<td><code>-o</code></td>
<td>或运算,有一个表达式为true则返回true。</td>
<td><code>[ 10 -lt 20 -o 10 -gt 100 ]</code></td>
</tr>
<tr>
<td><code>-a</code></td>
<td>与运算,两个表达式都为true才返回true。</td>
<td><code>[ 10 -lt 20 -a 10 -gt 100 ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ ! 10 -eq 0 ];then echo &#39;hello&#39;;fi
# hello
if [ 10 -ge 10 -a 10 -ge 10 ];then echo &#39;hello&#39;;fi
# hello
if [ 10 -ge 20 -o 10 -ge 0 ];then echo &#39;hello&#39;;fi
# hello
</code></pre>
<p> <code>-o</code>也可以使用<code>||</code>替代,<code>-a</code>也可以使用<code>&amp;&amp;</code>替代,此时需要使用<code>(())</code>或<code>[[]]</code>替代<code>[]</code>。</p>
<pre><code class="language-shell">if &lt;a href=&quot;1010-55.html&quot; class=&quot;internal-link&quot;&gt; 10==10 &amp;&amp; 5==5 &lt;/a&gt;;then echo &#39;hello&#39;;fi
# hello
if ((10==10 &amp;&amp; 5==5));then echo &#39;hello&#39;;fi
# hello
</code></pre>
<h1>7. 传递参数</h1>
<p>在执行 <code>Shell</code>脚本时,向脚本传递参数,脚本内获取参数的格式为:<code>$n</code>。<code>n</code>代表一个数字,<code>1</code>为执行脚本的第一个参数,<code>2</code>为执行脚本的第二个参数,<code>$0</code>为执行的文件名。在为<code>shell</code>脚本传递的参数中如果包含空格,应该使用单引号或者双引号将该参数括起来,以便于脚本将这个参数作为整体来接收。另外,还有几个特殊字符用来处理参数:</p>
<table>
<thead>
<tr>
<th>参数处理</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>$#</code></td>
<td>传递到脚本的参数个数</td>
</tr>
<tr>
<td><code>$*</code></td>
<td>以一个单字符串显示所有向脚本传递的参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$$</code></td>
<td>脚本运行的当前进程ID号</td>
</tr>
<tr>
<td><code>$!</code></td>
<td>后台运行的最后一个进程的ID号</td>
</tr>
<tr>
<td><code>$@</code></td>
<td>与<code>$*</code>相同,但是使用时加引号,并在引号中返回每个参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$-</code></td>
<td>显示Shell使用的当前选项,与set功能相同。</td>
</tr>
<tr>
<td><code>$?</code></td>
<td>显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。</td>
</tr>
</tbody></table>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-bash">set -e
echo &quot;执行的文件名:$0&quot;
echo &quot;参数个数为$#&quot;
echo &quot;第一个参数为:$1&quot;
echo &quot;第二个参数为:$2&quot;
echo &quot;所有参数为:$@&quot;
echo &quot;进程ID号为:$$&quot;
echo &quot;当前shell选项为$-&quot;
echo &quot;上一个命令退出的状态为$?&quot;
</code></pre>
<p>执行结果如下:</p>
<pre><code class="language-shell">$ sh test.sh param1 &quot;param2 with space&quot;
执行的文件名:test.sh
参数个数为2
第一个参数为:param1
第二个参数为:param2 with space
所有参数为:param1 param2 with space
进程ID号为:3700
当前shell选项为ehB
上一个命令退出的状态为0
</code></pre>
<h1>8. 函数</h1>
<p>函数定义通过<code>function_name(){}</code>的形式定义,函数返回值可以显示用return返回,如果不加,将以最后一条命令的运行结果作为返回值,函数返回值只能是数字。函数也可以传递参数,但是函数定义的()中不需要申明。</p>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-shell">sayhello(){
echo &quot;hello&quot;
}
# 注意函数调用只需要函数名,不需要加()
sayhello
sayhellowithparam(){
echo &quot;hello, $1 $2 $3&quot;
return 1
}
sayhellowithparam zhangsan lisi wangwu
echo $?
</code></pre>
<p>输出如下:</p>
<blockquote>
<p>hello<br>hello, zhangsan lisi wangwu<br>1</p>
</blockquote>
<h1>9. 命令替换</h1>
<p>命令替换可以将一个命令的输出作为另外一个命令的参数。</p>
<pre><code class="language-shell"># command1 `command2`
cd `pwd` # 该命令将pwd命令列出的目录作为cd命令的参数,结果仍然是停留在当前目录下
cd `echo $HOME` # 将echo的输出作为cd的参数,即打开用户根目录
</code></pre>
<h1>10. let命令</h1>
<p>let 命令是 BASH 中用于计算的工具,用于执行一个或多个表达式,变量计算中不需要加上 $ 来表示变量。如果表达式中包含了空格或其他特殊字符,则必须引起来。</p>
<ul>
<li>自加操作:<code>let no++</code></li>
<li>自减操作:<code>let no--</code></li>
<li>简写形式 <code>let no+=10</code>,<code>let no-=20</code>,分别等同于<code>let no=no+10</code>,<code>let no=no-20</code></li>
</ul>
<h1>11. 流程控制</h1>
<h2>11.1. if</h2>
<pre><code class="language-shell">if ((10&lt;2));then
echo &quot;10小于2&quot;
elif ((10&gt;20));then
echo &quot;a大于10&quot;
else
echo &quot;10大于2且小于10&quot;
fi
</code></pre>
<h2>11.2. case</h2>
<p><code>case</code>每一种情况以右括号结尾,执行到<code>;;</code>结束</p>
<pre><code class="language-shell">case 10 in
0|1)
echo &quot;a为0或1&quot;
;;
11|12)
echo &quot;a为11或12&quot;
;;
*)
# *用来匹配所有情况
echo &quot;a为10&quot;
;;
esac
</code></pre>
<h2>11.3. while</h2>
<pre><code class="language-shell">count=0
while(($count&lt;5))
do
echo $count
let count++
done
</code></pre>
<h2>11.4. util</h2>
<pre><code class="language-shell">count=0
until(($count&gt;=5))
do
echo $count
let count++
done
</code></pre>
<h2>11.5. for</h2>
<pre><code class="language-shell"># for写法1
for ((count=0;$count&lt;5;count=$count+1))
do
echo $count
done
# for写法2
arr=(0 1 2 3 4)
for count in ${arr[*]}
do
echo $int
done
# for写法3
for int in 0 1 2 3 4
do
echo $int
done
</code></pre>
<h2>11.6. break和continue</h2>
<p>用法与一般编程语言类似,break跳出循环,continue跳出当前循环</p>
<pre><code class="language-shell">for ((count=0;$count&gt;=0;count=$count+1))
do
if (($count&gt;=5));then
break;
fi
echo $count
done
</code></pre>
<h1>12. 输入输出重定向</h1>
<h2>12.1. 输出重定向</h2>
<p><code>command &gt; file</code>将命令输出结果保存的file文件中。<code>&gt;</code>从文件头开始写,会覆盖旧内容,<code>&gt;&gt;</code>将内容追加到文件末尾</p>
<pre><code class="language-shell"># 将who命令的输出保存的users文件中,可以通过cat users查看
who &gt; users
# 将字符串hello world保存到text.txt文件中
echo &quot;hello world&quot; &gt; text.txt
</code></pre>
<h2>12.2. 输入重定向</h2>
<p><code>command &lt; file</code>从file文件获取输入</p>
<pre><code class="language-shell">wc -l /etc/passwd
# 123 /etc/passwd
wc -l &lt; users
# 123
# 第一个例子,会输出文件名;第二个不会,因为它仅仅知道从标准输入读取内容
# command &lt; infile &gt; outfile, 同时替换输入和输出,执行command,从文件infile读取内容,然后将输出写入到outfile中。
wc -l &lt; /etc/passwd &gt; result
cat result
# 123
</code></pre>
<h2>12.3. 文件描述符</h2>
<p>一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件</p>
<ul>
<li>标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。</li>
<li>标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。</li>
<li>标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。</li>
</ul>
<pre><code class="language-shell"># 将标准错误输出重定向到error_trace
cat /tmp/fake_file 2&gt;error_trace
cat error_trace
# cat: /tmp/fake_fule: No such file or directory
# 将标准输出和标准错误输出都重定向到result
cat /tmp/fake_file &amp;&gt;result
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准错误重定向到标准输出
ls /tmp/fake_file &gt; result 2&gt;&amp;1
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准输入重定向到result,将标准错误输出重定向到error_trace
cat /tmp/fake_file 1&gt;result 2&gt;error_trace
</code></pre>
<h2>12.4. Here Document</h2>
<p>将两个<code>EOF</code>之间的内容(document) 作为输入传递给<code>command</code></p>
<pre><code class="language-bash"># command &lt;&lt; EOF
# document
# EOF
cat &lt;&lt; EOF
hello
shinerio
learn shell
EOF
</code></pre>
<blockquote>
<p>结尾的<code>EOF</code>一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和<code>tab</code>缩进。开始的<code>EOF</code>前后的空格会被忽略掉。</p>
</blockquote>
<h2>12.5. /dev/null</h2>
<p>如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null。<code>command &gt; /dev/null</code></p>
<pre><code class="language-shell">cat users &gt; /dev/null
cat users &gt; /dev/null 2&gt;&amp;1
</code></pre>
<h1>13. set命令</h1>
<p>set指令能设置所使用shell的执行方式,可依照不同的需求来做设置。以下只列出常用的选项参数:</p>
<ul>
<li>-e 若指令传回值不等于0,则立即退出shell。</li>
<li>-f 取消使用通配符。</li>
<li>-n 只读取指令,而不实际执行。</li>
<li>-x 执行指令后,会先显示该指令及所下的参数。</li>
</ul>
#39;hello' ];then echo 'hello';fi
str='hello'
if [ $str ];then echo 'hello';fi
# hello
</code></pre>
<p>注意字符串的等值判断是一个等号<code>"="</code>,与下文要讲的逻辑运算符使用两个等号<code>"=="</code>做等值判断不一样。</p>
<h1>4. 文件测试运算符</h1>
<table>
<thead>
<tr>
<th>操作符</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>-b file</code></td>
<td>检测文件是否是块设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-c file</code></td>
<td>检测文件是否是字符设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-d file</code></td>
<td>检测文件是否是目录,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-f file</code></td>
<td>检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-g file</code></td>
<td>检测文件是否设置了<code>SGID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-k file</code></td>
<td>检测文件是否设置了粘着位(Sticky Bit),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-p file</code></td>
<td>检测文件是否是有名管道,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-u file</code></td>
<td>检测文件是否设置了<code>SUID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-r file</code></td>
<td>检测文件是否可读,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-w file</code></td>
<td>检测文件是否可写,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-x file</code></td>
<td>检测文件是否可执行,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-s file</code></td>
<td>检测文件是否为空(文件大小是否大于0),不为空返回true。</td>
</tr>
<tr>
<td><code>-e file</code></td>
<td>检测文件(包括目录)是否存在,如果是,则返回true。</td>
</tr>
</tbody></table>
<pre><code class="language-shell">if <a href="f-home.html" class="internal-link"> -f '/home' </a>;then echo 'directory';else echo 'file';fi
# file
if <a href="d-home.html" class="internal-link"> -d '/home' </a>;then echo 'directory';else echo 'file';fi
# directory
if <a href="e-tmpfake-file.html" class="internal-link"> -e '/tmp/fake_file' </a>;then echo 'exist';else echo 'not exist';fi
# not exist
</code></pre>
<h1>5. 数组</h1>
<p><code>shell</code>只支持一维数组,用括号表示,元素通过空格分隔,形如<code>数组名=(值1 值2 ... 值n)</code>。<code>shell</code>数组下标从<code>1</code>开始。</p>
<ul>
<li><code>${数组名[下标]}</code>,读取指索引位置数组元素</li>
<li>使用<code>@</code>或<code>*</code>代替下标,获取数组中所有元素。</li>
<li>使用<code>{<span class="tag">#数组名</span>[@]}</code>或<code>{<span class="tag">#数组名</span>[*]}</code>获取数组元素个数。</li>
</ul>
<pre><code class="language-shell">arr=(value1 value2 value3 value4)
echo ${arr[3]}
# value3
echo ${arr[*]}
# value1 value2 value3 value4
echo ${arr[@]}
# value1 value2 value3 value4
arr[3]='new_value3'
echo $arr[3]
# new_value3
echo ${<span class="tag">#arr</span>[@]}
# 4
echo "arr[1]的长度为:${<span class="tag">#arr</span>[1]}"
# arr[1]的长度为:6
</code></pre>
<h1>6. 运算符</h1>
<h2>6.1. 赋值运算符</h2>
<pre><code class="language-shell">a=10
b=$a
</code></pre>
<h2>6.2. 算术运算符</h2>
<p>算数运算符支持<code>+,-,*,/,%</code></p>
<h3>6.2.1. expr表示法</h3>
<pre><code class="language-shell">echo `expr 10 + 20`
# 30
echo $(expr 20 / 2)
# 10
echo $(expr 10 \* 20) # 使用expr进行乘法运算时必须使用\进行转义
# 200
</code></pre>
<blockquote>
<p>使用expr表示方法时,表达式和运算符之间必须有空格。</p>
</blockquote>
<h3>6.2.2. <code>$[]</code></h3>
<pre><code class="language-shell">echo $[10%3]
# 1
</code></pre>
<h3>6.2.3. <code>$(())</code></h3>
<pre><code class="language-shell">echo $((10*20))
# 200
</code></pre>
<h2>6.3. 关系运算符</h2>
<p>最常见的关系运算符是:<code>==,!=,<,>,>=,<=</code></p>
<pre><code class="language-shell">echo $[10==10]
# 1
flag=$[20==10]
echo $flag
# 1
echo $[10>=10]
# 1
</code></pre>
<p>如下关系运算符只能使用在条件表达式<code>if、while</code>下,类似<code>flag=[ $a -eq $b ]</code>的直接赋值语句是非法的。关系运算符的条件表达式要放在<strong>一对</strong>方括号中,并且中间需要有空格。也可以使用<code>(())</code>替代<code>[]</code>,此时<code>-eq,-lt,-le</code>之类的需要使用<code>==,<,<=</code>等替换。</p>
<blockquote>
<p><code>[]</code>搭配<code>-eq -ne</code>等使用,<code>(())</code>搭配<code>|| &&</code>等使用。</p>
</blockquote>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>-eq</code></td>
<td>检测两个数是否相等,相等返回true。</td>
<td><code>[ $a -eq $b ]</code></td>
</tr>
<tr>
<td><code>-ne</code></td>
<td>检测两个数是否不相等,不相等返回 true。</td>
<td><code>[ $a -ne $b ]</code></td>
</tr>
<tr>
<td><code>-gt</code></td>
<td>检测左边的数是否大于右边的,如果是,则返回 true。</td>
<td><code>[ $a -gt $b ]</code></td>
</tr>
<tr>
<td><code>-lt</code></td>
<td>检测左边的数是否小于右边的,如果是,则返回 true。</td>
<td><code>[ $a -lt $b ]</code></td>
</tr>
<tr>
<td><code>-ge</code></td>
<td>检测左边的数是否大于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -ge $b ]</code></td>
</tr>
<tr>
<td><code>-le</code></td>
<td>检测左边的数是否小于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -le $b ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ 1 -eq 1 ];then echo 'hello';fi;
# hello
if ((10>=10));then echo 'hello';fi;
# hello
</code></pre>
<h2>6.4. 布尔、逻辑运算符</h2>
<p>布尔、逻辑运算的条件表达式也要放在一对方括号中<code>[]</code>。</p>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>!</code></td>
<td>非运算,表达式为true则返回false,否则返回true。</td>
<td><code>[ ! 10 -eq 0 ]</code></td>
</tr>
<tr>
<td><code>-o</code></td>
<td>或运算,有一个表达式为true则返回true。</td>
<td><code>[ 10 -lt 20 -o 10 -gt 100 ]</code></td>
</tr>
<tr>
<td><code>-a</code></td>
<td>与运算,两个表达式都为true才返回true。</td>
<td><code>[ 10 -lt 20 -a 10 -gt 100 ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ ! 10 -eq 0 ];then echo 'hello';fi
# hello
if [ 10 -ge 10 -a 10 -ge 10 ];then echo 'hello';fi
# hello
if [ 10 -ge 20 -o 10 -ge 0 ];then echo 'hello';fi
# hello
</code></pre>
<p> <code>-o</code>也可以使用<code>||</code>替代,<code>-a</code>也可以使用<code>&&</code>替代,此时需要使用<code>(())</code>或<code>[[]]</code>替代<code>[]</code>。</p>
<pre><code class="language-shell">if <a href="1010-55.html" class="internal-link"> 10==10 && 5==5 </a>;then echo 'hello';fi
# hello
if ((10==10 && 5==5));then echo 'hello';fi
# hello
</code></pre>
<h1>7. 传递参数</h1>
<p>在执行 <code>Shell</code>脚本时,向脚本传递参数,脚本内获取参数的格式为:<code>$n</code>。<code>n</code>代表一个数字,<code>1</code>为执行脚本的第一个参数,<code>2</code>为执行脚本的第二个参数,<code>$0</code>为执行的文件名。在为<code>shell</code>脚本传递的参数中如果包含空格,应该使用单引号或者双引号将该参数括起来,以便于脚本将这个参数作为整体来接收。另外,还有几个特殊字符用来处理参数:</p>
<table>
<thead>
<tr>
<th>参数处理</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>$#</code></td>
<td>传递到脚本的参数个数</td>
</tr>
<tr>
<td><code>$*</code></td>
<td>以一个单字符串显示所有向脚本传递的参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$</code></td>
<td>脚本运行的当前进程ID号</td>
</tr>
<tr>
<td><code>$!</code></td>
<td>后台运行的最后一个进程的ID号</td>
</tr>
<tr>
<td><code>$@</code></td>
<td>与<code>$*</code>相同,但是使用时加引号,并在引号中返回每个参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$-</code></td>
<td>显示Shell使用的当前选项,与set功能相同。</td>
</tr>
<tr>
<td><code>$?</code></td>
<td>显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。</td>
</tr>
</tbody></table>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-bash">set -e
echo "执行的文件名:$0"
echo "参数个数为$#"
echo "第一个参数为:$1"
echo "第二个参数为:$2"
echo "所有参数为:$@"
echo "进程ID号为:$"
echo "当前shell选项为$-"
echo "上一个命令退出的状态为$?"
</code></pre>
<p>执行结果如下:</p>
<pre><code class="language-shell">$ sh test.sh param1 "param2 with space"
执行的文件名:test.sh
参数个数为2
第一个参数为:param1
第二个参数为:param2 with space
所有参数为:param1 param2 with space
进程ID号为:3700
当前shell选项为ehB
上一个命令退出的状态为0
</code></pre>
<h1>8. 函数</h1>
<p>函数定义通过<code>function_name(){}</code>的形式定义,函数返回值可以显示用return返回,如果不加,将以最后一条命令的运行结果作为返回值,函数返回值只能是数字。函数也可以传递参数,但是函数定义的()中不需要申明。</p>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-shell">sayhello(){
echo "hello"
}
# 注意函数调用只需要函数名,不需要加()
sayhello
sayhellowithparam(){
echo "hello, $1 $2 $3"
return 1
}
sayhellowithparam zhangsan lisi wangwu
echo $?
</code></pre>
<p>输出如下:</p>
<blockquote>
<p>hello<br>hello, zhangsan lisi wangwu<br>1</p>
</blockquote>
<h1>9. 命令替换</h1>
<p>命令替换可以将一个命令的输出作为另外一个命令的参数。</p>
<pre><code class="language-shell"># command1 `command2`
cd `pwd` # 该命令将pwd命令列出的目录作为cd命令的参数,结果仍然是停留在当前目录下
cd `echo $HOME` # 将echo的输出作为cd的参数,即打开用户根目录
</code></pre>
<h1>10. let命令</h1>
<p>let 命令是 BASH 中用于计算的工具,用于执行一个或多个表达式,变量计算中不需要加上 $ 来表示变量。如果表达式中包含了空格或其他特殊字符,则必须引起来。</p>
<ul>
<li>自加操作:<code>let no++</code></li>
<li>自减操作:<code>let no--</code></li>
<li>简写形式 <code>let no+=10</code>,<code>let no-=20</code>,分别等同于<code>let no=no+10</code>,<code>let no=no-20</code></li>
</ul>
<h1>11. 流程控制</h1>
<h2>11.1. if</h2>
<pre><code class="language-shell">if ((10<2));then
echo "10小于2"
elif ((10>20));then
echo "a大于10"
else
echo "10大于2且小于10"
fi
</code></pre>
<h2>11.2. case</h2>
<p><code>case</code>每一种情况以右括号结尾,执行到<code>;;</code>结束</p>
<pre><code class="language-shell">case 10 in
0|1)
echo "a为0或1"
;;
11|12)
echo "a为11或12"
;;
*)
# *用来匹配所有情况
echo "a为10"
;;
esac
</code></pre>
<h2>11.3. while</h2>
<pre><code class="language-shell">count=0
while(($count<5))
do
echo $count
let count++
done
</code></pre>
<h2>11.4. util</h2>
<pre><code class="language-shell">count=0
until(($count>=5))
do
echo $count
let count++
done
</code></pre>
<h2>11.5. for</h2>
<pre><code class="language-shell"># for写法1
for ((count=0;$count<5;count=$count+1))
do
echo $count
done
# for写法2
arr=(0 1 2 3 4)
for count in ${arr[*]}
do
echo $int
done
# for写法3
for int in 0 1 2 3 4
do
echo $int
done
</code></pre>
<h2>11.6. break和continue</h2>
<p>用法与一般编程语言类似,break跳出循环,continue跳出当前循环</p>
<pre><code class="language-shell">for ((count=0;$count>=0;count=$count+1))
do
if (($count>=5));then
break;
fi
echo $count
done
</code></pre>
<h1>12. 输入输出重定向</h1>
<h2>12.1. 输出重定向</h2>
<p><code>command > file</code>将命令输出结果保存的file文件中。<code>></code>从文件头开始写,会覆盖旧内容,<code>>></code>将内容追加到文件末尾</p>
<pre><code class="language-shell"># 将who命令的输出保存的users文件中,可以通过cat users查看
who > users
# 将字符串hello world保存到text.txt文件中
echo "hello world" > text.txt
</code></pre>
<h2>12.2. 输入重定向</h2>
<p><code>command < file</code>从file文件获取输入</p>
<pre><code class="language-shell">wc -l /etc/passwd
# 123 /etc/passwd
wc -l < users
# 123
# 第一个例子,会输出文件名;第二个不会,因为它仅仅知道从标准输入读取内容
# command < infile > outfile, 同时替换输入和输出,执行command,从文件infile读取内容,然后将输出写入到outfile中。
wc -l < /etc/passwd > result
cat result
# 123
</code></pre>
<h2>12.3. 文件描述符</h2>
<p>一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件</p>
<ul>
<li>标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。</li>
<li>标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。</li>
<li>标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。</li>
</ul>
<pre><code class="language-shell"># 将标准错误输出重定向到error_trace
cat /tmp/fake_file 2>error_trace
cat error_trace
# cat: /tmp/fake_fule: No such file or directory
# 将标准输出和标准错误输出都重定向到result
cat /tmp/fake_file &>result
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准错误重定向到标准输出
ls /tmp/fake_file > result 2>&1
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准输入重定向到result,将标准错误输出重定向到error_trace
cat /tmp/fake_file 1>result 2>error_trace
</code></pre>
<h2>12.4. Here Document</h2>
<p>将两个<code>EOF</code>之间的内容(document) 作为输入传递给<code>command</code></p>
<pre><code class="language-bash"># command << EOF
# document
# EOF
cat << EOF
hello
shinerio
learn shell
EOF
</code></pre>
<blockquote>
<p>结尾的<code>EOF</code>一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和<code>tab</code>缩进。开始的<code>EOF</code>前后的空格会被忽略掉。</p>
</blockquote>
<h2>12.5. /dev/null</h2>
<p>如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null。<code>command > /dev/null</code></p>
<pre><code class="language-shell">cat users > /dev/null
cat users > /dev/null 2>&1
</code></pre>
<h1>13. set命令</h1>
<p>set指令能设置所使用shell的执行方式,可依照不同的需求来做设置。以下只列出常用的选项参数:</p>
<ul>
<li>-e 若指令传回值不等于0,则立即退出shell。</li>
<li>-f 取消使用通配符。</li>
<li>-n 只读取指令,而不实际执行。</li>
<li>-x 执行指令后,会先显示该指令及所下的参数。</li>
</ul>
</section>
</article>lt;/code>符号,变量加<code>{}</code>是可选的,方便解释器识别边界。将变量加上<code>{}</code>是一个好习惯,不容易出错。</p>
<pre><code class="language-shell">your_age=25
your_name="shinerio"
your_name=shinerio
your_name='shinerio'
echo $your_age # 输出25
echo $your_name # 输出shinerio
echo "${your_name}hello" <span class="tag">#这里</span>{}必须添加,否则解释器认为是${your_namehello}
str='hello'' # 非法
str='hello'__'world' # 成对出现的单引号做字符拼接
echo $str <span class="tag">#输出hello__world</span>
str1='helloworld${your_age}\nnew line'
str2="helloworld${your_age}\nnew line"
echo $str1 # 输出helloworld${your_age}\nnew line
echo $str2 # 输出helloworld25\nnew line
echo -e $str2 # -e开启转义 \n表示换行 echo默认换行,通过\c强制不换行
<span class="tag">#helloworld25</span>
<span class="tag">#new</span> line
</code></pre>
<h2>2.3. 只读变量</h2>
<p>使用<code>readonly VARIABLENAME</code>设置变量只读,只读变量的值不能更改</p>
<pre><code class="language-shell">readonly name='jack'
name='kelly'
zsh: read-only variable: name
</code></pre>
<h2>2.4. 删除变量</h2>
<p>使用<code>unset VARIABLENAME</code>删除变量。</p>
<h1>3. 字符串操作</h1>
<h2>3.1. 字符串拼接</h2>
<pre><code class="language-shell">str1="hello"${your_name}"world"
str2="hello${your_name}world"
str3='hello'${your_name}'world'
</code></pre>
<h2>3.2. 字符串长度</h2>
<pre><code class="language-shell">str='hello'
echo ${<span class="tag">#str</span>}
5
</code></pre>
<h2>3.3. 字符串截取</h2>
<p><code>${string:start:length}</code>,索引从0开始,从start(包含)开始截取共计length长度的字符。</p>
<pre><code class="language-shell">str='helloworld'
echo ${str:0:5}
hello
</code></pre>
<h2>3.4. 字符串运算符</h2>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>=</code></td>
<td>检测两个字符串是否相等,相等返回true</td>
<td><code>[ 'hello' = 'hello' ]</code></td>
</tr>
<tr>
<td><code>!=</code></td>
<td>检测两个字符串是否相等,不相等返回true</td>
<td><code>[ 'hello' != 'ello' ]</code></td>
</tr>
<tr>
<td><code>-z</code></td>
<td>检测字符串长度是否为0,为0返回true</td>
<td><code>[ -z '' ]</code></td>
</tr>
<tr>
<td><code>-n </code></td>
<td>检测字符串长度是否不为0,不为0返回true</td>
<td><code>[ -n 'hello' ]</code></td>
</tr>
<tr>
<td><code><article>
<header>
<h1>shell编程</h1>
<time datetime="2023-01-24T00:00:00.000Z">2023年1月24日</time>
<div class="tags">
<span class="tag">linux</span>
</div>
</header>
<section class="content">
<p>本文主要介绍shell编程的基本语法以及实际应用中的常见命令。</p>
<h1>1. 注释</h1>
<h2>1.1. 单行注释</h2>
<pre><code class="language-shell"># 这是单行注释
</code></pre>
<h2>1.2. 多行注释</h2>
<pre><code class="language-shell">:<<EOF
多行注释内容
多行注释内容
多行注释内容
EOF
</code></pre>
<p>多行注释<code>EOF</code>也可替换成<code>!</code>或<code>'</code></p>
<pre><code class="language-shell">:<<'
多行注释内容
多行注释内容
多行注释内容
'
:<<!
多行注释内容
多行注释内容
多行注释内容
!
</code></pre>
<h1>2. 变量</h1>
<h2>2.1. 变量定义</h2>
<p>使用<code>VARIABLENAME=VALUE</code>的形式,VALUE如果是字符串的话,可以使用单引号、双引号或者不加引号。单引号内的任何字符都会原样输出,不能进行转义,单引号内不能单独出现一个单引号,但可成对出现,作为字符串拼接使用。双引号内可以有变量,可以出现转义字符。</p>
<h2>2.2. 变量使用</h2>
<p>只需要在变量前加<code>$</code>符号,变量加<code>{}</code>是可选的,方便解释器识别边界。将变量加上<code>{}</code>是一个好习惯,不容易出错。</p>
<pre><code class="language-shell">your_age=25
your_name="shinerio"
your_name=shinerio
your_name='shinerio'
echo $your_age # 输出25
echo $your_name # 输出shinerio
echo "${your_name}hello" <span class="tag">#这里</span>{}必须添加,否则解释器认为是${your_namehello}
str='hello'' # 非法
str='hello'__'world' # 成对出现的单引号做字符拼接
echo $str <span class="tag">#输出hello__world</span>
str1='helloworld${your_age}\nnew line'
str2="helloworld${your_age}\nnew line"
echo $str1 # 输出helloworld${your_age}\nnew line
echo $str2 # 输出helloworld25\nnew line
echo -e $str2 # -e开启转义 \n表示换行 echo默认换行,通过\c强制不换行
<span class="tag">#helloworld25</span>
<span class="tag">#new</span> line
</code></pre>
<h2>2.3. 只读变量</h2>
<p>使用<code>readonly VARIABLENAME</code>设置变量只读,只读变量的值不能更改</p>
<pre><code class="language-shell">readonly name='jack'
name='kelly'
zsh: read-only variable: name
</code></pre>
<h2>2.4. 删除变量</h2>
<p>使用<code>unset VARIABLENAME</code>删除变量。</p>
<h1>3. 字符串操作</h1>
<h2>3.1. 字符串拼接</h2>
<pre><code class="language-shell">str1="hello"${your_name}"world"
str2="hello${your_name}world"
str3='hello'${your_name}'world'
</code></pre>
<h2>3.2. 字符串长度</h2>
<pre><code class="language-shell">str='hello'
echo ${<span class="tag">#str</span>}
5
</code></pre>
<h2>3.3. 字符串截取</h2>
<p><code>${string:start:length}</code>,索引从0开始,从start(包含)开始截取共计length长度的字符。</p>
<pre><code class="language-shell">str='helloworld'
echo ${str:0:5}
hello
</code></pre>
<h2>3.4. 字符串运算符</h2>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>=</code></td>
<td>检测两个字符串是否相等,相等返回true</td>
<td><code>[ 'hello' = 'hello' ]</code></td>
</tr>
<tr>
<td><code>!=</code></td>
<td>检测两个字符串是否相等,不相等返回true</td>
<td><code>[ 'hello' != 'ello' ]</code></td>
</tr>
<tr>
<td><code>-z</code></td>
<td>检测字符串长度是否为0,为0返回true</td>
<td><code>[ -z '' ]</code></td>
</tr>
<tr>
<td><code>-n </code></td>
<td>检测字符串长度是否不为0,不为0返回true</td>
<td><code>[ -n 'hello' ]</code></td>
</tr>
<tr>
<td><code>$</code></td>
<td>检测字符串是否为空,不为空返回true</td>
<td><code>[ <p>本文主要介绍shell编程的基本语法以及实际应用中的常见命令。</p>
<h1>1. 注释</h1>
<h2>1.1. 单行注释</h2>
<pre><code class="language-shell"># 这是单行注释
</code></pre>
<h2>1.2. 多行注释</h2>
<pre><code class="language-shell">:&lt;&lt;EOF
多行注释内容
多行注释内容
多行注释内容
EOF
</code></pre>
<p>多行注释<code>EOF</code>也可替换成<code>!</code>或<code>&#39;</code></p>
<pre><code class="language-shell">:&lt;&lt;&#39;
多行注释内容
多行注释内容
多行注释内容
&#39;
:&lt;&lt;!
多行注释内容
多行注释内容
多行注释内容
!
</code></pre>
<h1>2. 变量</h1>
<h2>2.1. 变量定义</h2>
<p>使用<code>VARIABLENAME=VALUE</code>的形式,VALUE如果是字符串的话,可以使用单引号、双引号或者不加引号。单引号内的任何字符都会原样输出,不能进行转义,单引号内不能单独出现一个单引号,但可成对出现,作为字符串拼接使用。双引号内可以有变量,可以出现转义字符。</p>
<h2>2.2. 变量使用</h2>
<p>只需要在变量前加<code>$</code>符号,变量加<code>{}</code>是可选的,方便解释器识别边界。将变量加上<code>{}</code>是一个好习惯,不容易出错。</p>
<pre><code class="language-shell">your_age=25
your_name=&quot;shinerio&quot;
your_name=shinerio
your_name=&#39;shinerio&#39;
echo $your_age # 输出25
echo $your_name # 输出shinerio
echo &quot;${your_name}hello&quot; &lt;span class=&quot;tag&quot;&gt;#这里&lt;/span&gt;{}必须添加,否则解释器认为是${your_namehello}
str=&#39;hello&#39;&#39; # 非法
str=&#39;hello&#39;__&#39;world&#39; # 成对出现的单引号做字符拼接
echo $str &lt;span class=&quot;tag&quot;&gt;#输出hello__world&lt;/span&gt;
str1=&#39;helloworld${your_age}\nnew line&#39;
str2=&quot;helloworld${your_age}\nnew line&quot;
echo $str1 # 输出helloworld${your_age}\nnew line
echo $str2 # 输出helloworld25\nnew line
echo -e $str2 # -e开启转义 \n表示换行 echo默认换行,通过\c强制不换行
&lt;span class=&quot;tag&quot;&gt;#helloworld25&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;#new&lt;/span&gt; line
</code></pre>
<h2>2.3. 只读变量</h2>
<p>使用<code>readonly VARIABLENAME</code>设置变量只读,只读变量的值不能更改</p>
<pre><code class="language-shell">readonly name=&#39;jack&#39;
name=&#39;kelly&#39;
zsh: read-only variable: name
</code></pre>
<h2>2.4. 删除变量</h2>
<p>使用<code>unset VARIABLENAME</code>删除变量。</p>
<h1>3. 字符串操作</h1>
<h2>3.1. 字符串拼接</h2>
<pre><code class="language-shell">str1=&quot;hello&quot;${your_name}&quot;world&quot;
str2=&quot;hello${your_name}world&quot;
str3=&#39;hello&#39;${your_name}&#39;world&#39;
</code></pre>
<h2>3.2. 字符串长度</h2>
<pre><code class="language-shell">str=&#39;hello&#39;
echo ${&lt;span class=&quot;tag&quot;&gt;#str&lt;/span&gt;}
5
</code></pre>
<h2>3.3. 字符串截取</h2>
<p><code>${string:start:length}</code>,索引从0开始,从start(包含)开始截取共计length长度的字符。</p>
<pre><code class="language-shell">str=&#39;helloworld&#39;
echo ${str:0:5}
hello
</code></pre>
<h2>3.4. 字符串运算符</h2>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>=</code></td>
<td>检测两个字符串是否相等,相等返回true</td>
<td><code>[ &#39;hello&#39; = &#39;hello&#39; ]</code></td>
</tr>
<tr>
<td><code>!=</code></td>
<td>检测两个字符串是否相等,不相等返回true</td>
<td><code>[ &#39;hello&#39; != &#39;ello&#39; ]</code></td>
</tr>
<tr>
<td><code>-z</code></td>
<td>检测字符串长度是否为0,为0返回true</td>
<td><code>[ -z &#39;&#39; ]</code></td>
</tr>
<tr>
<td><code>-n </code></td>
<td>检测字符串长度是否不为0,不为0返回true</td>
<td><code>[ -n &#39;hello&#39; ]</code></td>
</tr>
<tr>
<td><code>$</code></td>
<td>检测字符串是否为空,不为空返回true</td>
<td><code>[ $&#39;hello&#39; ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ &#39;hello&#39; = &#39;hello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ &#39;hello&#39; != &#39;ello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ -z &#39;&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ -n &#39;hello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ $&#39;hello&#39; ];then echo &#39;hello&#39;;fi
str=&#39;hello&#39;
if [ $str ];then echo &#39;hello&#39;;fi
# hello
</code></pre>
<p>注意字符串的等值判断是一个等号<code>&quot;=&quot;</code>,与下文要讲的逻辑运算符使用两个等号<code>&quot;==&quot;</code>做等值判断不一样。</p>
<h1>4. 文件测试运算符</h1>
<table>
<thead>
<tr>
<th>操作符</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>-b file</code></td>
<td>检测文件是否是块设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-c file</code></td>
<td>检测文件是否是字符设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-d file</code></td>
<td>检测文件是否是目录,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-f file</code></td>
<td>检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-g file</code></td>
<td>检测文件是否设置了<code>SGID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-k file</code></td>
<td>检测文件是否设置了粘着位(Sticky Bit),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-p file</code></td>
<td>检测文件是否是有名管道,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-u file</code></td>
<td>检测文件是否设置了<code>SUID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-r file</code></td>
<td>检测文件是否可读,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-w file</code></td>
<td>检测文件是否可写,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-x file</code></td>
<td>检测文件是否可执行,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-s file</code></td>
<td>检测文件是否为空(文件大小是否大于0),不为空返回true。</td>
</tr>
<tr>
<td><code>-e file</code></td>
<td>检测文件(包括目录)是否存在,如果是,则返回true。</td>
</tr>
</tbody></table>
<pre><code class="language-shell">if &lt;a href=&quot;f-home.html&quot; class=&quot;internal-link&quot;&gt; -f &#39;/home&#39; &lt;/a&gt;;then echo &#39;directory&#39;;else echo &#39;file&#39;;fi
# file
if &lt;a href=&quot;d-home.html&quot; class=&quot;internal-link&quot;&gt; -d &#39;/home&#39; &lt;/a&gt;;then echo &#39;directory&#39;;else echo &#39;file&#39;;fi
# directory
if &lt;a href=&quot;e-tmpfake-file.html&quot; class=&quot;internal-link&quot;&gt; -e &#39;/tmp/fake_file&#39; &lt;/a&gt;;then echo &#39;exist&#39;;else echo &#39;not exist&#39;;fi
# not exist
</code></pre>
<h1>5. 数组</h1>
<p><code>shell</code>只支持一维数组,用括号表示,元素通过空格分隔,形如<code>数组名=(值1 值2 ... 值n)</code>。<code>shell</code>数组下标从<code>1</code>开始。</p>
<ul>
<li><code>${数组名[下标]}</code>,读取指索引位置数组元素</li>
<li>使用<code>@</code>或<code>*</code>代替下标,获取数组中所有元素。</li>
<li>使用<code>{&lt;span class=&quot;tag&quot;&gt;#数组名&lt;/span&gt;[@]}</code>或<code>{&lt;span class=&quot;tag&quot;&gt;#数组名&lt;/span&gt;[*]}</code>获取数组元素个数。</li>
</ul>
<pre><code class="language-shell">arr=(value1 value2 value3 value4)
echo ${arr[3]}
# value3
echo ${arr[*]}
# value1 value2 value3 value4
echo ${arr[@]}
# value1 value2 value3 value4
arr[3]=&#39;new_value3&#39;
echo $arr[3]
# new_value3
echo ${&lt;span class=&quot;tag&quot;&gt;#arr&lt;/span&gt;[@]}
# 4
echo &quot;arr[1]的长度为:${&lt;span class=&quot;tag&quot;&gt;#arr&lt;/span&gt;[1]}&quot;
# arr[1]的长度为:6
</code></pre>
<h1>6. 运算符</h1>
<h2>6.1. 赋值运算符</h2>
<pre><code class="language-shell">a=10
b=$a
</code></pre>
<h2>6.2. 算术运算符</h2>
<p>算数运算符支持<code>+,-,*,/,%</code></p>
<h3>6.2.1. expr表示法</h3>
<pre><code class="language-shell">echo `expr 10 + 20`
# 30
echo $(expr 20 / 2)
# 10
echo $(expr 10 \* 20) # 使用expr进行乘法运算时必须使用\进行转义
# 200
</code></pre>
<blockquote>
<p>使用expr表示方法时,表达式和运算符之间必须有空格。</p>
</blockquote>
<h3>6.2.2. <code>$[]</code></h3>
<pre><code class="language-shell">echo $[10%3]
# 1
</code></pre>
<h3>6.2.3. <code>$(())</code></h3>
<pre><code class="language-shell">echo $((10*20))
# 200
</code></pre>
<h2>6.3. 关系运算符</h2>
<p>最常见的关系运算符是:<code>==,!=,&lt;,&gt;,&gt;=,&lt;=</code></p>
<pre><code class="language-shell">echo $[10==10]
# 1
flag=$[20==10]
echo $flag
# 1
echo $[10&gt;=10]
# 1
</code></pre>
<p>如下关系运算符只能使用在条件表达式<code>if、while</code>下,类似<code>flag=[ $a -eq $b ]</code>的直接赋值语句是非法的。关系运算符的条件表达式要放在<strong>一对</strong>方括号中,并且中间需要有空格。也可以使用<code>(())</code>替代<code>[]</code>,此时<code>-eq,-lt,-le</code>之类的需要使用<code>==,&lt;,&lt;=</code>等替换。</p>
<blockquote>
<p><code>[]</code>搭配<code>-eq -ne</code>等使用,<code>(())</code>搭配<code>|| &amp;&amp;</code>等使用。</p>
</blockquote>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>-eq</code></td>
<td>检测两个数是否相等,相等返回true。</td>
<td><code>[ $a -eq $b ]</code></td>
</tr>
<tr>
<td><code>-ne</code></td>
<td>检测两个数是否不相等,不相等返回 true。</td>
<td><code>[ $a -ne $b ]</code></td>
</tr>
<tr>
<td><code>-gt</code></td>
<td>检测左边的数是否大于右边的,如果是,则返回 true。</td>
<td><code>[ $a -gt $b ]</code></td>
</tr>
<tr>
<td><code>-lt</code></td>
<td>检测左边的数是否小于右边的,如果是,则返回 true。</td>
<td><code>[ $a -lt $b ]</code></td>
</tr>
<tr>
<td><code>-ge</code></td>
<td>检测左边的数是否大于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -ge $b ]</code></td>
</tr>
<tr>
<td><code>-le</code></td>
<td>检测左边的数是否小于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -le $b ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ 1 -eq 1 ];then echo &#39;hello&#39;;fi;
# hello
if ((10&gt;=10));then echo &#39;hello&#39;;fi;
# hello
</code></pre>
<h2>6.4. 布尔、逻辑运算符</h2>
<p>布尔、逻辑运算的条件表达式也要放在一对方括号中<code>[]</code>。</p>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>!</code></td>
<td>非运算,表达式为true则返回false,否则返回true。</td>
<td><code>[ ! 10 -eq 0 ]</code></td>
</tr>
<tr>
<td><code>-o</code></td>
<td>或运算,有一个表达式为true则返回true。</td>
<td><code>[ 10 -lt 20 -o 10 -gt 100 ]</code></td>
</tr>
<tr>
<td><code>-a</code></td>
<td>与运算,两个表达式都为true才返回true。</td>
<td><code>[ 10 -lt 20 -a 10 -gt 100 ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ ! 10 -eq 0 ];then echo &#39;hello&#39;;fi
# hello
if [ 10 -ge 10 -a 10 -ge 10 ];then echo &#39;hello&#39;;fi
# hello
if [ 10 -ge 20 -o 10 -ge 0 ];then echo &#39;hello&#39;;fi
# hello
</code></pre>
<p> <code>-o</code>也可以使用<code>||</code>替代,<code>-a</code>也可以使用<code>&amp;&amp;</code>替代,此时需要使用<code>(())</code>或<code>[[]]</code>替代<code>[]</code>。</p>
<pre><code class="language-shell">if &lt;a href=&quot;1010-55.html&quot; class=&quot;internal-link&quot;&gt; 10==10 &amp;&amp; 5==5 &lt;/a&gt;;then echo &#39;hello&#39;;fi
# hello
if ((10==10 &amp;&amp; 5==5));then echo &#39;hello&#39;;fi
# hello
</code></pre>
<h1>7. 传递参数</h1>
<p>在执行 <code>Shell</code>脚本时,向脚本传递参数,脚本内获取参数的格式为:<code>$n</code>。<code>n</code>代表一个数字,<code>1</code>为执行脚本的第一个参数,<code>2</code>为执行脚本的第二个参数,<code>$0</code>为执行的文件名。在为<code>shell</code>脚本传递的参数中如果包含空格,应该使用单引号或者双引号将该参数括起来,以便于脚本将这个参数作为整体来接收。另外,还有几个特殊字符用来处理参数:</p>
<table>
<thead>
<tr>
<th>参数处理</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>$#</code></td>
<td>传递到脚本的参数个数</td>
</tr>
<tr>
<td><code>$*</code></td>
<td>以一个单字符串显示所有向脚本传递的参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$$</code></td>
<td>脚本运行的当前进程ID号</td>
</tr>
<tr>
<td><code>$!</code></td>
<td>后台运行的最后一个进程的ID号</td>
</tr>
<tr>
<td><code>$@</code></td>
<td>与<code>$*</code>相同,但是使用时加引号,并在引号中返回每个参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$-</code></td>
<td>显示Shell使用的当前选项,与set功能相同。</td>
</tr>
<tr>
<td><code>$?</code></td>
<td>显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。</td>
</tr>
</tbody></table>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-bash">set -e
echo &quot;执行的文件名:$0&quot;
echo &quot;参数个数为$#&quot;
echo &quot;第一个参数为:$1&quot;
echo &quot;第二个参数为:$2&quot;
echo &quot;所有参数为:$@&quot;
echo &quot;进程ID号为:$$&quot;
echo &quot;当前shell选项为$-&quot;
echo &quot;上一个命令退出的状态为$?&quot;
</code></pre>
<p>执行结果如下:</p>
<pre><code class="language-shell">$ sh test.sh param1 &quot;param2 with space&quot;
执行的文件名:test.sh
参数个数为2
第一个参数为:param1
第二个参数为:param2 with space
所有参数为:param1 param2 with space
进程ID号为:3700
当前shell选项为ehB
上一个命令退出的状态为0
</code></pre>
<h1>8. 函数</h1>
<p>函数定义通过<code>function_name(){}</code>的形式定义,函数返回值可以显示用return返回,如果不加,将以最后一条命令的运行结果作为返回值,函数返回值只能是数字。函数也可以传递参数,但是函数定义的()中不需要申明。</p>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-shell">sayhello(){
echo &quot;hello&quot;
}
# 注意函数调用只需要函数名,不需要加()
sayhello
sayhellowithparam(){
echo &quot;hello, $1 $2 $3&quot;
return 1
}
sayhellowithparam zhangsan lisi wangwu
echo $?
</code></pre>
<p>输出如下:</p>
<blockquote>
<p>hello<br>hello, zhangsan lisi wangwu<br>1</p>
</blockquote>
<h1>9. 命令替换</h1>
<p>命令替换可以将一个命令的输出作为另外一个命令的参数。</p>
<pre><code class="language-shell"># command1 `command2`
cd `pwd` # 该命令将pwd命令列出的目录作为cd命令的参数,结果仍然是停留在当前目录下
cd `echo $HOME` # 将echo的输出作为cd的参数,即打开用户根目录
</code></pre>
<h1>10. let命令</h1>
<p>let 命令是 BASH 中用于计算的工具,用于执行一个或多个表达式,变量计算中不需要加上 $ 来表示变量。如果表达式中包含了空格或其他特殊字符,则必须引起来。</p>
<ul>
<li>自加操作:<code>let no++</code></li>
<li>自减操作:<code>let no--</code></li>
<li>简写形式 <code>let no+=10</code>,<code>let no-=20</code>,分别等同于<code>let no=no+10</code>,<code>let no=no-20</code></li>
</ul>
<h1>11. 流程控制</h1>
<h2>11.1. if</h2>
<pre><code class="language-shell">if ((10&lt;2));then
echo &quot;10小于2&quot;
elif ((10&gt;20));then
echo &quot;a大于10&quot;
else
echo &quot;10大于2且小于10&quot;
fi
</code></pre>
<h2>11.2. case</h2>
<p><code>case</code>每一种情况以右括号结尾,执行到<code>;;</code>结束</p>
<pre><code class="language-shell">case 10 in
0|1)
echo &quot;a为0或1&quot;
;;
11|12)
echo &quot;a为11或12&quot;
;;
*)
# *用来匹配所有情况
echo &quot;a为10&quot;
;;
esac
</code></pre>
<h2>11.3. while</h2>
<pre><code class="language-shell">count=0
while(($count&lt;5))
do
echo $count
let count++
done
</code></pre>
<h2>11.4. util</h2>
<pre><code class="language-shell">count=0
until(($count&gt;=5))
do
echo $count
let count++
done
</code></pre>
<h2>11.5. for</h2>
<pre><code class="language-shell"># for写法1
for ((count=0;$count&lt;5;count=$count+1))
do
echo $count
done
# for写法2
arr=(0 1 2 3 4)
for count in ${arr[*]}
do
echo $int
done
# for写法3
for int in 0 1 2 3 4
do
echo $int
done
</code></pre>
<h2>11.6. break和continue</h2>
<p>用法与一般编程语言类似,break跳出循环,continue跳出当前循环</p>
<pre><code class="language-shell">for ((count=0;$count&gt;=0;count=$count+1))
do
if (($count&gt;=5));then
break;
fi
echo $count
done
</code></pre>
<h1>12. 输入输出重定向</h1>
<h2>12.1. 输出重定向</h2>
<p><code>command &gt; file</code>将命令输出结果保存的file文件中。<code>&gt;</code>从文件头开始写,会覆盖旧内容,<code>&gt;&gt;</code>将内容追加到文件末尾</p>
<pre><code class="language-shell"># 将who命令的输出保存的users文件中,可以通过cat users查看
who &gt; users
# 将字符串hello world保存到text.txt文件中
echo &quot;hello world&quot; &gt; text.txt
</code></pre>
<h2>12.2. 输入重定向</h2>
<p><code>command &lt; file</code>从file文件获取输入</p>
<pre><code class="language-shell">wc -l /etc/passwd
# 123 /etc/passwd
wc -l &lt; users
# 123
# 第一个例子,会输出文件名;第二个不会,因为它仅仅知道从标准输入读取内容
# command &lt; infile &gt; outfile, 同时替换输入和输出,执行command,从文件infile读取内容,然后将输出写入到outfile中。
wc -l &lt; /etc/passwd &gt; result
cat result
# 123
</code></pre>
<h2>12.3. 文件描述符</h2>
<p>一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件</p>
<ul>
<li>标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。</li>
<li>标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。</li>
<li>标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。</li>
</ul>
<pre><code class="language-shell"># 将标准错误输出重定向到error_trace
cat /tmp/fake_file 2&gt;error_trace
cat error_trace
# cat: /tmp/fake_fule: No such file or directory
# 将标准输出和标准错误输出都重定向到result
cat /tmp/fake_file &amp;&gt;result
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准错误重定向到标准输出
ls /tmp/fake_file &gt; result 2&gt;&amp;1
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准输入重定向到result,将标准错误输出重定向到error_trace
cat /tmp/fake_file 1&gt;result 2&gt;error_trace
</code></pre>
<h2>12.4. Here Document</h2>
<p>将两个<code>EOF</code>之间的内容(document) 作为输入传递给<code>command</code></p>
<pre><code class="language-bash"># command &lt;&lt; EOF
# document
# EOF
cat &lt;&lt; EOF
hello
shinerio
learn shell
EOF
</code></pre>
<blockquote>
<p>结尾的<code>EOF</code>一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和<code>tab</code>缩进。开始的<code>EOF</code>前后的空格会被忽略掉。</p>
</blockquote>
<h2>12.5. /dev/null</h2>
<p>如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null。<code>command &gt; /dev/null</code></p>
<pre><code class="language-shell">cat users &gt; /dev/null
cat users &gt; /dev/null 2&gt;&amp;1
</code></pre>
<h1>13. set命令</h1>
<p>set指令能设置所使用shell的执行方式,可依照不同的需求来做设置。以下只列出常用的选项参数:</p>
<ul>
<li>-e 若指令传回值不等于0,则立即退出shell。</li>
<li>-f 取消使用通配符。</li>
<li>-n 只读取指令,而不实际执行。</li>
<li>-x 执行指令后,会先显示该指令及所下的参数。</li>
</ul>
#39;hello' ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ 'hello' = 'hello' ];then echo 'hello';fi
# hello
if [ 'hello' != 'ello' ];then echo 'hello';fi
# hello
if [ -z '' ];then echo 'hello';fi
# hello
if [ -n 'hello' ];then echo 'hello';fi
# hello
if [ <p>本文主要介绍shell编程的基本语法以及实际应用中的常见命令。</p>
<h1>1. 注释</h1>
<h2>1.1. 单行注释</h2>
<pre><code class="language-shell"># 这是单行注释
</code></pre>
<h2>1.2. 多行注释</h2>
<pre><code class="language-shell">:&lt;&lt;EOF
多行注释内容
多行注释内容
多行注释内容
EOF
</code></pre>
<p>多行注释<code>EOF</code>也可替换成<code>!</code>或<code>&#39;</code></p>
<pre><code class="language-shell">:&lt;&lt;&#39;
多行注释内容
多行注释内容
多行注释内容
&#39;
:&lt;&lt;!
多行注释内容
多行注释内容
多行注释内容
!
</code></pre>
<h1>2. 变量</h1>
<h2>2.1. 变量定义</h2>
<p>使用<code>VARIABLENAME=VALUE</code>的形式,VALUE如果是字符串的话,可以使用单引号、双引号或者不加引号。单引号内的任何字符都会原样输出,不能进行转义,单引号内不能单独出现一个单引号,但可成对出现,作为字符串拼接使用。双引号内可以有变量,可以出现转义字符。</p>
<h2>2.2. 变量使用</h2>
<p>只需要在变量前加<code>$</code>符号,变量加<code>{}</code>是可选的,方便解释器识别边界。将变量加上<code>{}</code>是一个好习惯,不容易出错。</p>
<pre><code class="language-shell">your_age=25
your_name=&quot;shinerio&quot;
your_name=shinerio
your_name=&#39;shinerio&#39;
echo $your_age # 输出25
echo $your_name # 输出shinerio
echo &quot;${your_name}hello&quot; &lt;span class=&quot;tag&quot;&gt;#这里&lt;/span&gt;{}必须添加,否则解释器认为是${your_namehello}
str=&#39;hello&#39;&#39; # 非法
str=&#39;hello&#39;__&#39;world&#39; # 成对出现的单引号做字符拼接
echo $str &lt;span class=&quot;tag&quot;&gt;#输出hello__world&lt;/span&gt;
str1=&#39;helloworld${your_age}\nnew line&#39;
str2=&quot;helloworld${your_age}\nnew line&quot;
echo $str1 # 输出helloworld${your_age}\nnew line
echo $str2 # 输出helloworld25\nnew line
echo -e $str2 # -e开启转义 \n表示换行 echo默认换行,通过\c强制不换行
&lt;span class=&quot;tag&quot;&gt;#helloworld25&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;#new&lt;/span&gt; line
</code></pre>
<h2>2.3. 只读变量</h2>
<p>使用<code>readonly VARIABLENAME</code>设置变量只读,只读变量的值不能更改</p>
<pre><code class="language-shell">readonly name=&#39;jack&#39;
name=&#39;kelly&#39;
zsh: read-only variable: name
</code></pre>
<h2>2.4. 删除变量</h2>
<p>使用<code>unset VARIABLENAME</code>删除变量。</p>
<h1>3. 字符串操作</h1>
<h2>3.1. 字符串拼接</h2>
<pre><code class="language-shell">str1=&quot;hello&quot;${your_name}&quot;world&quot;
str2=&quot;hello${your_name}world&quot;
str3=&#39;hello&#39;${your_name}&#39;world&#39;
</code></pre>
<h2>3.2. 字符串长度</h2>
<pre><code class="language-shell">str=&#39;hello&#39;
echo ${&lt;span class=&quot;tag&quot;&gt;#str&lt;/span&gt;}
5
</code></pre>
<h2>3.3. 字符串截取</h2>
<p><code>${string:start:length}</code>,索引从0开始,从start(包含)开始截取共计length长度的字符。</p>
<pre><code class="language-shell">str=&#39;helloworld&#39;
echo ${str:0:5}
hello
</code></pre>
<h2>3.4. 字符串运算符</h2>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>=</code></td>
<td>检测两个字符串是否相等,相等返回true</td>
<td><code>[ &#39;hello&#39; = &#39;hello&#39; ]</code></td>
</tr>
<tr>
<td><code>!=</code></td>
<td>检测两个字符串是否相等,不相等返回true</td>
<td><code>[ &#39;hello&#39; != &#39;ello&#39; ]</code></td>
</tr>
<tr>
<td><code>-z</code></td>
<td>检测字符串长度是否为0,为0返回true</td>
<td><code>[ -z &#39;&#39; ]</code></td>
</tr>
<tr>
<td><code>-n </code></td>
<td>检测字符串长度是否不为0,不为0返回true</td>
<td><code>[ -n &#39;hello&#39; ]</code></td>
</tr>
<tr>
<td><code>$</code></td>
<td>检测字符串是否为空,不为空返回true</td>
<td><code>[ $&#39;hello&#39; ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ &#39;hello&#39; = &#39;hello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ &#39;hello&#39; != &#39;ello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ -z &#39;&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ -n &#39;hello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ $&#39;hello&#39; ];then echo &#39;hello&#39;;fi
str=&#39;hello&#39;
if [ $str ];then echo &#39;hello&#39;;fi
# hello
</code></pre>
<p>注意字符串的等值判断是一个等号<code>&quot;=&quot;</code>,与下文要讲的逻辑运算符使用两个等号<code>&quot;==&quot;</code>做等值判断不一样。</p>
<h1>4. 文件测试运算符</h1>
<table>
<thead>
<tr>
<th>操作符</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>-b file</code></td>
<td>检测文件是否是块设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-c file</code></td>
<td>检测文件是否是字符设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-d file</code></td>
<td>检测文件是否是目录,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-f file</code></td>
<td>检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-g file</code></td>
<td>检测文件是否设置了<code>SGID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-k file</code></td>
<td>检测文件是否设置了粘着位(Sticky Bit),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-p file</code></td>
<td>检测文件是否是有名管道,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-u file</code></td>
<td>检测文件是否设置了<code>SUID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-r file</code></td>
<td>检测文件是否可读,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-w file</code></td>
<td>检测文件是否可写,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-x file</code></td>
<td>检测文件是否可执行,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-s file</code></td>
<td>检测文件是否为空(文件大小是否大于0),不为空返回true。</td>
</tr>
<tr>
<td><code>-e file</code></td>
<td>检测文件(包括目录)是否存在,如果是,则返回true。</td>
</tr>
</tbody></table>
<pre><code class="language-shell">if &lt;a href=&quot;f-home.html&quot; class=&quot;internal-link&quot;&gt; -f &#39;/home&#39; &lt;/a&gt;;then echo &#39;directory&#39;;else echo &#39;file&#39;;fi
# file
if &lt;a href=&quot;d-home.html&quot; class=&quot;internal-link&quot;&gt; -d &#39;/home&#39; &lt;/a&gt;;then echo &#39;directory&#39;;else echo &#39;file&#39;;fi
# directory
if &lt;a href=&quot;e-tmpfake-file.html&quot; class=&quot;internal-link&quot;&gt; -e &#39;/tmp/fake_file&#39; &lt;/a&gt;;then echo &#39;exist&#39;;else echo &#39;not exist&#39;;fi
# not exist
</code></pre>
<h1>5. 数组</h1>
<p><code>shell</code>只支持一维数组,用括号表示,元素通过空格分隔,形如<code>数组名=(值1 值2 ... 值n)</code>。<code>shell</code>数组下标从<code>1</code>开始。</p>
<ul>
<li><code>${数组名[下标]}</code>,读取指索引位置数组元素</li>
<li>使用<code>@</code>或<code>*</code>代替下标,获取数组中所有元素。</li>
<li>使用<code>{&lt;span class=&quot;tag&quot;&gt;#数组名&lt;/span&gt;[@]}</code>或<code>{&lt;span class=&quot;tag&quot;&gt;#数组名&lt;/span&gt;[*]}</code>获取数组元素个数。</li>
</ul>
<pre><code class="language-shell">arr=(value1 value2 value3 value4)
echo ${arr[3]}
# value3
echo ${arr[*]}
# value1 value2 value3 value4
echo ${arr[@]}
# value1 value2 value3 value4
arr[3]=&#39;new_value3&#39;
echo $arr[3]
# new_value3
echo ${&lt;span class=&quot;tag&quot;&gt;#arr&lt;/span&gt;[@]}
# 4
echo &quot;arr[1]的长度为:${&lt;span class=&quot;tag&quot;&gt;#arr&lt;/span&gt;[1]}&quot;
# arr[1]的长度为:6
</code></pre>
<h1>6. 运算符</h1>
<h2>6.1. 赋值运算符</h2>
<pre><code class="language-shell">a=10
b=$a
</code></pre>
<h2>6.2. 算术运算符</h2>
<p>算数运算符支持<code>+,-,*,/,%</code></p>
<h3>6.2.1. expr表示法</h3>
<pre><code class="language-shell">echo `expr 10 + 20`
# 30
echo $(expr 20 / 2)
# 10
echo $(expr 10 \* 20) # 使用expr进行乘法运算时必须使用\进行转义
# 200
</code></pre>
<blockquote>
<p>使用expr表示方法时,表达式和运算符之间必须有空格。</p>
</blockquote>
<h3>6.2.2. <code>$[]</code></h3>
<pre><code class="language-shell">echo $[10%3]
# 1
</code></pre>
<h3>6.2.3. <code>$(())</code></h3>
<pre><code class="language-shell">echo $((10*20))
# 200
</code></pre>
<h2>6.3. 关系运算符</h2>
<p>最常见的关系运算符是:<code>==,!=,&lt;,&gt;,&gt;=,&lt;=</code></p>
<pre><code class="language-shell">echo $[10==10]
# 1
flag=$[20==10]
echo $flag
# 1
echo $[10&gt;=10]
# 1
</code></pre>
<p>如下关系运算符只能使用在条件表达式<code>if、while</code>下,类似<code>flag=[ $a -eq $b ]</code>的直接赋值语句是非法的。关系运算符的条件表达式要放在<strong>一对</strong>方括号中,并且中间需要有空格。也可以使用<code>(())</code>替代<code>[]</code>,此时<code>-eq,-lt,-le</code>之类的需要使用<code>==,&lt;,&lt;=</code>等替换。</p>
<blockquote>
<p><code>[]</code>搭配<code>-eq -ne</code>等使用,<code>(())</code>搭配<code>|| &amp;&amp;</code>等使用。</p>
</blockquote>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>-eq</code></td>
<td>检测两个数是否相等,相等返回true。</td>
<td><code>[ $a -eq $b ]</code></td>
</tr>
<tr>
<td><code>-ne</code></td>
<td>检测两个数是否不相等,不相等返回 true。</td>
<td><code>[ $a -ne $b ]</code></td>
</tr>
<tr>
<td><code>-gt</code></td>
<td>检测左边的数是否大于右边的,如果是,则返回 true。</td>
<td><code>[ $a -gt $b ]</code></td>
</tr>
<tr>
<td><code>-lt</code></td>
<td>检测左边的数是否小于右边的,如果是,则返回 true。</td>
<td><code>[ $a -lt $b ]</code></td>
</tr>
<tr>
<td><code>-ge</code></td>
<td>检测左边的数是否大于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -ge $b ]</code></td>
</tr>
<tr>
<td><code>-le</code></td>
<td>检测左边的数是否小于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -le $b ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ 1 -eq 1 ];then echo &#39;hello&#39;;fi;
# hello
if ((10&gt;=10));then echo &#39;hello&#39;;fi;
# hello
</code></pre>
<h2>6.4. 布尔、逻辑运算符</h2>
<p>布尔、逻辑运算的条件表达式也要放在一对方括号中<code>[]</code>。</p>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>!</code></td>
<td>非运算,表达式为true则返回false,否则返回true。</td>
<td><code>[ ! 10 -eq 0 ]</code></td>
</tr>
<tr>
<td><code>-o</code></td>
<td>或运算,有一个表达式为true则返回true。</td>
<td><code>[ 10 -lt 20 -o 10 -gt 100 ]</code></td>
</tr>
<tr>
<td><code>-a</code></td>
<td>与运算,两个表达式都为true才返回true。</td>
<td><code>[ 10 -lt 20 -a 10 -gt 100 ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ ! 10 -eq 0 ];then echo &#39;hello&#39;;fi
# hello
if [ 10 -ge 10 -a 10 -ge 10 ];then echo &#39;hello&#39;;fi
# hello
if [ 10 -ge 20 -o 10 -ge 0 ];then echo &#39;hello&#39;;fi
# hello
</code></pre>
<p> <code>-o</code>也可以使用<code>||</code>替代,<code>-a</code>也可以使用<code>&amp;&amp;</code>替代,此时需要使用<code>(())</code>或<code>[[]]</code>替代<code>[]</code>。</p>
<pre><code class="language-shell">if &lt;a href=&quot;1010-55.html&quot; class=&quot;internal-link&quot;&gt; 10==10 &amp;&amp; 5==5 &lt;/a&gt;;then echo &#39;hello&#39;;fi
# hello
if ((10==10 &amp;&amp; 5==5));then echo &#39;hello&#39;;fi
# hello
</code></pre>
<h1>7. 传递参数</h1>
<p>在执行 <code>Shell</code>脚本时,向脚本传递参数,脚本内获取参数的格式为:<code>$n</code>。<code>n</code>代表一个数字,<code>1</code>为执行脚本的第一个参数,<code>2</code>为执行脚本的第二个参数,<code>$0</code>为执行的文件名。在为<code>shell</code>脚本传递的参数中如果包含空格,应该使用单引号或者双引号将该参数括起来,以便于脚本将这个参数作为整体来接收。另外,还有几个特殊字符用来处理参数:</p>
<table>
<thead>
<tr>
<th>参数处理</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>$#</code></td>
<td>传递到脚本的参数个数</td>
</tr>
<tr>
<td><code>$*</code></td>
<td>以一个单字符串显示所有向脚本传递的参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$$</code></td>
<td>脚本运行的当前进程ID号</td>
</tr>
<tr>
<td><code>$!</code></td>
<td>后台运行的最后一个进程的ID号</td>
</tr>
<tr>
<td><code>$@</code></td>
<td>与<code>$*</code>相同,但是使用时加引号,并在引号中返回每个参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$-</code></td>
<td>显示Shell使用的当前选项,与set功能相同。</td>
</tr>
<tr>
<td><code>$?</code></td>
<td>显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。</td>
</tr>
</tbody></table>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-bash">set -e
echo &quot;执行的文件名:$0&quot;
echo &quot;参数个数为$#&quot;
echo &quot;第一个参数为:$1&quot;
echo &quot;第二个参数为:$2&quot;
echo &quot;所有参数为:$@&quot;
echo &quot;进程ID号为:$$&quot;
echo &quot;当前shell选项为$-&quot;
echo &quot;上一个命令退出的状态为$?&quot;
</code></pre>
<p>执行结果如下:</p>
<pre><code class="language-shell">$ sh test.sh param1 &quot;param2 with space&quot;
执行的文件名:test.sh
参数个数为2
第一个参数为:param1
第二个参数为:param2 with space
所有参数为:param1 param2 with space
进程ID号为:3700
当前shell选项为ehB
上一个命令退出的状态为0
</code></pre>
<h1>8. 函数</h1>
<p>函数定义通过<code>function_name(){}</code>的形式定义,函数返回值可以显示用return返回,如果不加,将以最后一条命令的运行结果作为返回值,函数返回值只能是数字。函数也可以传递参数,但是函数定义的()中不需要申明。</p>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-shell">sayhello(){
echo &quot;hello&quot;
}
# 注意函数调用只需要函数名,不需要加()
sayhello
sayhellowithparam(){
echo &quot;hello, $1 $2 $3&quot;
return 1
}
sayhellowithparam zhangsan lisi wangwu
echo $?
</code></pre>
<p>输出如下:</p>
<blockquote>
<p>hello<br>hello, zhangsan lisi wangwu<br>1</p>
</blockquote>
<h1>9. 命令替换</h1>
<p>命令替换可以将一个命令的输出作为另外一个命令的参数。</p>
<pre><code class="language-shell"># command1 `command2`
cd `pwd` # 该命令将pwd命令列出的目录作为cd命令的参数,结果仍然是停留在当前目录下
cd `echo $HOME` # 将echo的输出作为cd的参数,即打开用户根目录
</code></pre>
<h1>10. let命令</h1>
<p>let 命令是 BASH 中用于计算的工具,用于执行一个或多个表达式,变量计算中不需要加上 $ 来表示变量。如果表达式中包含了空格或其他特殊字符,则必须引起来。</p>
<ul>
<li>自加操作:<code>let no++</code></li>
<li>自减操作:<code>let no--</code></li>
<li>简写形式 <code>let no+=10</code>,<code>let no-=20</code>,分别等同于<code>let no=no+10</code>,<code>let no=no-20</code></li>
</ul>
<h1>11. 流程控制</h1>
<h2>11.1. if</h2>
<pre><code class="language-shell">if ((10&lt;2));then
echo &quot;10小于2&quot;
elif ((10&gt;20));then
echo &quot;a大于10&quot;
else
echo &quot;10大于2且小于10&quot;
fi
</code></pre>
<h2>11.2. case</h2>
<p><code>case</code>每一种情况以右括号结尾,执行到<code>;;</code>结束</p>
<pre><code class="language-shell">case 10 in
0|1)
echo &quot;a为0或1&quot;
;;
11|12)
echo &quot;a为11或12&quot;
;;
*)
# *用来匹配所有情况
echo &quot;a为10&quot;
;;
esac
</code></pre>
<h2>11.3. while</h2>
<pre><code class="language-shell">count=0
while(($count&lt;5))
do
echo $count
let count++
done
</code></pre>
<h2>11.4. util</h2>
<pre><code class="language-shell">count=0
until(($count&gt;=5))
do
echo $count
let count++
done
</code></pre>
<h2>11.5. for</h2>
<pre><code class="language-shell"># for写法1
for ((count=0;$count&lt;5;count=$count+1))
do
echo $count
done
# for写法2
arr=(0 1 2 3 4)
for count in ${arr[*]}
do
echo $int
done
# for写法3
for int in 0 1 2 3 4
do
echo $int
done
</code></pre>
<h2>11.6. break和continue</h2>
<p>用法与一般编程语言类似,break跳出循环,continue跳出当前循环</p>
<pre><code class="language-shell">for ((count=0;$count&gt;=0;count=$count+1))
do
if (($count&gt;=5));then
break;
fi
echo $count
done
</code></pre>
<h1>12. 输入输出重定向</h1>
<h2>12.1. 输出重定向</h2>
<p><code>command &gt; file</code>将命令输出结果保存的file文件中。<code>&gt;</code>从文件头开始写,会覆盖旧内容,<code>&gt;&gt;</code>将内容追加到文件末尾</p>
<pre><code class="language-shell"># 将who命令的输出保存的users文件中,可以通过cat users查看
who &gt; users
# 将字符串hello world保存到text.txt文件中
echo &quot;hello world&quot; &gt; text.txt
</code></pre>
<h2>12.2. 输入重定向</h2>
<p><code>command &lt; file</code>从file文件获取输入</p>
<pre><code class="language-shell">wc -l /etc/passwd
# 123 /etc/passwd
wc -l &lt; users
# 123
# 第一个例子,会输出文件名;第二个不会,因为它仅仅知道从标准输入读取内容
# command &lt; infile &gt; outfile, 同时替换输入和输出,执行command,从文件infile读取内容,然后将输出写入到outfile中。
wc -l &lt; /etc/passwd &gt; result
cat result
# 123
</code></pre>
<h2>12.3. 文件描述符</h2>
<p>一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件</p>
<ul>
<li>标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。</li>
<li>标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。</li>
<li>标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。</li>
</ul>
<pre><code class="language-shell"># 将标准错误输出重定向到error_trace
cat /tmp/fake_file 2&gt;error_trace
cat error_trace
# cat: /tmp/fake_fule: No such file or directory
# 将标准输出和标准错误输出都重定向到result
cat /tmp/fake_file &amp;&gt;result
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准错误重定向到标准输出
ls /tmp/fake_file &gt; result 2&gt;&amp;1
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准输入重定向到result,将标准错误输出重定向到error_trace
cat /tmp/fake_file 1&gt;result 2&gt;error_trace
</code></pre>
<h2>12.4. Here Document</h2>
<p>将两个<code>EOF</code>之间的内容(document) 作为输入传递给<code>command</code></p>
<pre><code class="language-bash"># command &lt;&lt; EOF
# document
# EOF
cat &lt;&lt; EOF
hello
shinerio
learn shell
EOF
</code></pre>
<blockquote>
<p>结尾的<code>EOF</code>一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和<code>tab</code>缩进。开始的<code>EOF</code>前后的空格会被忽略掉。</p>
</blockquote>
<h2>12.5. /dev/null</h2>
<p>如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null。<code>command &gt; /dev/null</code></p>
<pre><code class="language-shell">cat users &gt; /dev/null
cat users &gt; /dev/null 2&gt;&amp;1
</code></pre>
<h1>13. set命令</h1>
<p>set指令能设置所使用shell的执行方式,可依照不同的需求来做设置。以下只列出常用的选项参数:</p>
<ul>
<li>-e 若指令传回值不等于0,则立即退出shell。</li>
<li>-f 取消使用通配符。</li>
<li>-n 只读取指令,而不实际执行。</li>
<li>-x 执行指令后,会先显示该指令及所下的参数。</li>
</ul>
#39;hello' ];then echo 'hello';fi
str='hello'
if [ $str ];then echo 'hello';fi
# hello
</code></pre>
<p>注意字符串的等值判断是一个等号<code>"="</code>,与下文要讲的逻辑运算符使用两个等号<code>"=="</code>做等值判断不一样。</p>
<h1>4. 文件测试运算符</h1>
<table>
<thead>
<tr>
<th>操作符</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>-b file</code></td>
<td>检测文件是否是块设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-c file</code></td>
<td>检测文件是否是字符设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-d file</code></td>
<td>检测文件是否是目录,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-f file</code></td>
<td>检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-g file</code></td>
<td>检测文件是否设置了<code>SGID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-k file</code></td>
<td>检测文件是否设置了粘着位(Sticky Bit),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-p file</code></td>
<td>检测文件是否是有名管道,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-u file</code></td>
<td>检测文件是否设置了<code>SUID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-r file</code></td>
<td>检测文件是否可读,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-w file</code></td>
<td>检测文件是否可写,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-x file</code></td>
<td>检测文件是否可执行,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-s file</code></td>
<td>检测文件是否为空(文件大小是否大于0),不为空返回true。</td>
</tr>
<tr>
<td><code>-e file</code></td>
<td>检测文件(包括目录)是否存在,如果是,则返回true。</td>
</tr>
</tbody></table>
<pre><code class="language-shell">if <a href="f-home.html" class="internal-link"> -f '/home' </a>;then echo 'directory';else echo 'file';fi
# file
if <a href="d-home.html" class="internal-link"> -d '/home' </a>;then echo 'directory';else echo 'file';fi
# directory
if <a href="e-tmpfake-file.html" class="internal-link"> -e '/tmp/fake_file' </a>;then echo 'exist';else echo 'not exist';fi
# not exist
</code></pre>
<h1>5. 数组</h1>
<p><code>shell</code>只支持一维数组,用括号表示,元素通过空格分隔,形如<code>数组名=(值1 值2 ... 值n)</code>。<code>shell</code>数组下标从<code>1</code>开始。</p>
<ul>
<li><code>${数组名[下标]}</code>,读取指索引位置数组元素</li>
<li>使用<code>@</code>或<code>*</code>代替下标,获取数组中所有元素。</li>
<li>使用<code>{<span class="tag">#数组名</span>[@]}</code>或<code>{<span class="tag">#数组名</span>[*]}</code>获取数组元素个数。</li>
</ul>
<pre><code class="language-shell">arr=(value1 value2 value3 value4)
echo ${arr[3]}
# value3
echo ${arr[*]}
# value1 value2 value3 value4
echo ${arr[@]}
# value1 value2 value3 value4
arr[3]='new_value3'
echo $arr[3]
# new_value3
echo ${<span class="tag">#arr</span>[@]}
# 4
echo "arr[1]的长度为:${<span class="tag">#arr</span>[1]}"
# arr[1]的长度为:6
</code></pre>
<h1>6. 运算符</h1>
<h2>6.1. 赋值运算符</h2>
<pre><code class="language-shell">a=10
b=$a
</code></pre>
<h2>6.2. 算术运算符</h2>
<p>算数运算符支持<code>+,-,*,/,%</code></p>
<h3>6.2.1. expr表示法</h3>
<pre><code class="language-shell">echo `expr 10 + 20`
# 30
echo $(expr 20 / 2)
# 10
echo $(expr 10 \* 20) # 使用expr进行乘法运算时必须使用\进行转义
# 200
</code></pre>
<blockquote>
<p>使用expr表示方法时,表达式和运算符之间必须有空格。</p>
</blockquote>
<h3>6.2.2. <code>$[]</code></h3>
<pre><code class="language-shell">echo $[10%3]
# 1
</code></pre>
<h3>6.2.3. <code>$(())</code></h3>
<pre><code class="language-shell">echo $((10*20))
# 200
</code></pre>
<h2>6.3. 关系运算符</h2>
<p>最常见的关系运算符是:<code>==,!=,<,>,>=,<=</code></p>
<pre><code class="language-shell">echo $[10==10]
# 1
flag=$[20==10]
echo $flag
# 1
echo $[10>=10]
# 1
</code></pre>
<p>如下关系运算符只能使用在条件表达式<code>if、while</code>下,类似<code>flag=[ $a -eq $b ]</code>的直接赋值语句是非法的。关系运算符的条件表达式要放在<strong>一对</strong>方括号中,并且中间需要有空格。也可以使用<code>(())</code>替代<code>[]</code>,此时<code>-eq,-lt,-le</code>之类的需要使用<code>==,<,<=</code>等替换。</p>
<blockquote>
<p><code>[]</code>搭配<code>-eq -ne</code>等使用,<code>(())</code>搭配<code>|| &&</code>等使用。</p>
</blockquote>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>-eq</code></td>
<td>检测两个数是否相等,相等返回true。</td>
<td><code>[ $a -eq $b ]</code></td>
</tr>
<tr>
<td><code>-ne</code></td>
<td>检测两个数是否不相等,不相等返回 true。</td>
<td><code>[ $a -ne $b ]</code></td>
</tr>
<tr>
<td><code>-gt</code></td>
<td>检测左边的数是否大于右边的,如果是,则返回 true。</td>
<td><code>[ $a -gt $b ]</code></td>
</tr>
<tr>
<td><code>-lt</code></td>
<td>检测左边的数是否小于右边的,如果是,则返回 true。</td>
<td><code>[ $a -lt $b ]</code></td>
</tr>
<tr>
<td><code>-ge</code></td>
<td>检测左边的数是否大于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -ge $b ]</code></td>
</tr>
<tr>
<td><code>-le</code></td>
<td>检测左边的数是否小于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -le $b ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ 1 -eq 1 ];then echo 'hello';fi;
# hello
if ((10>=10));then echo 'hello';fi;
# hello
</code></pre>
<h2>6.4. 布尔、逻辑运算符</h2>
<p>布尔、逻辑运算的条件表达式也要放在一对方括号中<code>[]</code>。</p>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>!</code></td>
<td>非运算,表达式为true则返回false,否则返回true。</td>
<td><code>[ ! 10 -eq 0 ]</code></td>
</tr>
<tr>
<td><code>-o</code></td>
<td>或运算,有一个表达式为true则返回true。</td>
<td><code>[ 10 -lt 20 -o 10 -gt 100 ]</code></td>
</tr>
<tr>
<td><code>-a</code></td>
<td>与运算,两个表达式都为true才返回true。</td>
<td><code>[ 10 -lt 20 -a 10 -gt 100 ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ ! 10 -eq 0 ];then echo 'hello';fi
# hello
if [ 10 -ge 10 -a 10 -ge 10 ];then echo 'hello';fi
# hello
if [ 10 -ge 20 -o 10 -ge 0 ];then echo 'hello';fi
# hello
</code></pre>
<p> <code>-o</code>也可以使用<code>||</code>替代,<code>-a</code>也可以使用<code>&&</code>替代,此时需要使用<code>(())</code>或<code>[[]]</code>替代<code>[]</code>。</p>
<pre><code class="language-shell">if <a href="1010-55.html" class="internal-link"> 10==10 && 5==5 </a>;then echo 'hello';fi
# hello
if ((10==10 && 5==5));then echo 'hello';fi
# hello
</code></pre>
<h1>7. 传递参数</h1>
<p>在执行 <code>Shell</code>脚本时,向脚本传递参数,脚本内获取参数的格式为:<code>$n</code>。<code>n</code>代表一个数字,<code>1</code>为执行脚本的第一个参数,<code>2</code>为执行脚本的第二个参数,<code>$0</code>为执行的文件名。在为<code>shell</code>脚本传递的参数中如果包含空格,应该使用单引号或者双引号将该参数括起来,以便于脚本将这个参数作为整体来接收。另外,还有几个特殊字符用来处理参数:</p>
<table>
<thead>
<tr>
<th>参数处理</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>$#</code></td>
<td>传递到脚本的参数个数</td>
</tr>
<tr>
<td><code>$*</code></td>
<td>以一个单字符串显示所有向脚本传递的参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$</code></td>
<td>脚本运行的当前进程ID号</td>
</tr>
<tr>
<td><code>$!</code></td>
<td>后台运行的最后一个进程的ID号</td>
</tr>
<tr>
<td><code>$@</code></td>
<td>与<code>$*</code>相同,但是使用时加引号,并在引号中返回每个参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$-</code></td>
<td>显示Shell使用的当前选项,与set功能相同。</td>
</tr>
<tr>
<td><code>$?</code></td>
<td>显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。</td>
</tr>
</tbody></table>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-bash">set -e
echo "执行的文件名:$0"
echo "参数个数为$#"
echo "第一个参数为:$1"
echo "第二个参数为:$2"
echo "所有参数为:$@"
echo "进程ID号为:$"
echo "当前shell选项为$-"
echo "上一个命令退出的状态为$?"
</code></pre>
<p>执行结果如下:</p>
<pre><code class="language-shell">$ sh test.sh param1 "param2 with space"
执行的文件名:test.sh
参数个数为2
第一个参数为:param1
第二个参数为:param2 with space
所有参数为:param1 param2 with space
进程ID号为:3700
当前shell选项为ehB
上一个命令退出的状态为0
</code></pre>
<h1>8. 函数</h1>
<p>函数定义通过<code>function_name(){}</code>的形式定义,函数返回值可以显示用return返回,如果不加,将以最后一条命令的运行结果作为返回值,函数返回值只能是数字。函数也可以传递参数,但是函数定义的()中不需要申明。</p>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-shell">sayhello(){
echo "hello"
}
# 注意函数调用只需要函数名,不需要加()
sayhello
sayhellowithparam(){
echo "hello, $1 $2 $3"
return 1
}
sayhellowithparam zhangsan lisi wangwu
echo $?
</code></pre>
<p>输出如下:</p>
<blockquote>
<p>hello<br>hello, zhangsan lisi wangwu<br>1</p>
</blockquote>
<h1>9. 命令替换</h1>
<p>命令替换可以将一个命令的输出作为另外一个命令的参数。</p>
<pre><code class="language-shell"># command1 `command2`
cd `pwd` # 该命令将pwd命令列出的目录作为cd命令的参数,结果仍然是停留在当前目录下
cd `echo $HOME` # 将echo的输出作为cd的参数,即打开用户根目录
</code></pre>
<h1>10. let命令</h1>
<p>let 命令是 BASH 中用于计算的工具,用于执行一个或多个表达式,变量计算中不需要加上 $ 来表示变量。如果表达式中包含了空格或其他特殊字符,则必须引起来。</p>
<ul>
<li>自加操作:<code>let no++</code></li>
<li>自减操作:<code>let no--</code></li>
<li>简写形式 <code>let no+=10</code>,<code>let no-=20</code>,分别等同于<code>let no=no+10</code>,<code>let no=no-20</code></li>
</ul>
<h1>11. 流程控制</h1>
<h2>11.1. if</h2>
<pre><code class="language-shell">if ((10<2));then
echo "10小于2"
elif ((10>20));then
echo "a大于10"
else
echo "10大于2且小于10"
fi
</code></pre>
<h2>11.2. case</h2>
<p><code>case</code>每一种情况以右括号结尾,执行到<code>;;</code>结束</p>
<pre><code class="language-shell">case 10 in
0|1)
echo "a为0或1"
;;
11|12)
echo "a为11或12"
;;
*)
# *用来匹配所有情况
echo "a为10"
;;
esac
</code></pre>
<h2>11.3. while</h2>
<pre><code class="language-shell">count=0
while(($count<5))
do
echo $count
let count++
done
</code></pre>
<h2>11.4. util</h2>
<pre><code class="language-shell">count=0
until(($count>=5))
do
echo $count
let count++
done
</code></pre>
<h2>11.5. for</h2>
<pre><code class="language-shell"># for写法1
for ((count=0;$count<5;count=$count+1))
do
echo $count
done
# for写法2
arr=(0 1 2 3 4)
for count in ${arr[*]}
do
echo $int
done
# for写法3
for int in 0 1 2 3 4
do
echo $int
done
</code></pre>
<h2>11.6. break和continue</h2>
<p>用法与一般编程语言类似,break跳出循环,continue跳出当前循环</p>
<pre><code class="language-shell">for ((count=0;$count>=0;count=$count+1))
do
if (($count>=5));then
break;
fi
echo $count
done
</code></pre>
<h1>12. 输入输出重定向</h1>
<h2>12.1. 输出重定向</h2>
<p><code>command > file</code>将命令输出结果保存的file文件中。<code>></code>从文件头开始写,会覆盖旧内容,<code>>></code>将内容追加到文件末尾</p>
<pre><code class="language-shell"># 将who命令的输出保存的users文件中,可以通过cat users查看
who > users
# 将字符串hello world保存到text.txt文件中
echo "hello world" > text.txt
</code></pre>
<h2>12.2. 输入重定向</h2>
<p><code>command < file</code>从file文件获取输入</p>
<pre><code class="language-shell">wc -l /etc/passwd
# 123 /etc/passwd
wc -l < users
# 123
# 第一个例子,会输出文件名;第二个不会,因为它仅仅知道从标准输入读取内容
# command < infile > outfile, 同时替换输入和输出,执行command,从文件infile读取内容,然后将输出写入到outfile中。
wc -l < /etc/passwd > result
cat result
# 123
</code></pre>
<h2>12.3. 文件描述符</h2>
<p>一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件</p>
<ul>
<li>标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。</li>
<li>标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。</li>
<li>标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。</li>
</ul>
<pre><code class="language-shell"># 将标准错误输出重定向到error_trace
cat /tmp/fake_file 2>error_trace
cat error_trace
# cat: /tmp/fake_fule: No such file or directory
# 将标准输出和标准错误输出都重定向到result
cat /tmp/fake_file &>result
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准错误重定向到标准输出
ls /tmp/fake_file > result 2>&1
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准输入重定向到result,将标准错误输出重定向到error_trace
cat /tmp/fake_file 1>result 2>error_trace
</code></pre>
<h2>12.4. Here Document</h2>
<p>将两个<code>EOF</code>之间的内容(document) 作为输入传递给<code>command</code></p>
<pre><code class="language-bash"># command << EOF
# document
# EOF
cat << EOF
hello
shinerio
learn shell
EOF
</code></pre>
<blockquote>
<p>结尾的<code>EOF</code>一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和<code>tab</code>缩进。开始的<code>EOF</code>前后的空格会被忽略掉。</p>
</blockquote>
<h2>12.5. /dev/null</h2>
<p>如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null。<code>command > /dev/null</code></p>
<pre><code class="language-shell">cat users > /dev/null
cat users > /dev/null 2>&1
</code></pre>
<h1>13. set命令</h1>
<p>set指令能设置所使用shell的执行方式,可依照不同的需求来做设置。以下只列出常用的选项参数:</p>
<ul>
<li>-e 若指令传回值不等于0,则立即退出shell。</li>
<li>-f 取消使用通配符。</li>
<li>-n 只读取指令,而不实际执行。</li>
<li>-x 执行指令后,会先显示该指令及所下的参数。</li>
</ul>
</section>
</article>lt;/code></td>
<td>检测字符串是否为空,不为空返回true</td>
<td><code>[ <article>
<header>
<h1>shell编程</h1>
<time datetime="2023-01-24T00:00:00.000Z">2023年1月24日</time>
<div class="tags">
<span class="tag">linux</span>
</div>
</header>
<section class="content">
<p>本文主要介绍shell编程的基本语法以及实际应用中的常见命令。</p>
<h1>1. 注释</h1>
<h2>1.1. 单行注释</h2>
<pre><code class="language-shell"># 这是单行注释
</code></pre>
<h2>1.2. 多行注释</h2>
<pre><code class="language-shell">:<<EOF
多行注释内容
多行注释内容
多行注释内容
EOF
</code></pre>
<p>多行注释<code>EOF</code>也可替换成<code>!</code>或<code>'</code></p>
<pre><code class="language-shell">:<<'
多行注释内容
多行注释内容
多行注释内容
'
:<<!
多行注释内容
多行注释内容
多行注释内容
!
</code></pre>
<h1>2. 变量</h1>
<h2>2.1. 变量定义</h2>
<p>使用<code>VARIABLENAME=VALUE</code>的形式,VALUE如果是字符串的话,可以使用单引号、双引号或者不加引号。单引号内的任何字符都会原样输出,不能进行转义,单引号内不能单独出现一个单引号,但可成对出现,作为字符串拼接使用。双引号内可以有变量,可以出现转义字符。</p>
<h2>2.2. 变量使用</h2>
<p>只需要在变量前加<code>$</code>符号,变量加<code>{}</code>是可选的,方便解释器识别边界。将变量加上<code>{}</code>是一个好习惯,不容易出错。</p>
<pre><code class="language-shell">your_age=25
your_name="shinerio"
your_name=shinerio
your_name='shinerio'
echo $your_age # 输出25
echo $your_name # 输出shinerio
echo "${your_name}hello" <span class="tag">#这里</span>{}必须添加,否则解释器认为是${your_namehello}
str='hello'' # 非法
str='hello'__'world' # 成对出现的单引号做字符拼接
echo $str <span class="tag">#输出hello__world</span>
str1='helloworld${your_age}\nnew line'
str2="helloworld${your_age}\nnew line"
echo $str1 # 输出helloworld${your_age}\nnew line
echo $str2 # 输出helloworld25\nnew line
echo -e $str2 # -e开启转义 \n表示换行 echo默认换行,通过\c强制不换行
<span class="tag">#helloworld25</span>
<span class="tag">#new</span> line
</code></pre>
<h2>2.3. 只读变量</h2>
<p>使用<code>readonly VARIABLENAME</code>设置变量只读,只读变量的值不能更改</p>
<pre><code class="language-shell">readonly name='jack'
name='kelly'
zsh: read-only variable: name
</code></pre>
<h2>2.4. 删除变量</h2>
<p>使用<code>unset VARIABLENAME</code>删除变量。</p>
<h1>3. 字符串操作</h1>
<h2>3.1. 字符串拼接</h2>
<pre><code class="language-shell">str1="hello"${your_name}"world"
str2="hello${your_name}world"
str3='hello'${your_name}'world'
</code></pre>
<h2>3.2. 字符串长度</h2>
<pre><code class="language-shell">str='hello'
echo ${<span class="tag">#str</span>}
5
</code></pre>
<h2>3.3. 字符串截取</h2>
<p><code>${string:start:length}</code>,索引从0开始,从start(包含)开始截取共计length长度的字符。</p>
<pre><code class="language-shell">str='helloworld'
echo ${str:0:5}
hello
</code></pre>
<h2>3.4. 字符串运算符</h2>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>=</code></td>
<td>检测两个字符串是否相等,相等返回true</td>
<td><code>[ 'hello' = 'hello' ]</code></td>
</tr>
<tr>
<td><code>!=</code></td>
<td>检测两个字符串是否相等,不相等返回true</td>
<td><code>[ 'hello' != 'ello' ]</code></td>
</tr>
<tr>
<td><code>-z</code></td>
<td>检测字符串长度是否为0,为0返回true</td>
<td><code>[ -z '' ]</code></td>
</tr>
<tr>
<td><code>-n </code></td>
<td>检测字符串长度是否不为0,不为0返回true</td>
<td><code>[ -n 'hello' ]</code></td>
</tr>
<tr>
<td><code>$</code></td>
<td>检测字符串是否为空,不为空返回true</td>
<td><code>[ <p>本文主要介绍shell编程的基本语法以及实际应用中的常见命令。</p>
<h1>1. 注释</h1>
<h2>1.1. 单行注释</h2>
<pre><code class="language-shell"># 这是单行注释
</code></pre>
<h2>1.2. 多行注释</h2>
<pre><code class="language-shell">:&lt;&lt;EOF
多行注释内容
多行注释内容
多行注释内容
EOF
</code></pre>
<p>多行注释<code>EOF</code>也可替换成<code>!</code>或<code>&#39;</code></p>
<pre><code class="language-shell">:&lt;&lt;&#39;
多行注释内容
多行注释内容
多行注释内容
&#39;
:&lt;&lt;!
多行注释内容
多行注释内容
多行注释内容
!
</code></pre>
<h1>2. 变量</h1>
<h2>2.1. 变量定义</h2>
<p>使用<code>VARIABLENAME=VALUE</code>的形式,VALUE如果是字符串的话,可以使用单引号、双引号或者不加引号。单引号内的任何字符都会原样输出,不能进行转义,单引号内不能单独出现一个单引号,但可成对出现,作为字符串拼接使用。双引号内可以有变量,可以出现转义字符。</p>
<h2>2.2. 变量使用</h2>
<p>只需要在变量前加<code>$</code>符号,变量加<code>{}</code>是可选的,方便解释器识别边界。将变量加上<code>{}</code>是一个好习惯,不容易出错。</p>
<pre><code class="language-shell">your_age=25
your_name=&quot;shinerio&quot;
your_name=shinerio
your_name=&#39;shinerio&#39;
echo $your_age # 输出25
echo $your_name # 输出shinerio
echo &quot;${your_name}hello&quot; &lt;span class=&quot;tag&quot;&gt;#这里&lt;/span&gt;{}必须添加,否则解释器认为是${your_namehello}
str=&#39;hello&#39;&#39; # 非法
str=&#39;hello&#39;__&#39;world&#39; # 成对出现的单引号做字符拼接
echo $str &lt;span class=&quot;tag&quot;&gt;#输出hello__world&lt;/span&gt;
str1=&#39;helloworld${your_age}\nnew line&#39;
str2=&quot;helloworld${your_age}\nnew line&quot;
echo $str1 # 输出helloworld${your_age}\nnew line
echo $str2 # 输出helloworld25\nnew line
echo -e $str2 # -e开启转义 \n表示换行 echo默认换行,通过\c强制不换行
&lt;span class=&quot;tag&quot;&gt;#helloworld25&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;#new&lt;/span&gt; line
</code></pre>
<h2>2.3. 只读变量</h2>
<p>使用<code>readonly VARIABLENAME</code>设置变量只读,只读变量的值不能更改</p>
<pre><code class="language-shell">readonly name=&#39;jack&#39;
name=&#39;kelly&#39;
zsh: read-only variable: name
</code></pre>
<h2>2.4. 删除变量</h2>
<p>使用<code>unset VARIABLENAME</code>删除变量。</p>
<h1>3. 字符串操作</h1>
<h2>3.1. 字符串拼接</h2>
<pre><code class="language-shell">str1=&quot;hello&quot;${your_name}&quot;world&quot;
str2=&quot;hello${your_name}world&quot;
str3=&#39;hello&#39;${your_name}&#39;world&#39;
</code></pre>
<h2>3.2. 字符串长度</h2>
<pre><code class="language-shell">str=&#39;hello&#39;
echo ${&lt;span class=&quot;tag&quot;&gt;#str&lt;/span&gt;}
5
</code></pre>
<h2>3.3. 字符串截取</h2>
<p><code>${string:start:length}</code>,索引从0开始,从start(包含)开始截取共计length长度的字符。</p>
<pre><code class="language-shell">str=&#39;helloworld&#39;
echo ${str:0:5}
hello
</code></pre>
<h2>3.4. 字符串运算符</h2>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>=</code></td>
<td>检测两个字符串是否相等,相等返回true</td>
<td><code>[ &#39;hello&#39; = &#39;hello&#39; ]</code></td>
</tr>
<tr>
<td><code>!=</code></td>
<td>检测两个字符串是否相等,不相等返回true</td>
<td><code>[ &#39;hello&#39; != &#39;ello&#39; ]</code></td>
</tr>
<tr>
<td><code>-z</code></td>
<td>检测字符串长度是否为0,为0返回true</td>
<td><code>[ -z &#39;&#39; ]</code></td>
</tr>
<tr>
<td><code>-n </code></td>
<td>检测字符串长度是否不为0,不为0返回true</td>
<td><code>[ -n &#39;hello&#39; ]</code></td>
</tr>
<tr>
<td><code>$</code></td>
<td>检测字符串是否为空,不为空返回true</td>
<td><code>[ $&#39;hello&#39; ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ &#39;hello&#39; = &#39;hello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ &#39;hello&#39; != &#39;ello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ -z &#39;&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ -n &#39;hello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ $&#39;hello&#39; ];then echo &#39;hello&#39;;fi
str=&#39;hello&#39;
if [ $str ];then echo &#39;hello&#39;;fi
# hello
</code></pre>
<p>注意字符串的等值判断是一个等号<code>&quot;=&quot;</code>,与下文要讲的逻辑运算符使用两个等号<code>&quot;==&quot;</code>做等值判断不一样。</p>
<h1>4. 文件测试运算符</h1>
<table>
<thead>
<tr>
<th>操作符</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>-b file</code></td>
<td>检测文件是否是块设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-c file</code></td>
<td>检测文件是否是字符设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-d file</code></td>
<td>检测文件是否是目录,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-f file</code></td>
<td>检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-g file</code></td>
<td>检测文件是否设置了<code>SGID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-k file</code></td>
<td>检测文件是否设置了粘着位(Sticky Bit),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-p file</code></td>
<td>检测文件是否是有名管道,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-u file</code></td>
<td>检测文件是否设置了<code>SUID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-r file</code></td>
<td>检测文件是否可读,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-w file</code></td>
<td>检测文件是否可写,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-x file</code></td>
<td>检测文件是否可执行,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-s file</code></td>
<td>检测文件是否为空(文件大小是否大于0),不为空返回true。</td>
</tr>
<tr>
<td><code>-e file</code></td>
<td>检测文件(包括目录)是否存在,如果是,则返回true。</td>
</tr>
</tbody></table>
<pre><code class="language-shell">if &lt;a href=&quot;f-home.html&quot; class=&quot;internal-link&quot;&gt; -f &#39;/home&#39; &lt;/a&gt;;then echo &#39;directory&#39;;else echo &#39;file&#39;;fi
# file
if &lt;a href=&quot;d-home.html&quot; class=&quot;internal-link&quot;&gt; -d &#39;/home&#39; &lt;/a&gt;;then echo &#39;directory&#39;;else echo &#39;file&#39;;fi
# directory
if &lt;a href=&quot;e-tmpfake-file.html&quot; class=&quot;internal-link&quot;&gt; -e &#39;/tmp/fake_file&#39; &lt;/a&gt;;then echo &#39;exist&#39;;else echo &#39;not exist&#39;;fi
# not exist
</code></pre>
<h1>5. 数组</h1>
<p><code>shell</code>只支持一维数组,用括号表示,元素通过空格分隔,形如<code>数组名=(值1 值2 ... 值n)</code>。<code>shell</code>数组下标从<code>1</code>开始。</p>
<ul>
<li><code>${数组名[下标]}</code>,读取指索引位置数组元素</li>
<li>使用<code>@</code>或<code>*</code>代替下标,获取数组中所有元素。</li>
<li>使用<code>{&lt;span class=&quot;tag&quot;&gt;#数组名&lt;/span&gt;[@]}</code>或<code>{&lt;span class=&quot;tag&quot;&gt;#数组名&lt;/span&gt;[*]}</code>获取数组元素个数。</li>
</ul>
<pre><code class="language-shell">arr=(value1 value2 value3 value4)
echo ${arr[3]}
# value3
echo ${arr[*]}
# value1 value2 value3 value4
echo ${arr[@]}
# value1 value2 value3 value4
arr[3]=&#39;new_value3&#39;
echo $arr[3]
# new_value3
echo ${&lt;span class=&quot;tag&quot;&gt;#arr&lt;/span&gt;[@]}
# 4
echo &quot;arr[1]的长度为:${&lt;span class=&quot;tag&quot;&gt;#arr&lt;/span&gt;[1]}&quot;
# arr[1]的长度为:6
</code></pre>
<h1>6. 运算符</h1>
<h2>6.1. 赋值运算符</h2>
<pre><code class="language-shell">a=10
b=$a
</code></pre>
<h2>6.2. 算术运算符</h2>
<p>算数运算符支持<code>+,-,*,/,%</code></p>
<h3>6.2.1. expr表示法</h3>
<pre><code class="language-shell">echo `expr 10 + 20`
# 30
echo $(expr 20 / 2)
# 10
echo $(expr 10 \* 20) # 使用expr进行乘法运算时必须使用\进行转义
# 200
</code></pre>
<blockquote>
<p>使用expr表示方法时,表达式和运算符之间必须有空格。</p>
</blockquote>
<h3>6.2.2. <code>$[]</code></h3>
<pre><code class="language-shell">echo $[10%3]
# 1
</code></pre>
<h3>6.2.3. <code>$(())</code></h3>
<pre><code class="language-shell">echo $((10*20))
# 200
</code></pre>
<h2>6.3. 关系运算符</h2>
<p>最常见的关系运算符是:<code>==,!=,&lt;,&gt;,&gt;=,&lt;=</code></p>
<pre><code class="language-shell">echo $[10==10]
# 1
flag=$[20==10]
echo $flag
# 1
echo $[10&gt;=10]
# 1
</code></pre>
<p>如下关系运算符只能使用在条件表达式<code>if、while</code>下,类似<code>flag=[ $a -eq $b ]</code>的直接赋值语句是非法的。关系运算符的条件表达式要放在<strong>一对</strong>方括号中,并且中间需要有空格。也可以使用<code>(())</code>替代<code>[]</code>,此时<code>-eq,-lt,-le</code>之类的需要使用<code>==,&lt;,&lt;=</code>等替换。</p>
<blockquote>
<p><code>[]</code>搭配<code>-eq -ne</code>等使用,<code>(())</code>搭配<code>|| &amp;&amp;</code>等使用。</p>
</blockquote>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>-eq</code></td>
<td>检测两个数是否相等,相等返回true。</td>
<td><code>[ $a -eq $b ]</code></td>
</tr>
<tr>
<td><code>-ne</code></td>
<td>检测两个数是否不相等,不相等返回 true。</td>
<td><code>[ $a -ne $b ]</code></td>
</tr>
<tr>
<td><code>-gt</code></td>
<td>检测左边的数是否大于右边的,如果是,则返回 true。</td>
<td><code>[ $a -gt $b ]</code></td>
</tr>
<tr>
<td><code>-lt</code></td>
<td>检测左边的数是否小于右边的,如果是,则返回 true。</td>
<td><code>[ $a -lt $b ]</code></td>
</tr>
<tr>
<td><code>-ge</code></td>
<td>检测左边的数是否大于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -ge $b ]</code></td>
</tr>
<tr>
<td><code>-le</code></td>
<td>检测左边的数是否小于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -le $b ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ 1 -eq 1 ];then echo &#39;hello&#39;;fi;
# hello
if ((10&gt;=10));then echo &#39;hello&#39;;fi;
# hello
</code></pre>
<h2>6.4. 布尔、逻辑运算符</h2>
<p>布尔、逻辑运算的条件表达式也要放在一对方括号中<code>[]</code>。</p>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>!</code></td>
<td>非运算,表达式为true则返回false,否则返回true。</td>
<td><code>[ ! 10 -eq 0 ]</code></td>
</tr>
<tr>
<td><code>-o</code></td>
<td>或运算,有一个表达式为true则返回true。</td>
<td><code>[ 10 -lt 20 -o 10 -gt 100 ]</code></td>
</tr>
<tr>
<td><code>-a</code></td>
<td>与运算,两个表达式都为true才返回true。</td>
<td><code>[ 10 -lt 20 -a 10 -gt 100 ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ ! 10 -eq 0 ];then echo &#39;hello&#39;;fi
# hello
if [ 10 -ge 10 -a 10 -ge 10 ];then echo &#39;hello&#39;;fi
# hello
if [ 10 -ge 20 -o 10 -ge 0 ];then echo &#39;hello&#39;;fi
# hello
</code></pre>
<p> <code>-o</code>也可以使用<code>||</code>替代,<code>-a</code>也可以使用<code>&amp;&amp;</code>替代,此时需要使用<code>(())</code>或<code>[[]]</code>替代<code>[]</code>。</p>
<pre><code class="language-shell">if &lt;a href=&quot;1010-55.html&quot; class=&quot;internal-link&quot;&gt; 10==10 &amp;&amp; 5==5 &lt;/a&gt;;then echo &#39;hello&#39;;fi
# hello
if ((10==10 &amp;&amp; 5==5));then echo &#39;hello&#39;;fi
# hello
</code></pre>
<h1>7. 传递参数</h1>
<p>在执行 <code>Shell</code>脚本时,向脚本传递参数,脚本内获取参数的格式为:<code>$n</code>。<code>n</code>代表一个数字,<code>1</code>为执行脚本的第一个参数,<code>2</code>为执行脚本的第二个参数,<code>$0</code>为执行的文件名。在为<code>shell</code>脚本传递的参数中如果包含空格,应该使用单引号或者双引号将该参数括起来,以便于脚本将这个参数作为整体来接收。另外,还有几个特殊字符用来处理参数:</p>
<table>
<thead>
<tr>
<th>参数处理</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>$#</code></td>
<td>传递到脚本的参数个数</td>
</tr>
<tr>
<td><code>$*</code></td>
<td>以一个单字符串显示所有向脚本传递的参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$$</code></td>
<td>脚本运行的当前进程ID号</td>
</tr>
<tr>
<td><code>$!</code></td>
<td>后台运行的最后一个进程的ID号</td>
</tr>
<tr>
<td><code>$@</code></td>
<td>与<code>$*</code>相同,但是使用时加引号,并在引号中返回每个参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$-</code></td>
<td>显示Shell使用的当前选项,与set功能相同。</td>
</tr>
<tr>
<td><code>$?</code></td>
<td>显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。</td>
</tr>
</tbody></table>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-bash">set -e
echo &quot;执行的文件名:$0&quot;
echo &quot;参数个数为$#&quot;
echo &quot;第一个参数为:$1&quot;
echo &quot;第二个参数为:$2&quot;
echo &quot;所有参数为:$@&quot;
echo &quot;进程ID号为:$$&quot;
echo &quot;当前shell选项为$-&quot;
echo &quot;上一个命令退出的状态为$?&quot;
</code></pre>
<p>执行结果如下:</p>
<pre><code class="language-shell">$ sh test.sh param1 &quot;param2 with space&quot;
执行的文件名:test.sh
参数个数为2
第一个参数为:param1
第二个参数为:param2 with space
所有参数为:param1 param2 with space
进程ID号为:3700
当前shell选项为ehB
上一个命令退出的状态为0
</code></pre>
<h1>8. 函数</h1>
<p>函数定义通过<code>function_name(){}</code>的形式定义,函数返回值可以显示用return返回,如果不加,将以最后一条命令的运行结果作为返回值,函数返回值只能是数字。函数也可以传递参数,但是函数定义的()中不需要申明。</p>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-shell">sayhello(){
echo &quot;hello&quot;
}
# 注意函数调用只需要函数名,不需要加()
sayhello
sayhellowithparam(){
echo &quot;hello, $1 $2 $3&quot;
return 1
}
sayhellowithparam zhangsan lisi wangwu
echo $?
</code></pre>
<p>输出如下:</p>
<blockquote>
<p>hello<br>hello, zhangsan lisi wangwu<br>1</p>
</blockquote>
<h1>9. 命令替换</h1>
<p>命令替换可以将一个命令的输出作为另外一个命令的参数。</p>
<pre><code class="language-shell"># command1 `command2`
cd `pwd` # 该命令将pwd命令列出的目录作为cd命令的参数,结果仍然是停留在当前目录下
cd `echo $HOME` # 将echo的输出作为cd的参数,即打开用户根目录
</code></pre>
<h1>10. let命令</h1>
<p>let 命令是 BASH 中用于计算的工具,用于执行一个或多个表达式,变量计算中不需要加上 $ 来表示变量。如果表达式中包含了空格或其他特殊字符,则必须引起来。</p>
<ul>
<li>自加操作:<code>let no++</code></li>
<li>自减操作:<code>let no--</code></li>
<li>简写形式 <code>let no+=10</code>,<code>let no-=20</code>,分别等同于<code>let no=no+10</code>,<code>let no=no-20</code></li>
</ul>
<h1>11. 流程控制</h1>
<h2>11.1. if</h2>
<pre><code class="language-shell">if ((10&lt;2));then
echo &quot;10小于2&quot;
elif ((10&gt;20));then
echo &quot;a大于10&quot;
else
echo &quot;10大于2且小于10&quot;
fi
</code></pre>
<h2>11.2. case</h2>
<p><code>case</code>每一种情况以右括号结尾,执行到<code>;;</code>结束</p>
<pre><code class="language-shell">case 10 in
0|1)
echo &quot;a为0或1&quot;
;;
11|12)
echo &quot;a为11或12&quot;
;;
*)
# *用来匹配所有情况
echo &quot;a为10&quot;
;;
esac
</code></pre>
<h2>11.3. while</h2>
<pre><code class="language-shell">count=0
while(($count&lt;5))
do
echo $count
let count++
done
</code></pre>
<h2>11.4. util</h2>
<pre><code class="language-shell">count=0
until(($count&gt;=5))
do
echo $count
let count++
done
</code></pre>
<h2>11.5. for</h2>
<pre><code class="language-shell"># for写法1
for ((count=0;$count&lt;5;count=$count+1))
do
echo $count
done
# for写法2
arr=(0 1 2 3 4)
for count in ${arr[*]}
do
echo $int
done
# for写法3
for int in 0 1 2 3 4
do
echo $int
done
</code></pre>
<h2>11.6. break和continue</h2>
<p>用法与一般编程语言类似,break跳出循环,continue跳出当前循环</p>
<pre><code class="language-shell">for ((count=0;$count&gt;=0;count=$count+1))
do
if (($count&gt;=5));then
break;
fi
echo $count
done
</code></pre>
<h1>12. 输入输出重定向</h1>
<h2>12.1. 输出重定向</h2>
<p><code>command &gt; file</code>将命令输出结果保存的file文件中。<code>&gt;</code>从文件头开始写,会覆盖旧内容,<code>&gt;&gt;</code>将内容追加到文件末尾</p>
<pre><code class="language-shell"># 将who命令的输出保存的users文件中,可以通过cat users查看
who &gt; users
# 将字符串hello world保存到text.txt文件中
echo &quot;hello world&quot; &gt; text.txt
</code></pre>
<h2>12.2. 输入重定向</h2>
<p><code>command &lt; file</code>从file文件获取输入</p>
<pre><code class="language-shell">wc -l /etc/passwd
# 123 /etc/passwd
wc -l &lt; users
# 123
# 第一个例子,会输出文件名;第二个不会,因为它仅仅知道从标准输入读取内容
# command &lt; infile &gt; outfile, 同时替换输入和输出,执行command,从文件infile读取内容,然后将输出写入到outfile中。
wc -l &lt; /etc/passwd &gt; result
cat result
# 123
</code></pre>
<h2>12.3. 文件描述符</h2>
<p>一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件</p>
<ul>
<li>标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。</li>
<li>标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。</li>
<li>标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。</li>
</ul>
<pre><code class="language-shell"># 将标准错误输出重定向到error_trace
cat /tmp/fake_file 2&gt;error_trace
cat error_trace
# cat: /tmp/fake_fule: No such file or directory
# 将标准输出和标准错误输出都重定向到result
cat /tmp/fake_file &amp;&gt;result
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准错误重定向到标准输出
ls /tmp/fake_file &gt; result 2&gt;&amp;1
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准输入重定向到result,将标准错误输出重定向到error_trace
cat /tmp/fake_file 1&gt;result 2&gt;error_trace
</code></pre>
<h2>12.4. Here Document</h2>
<p>将两个<code>EOF</code>之间的内容(document) 作为输入传递给<code>command</code></p>
<pre><code class="language-bash"># command &lt;&lt; EOF
# document
# EOF
cat &lt;&lt; EOF
hello
shinerio
learn shell
EOF
</code></pre>
<blockquote>
<p>结尾的<code>EOF</code>一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和<code>tab</code>缩进。开始的<code>EOF</code>前后的空格会被忽略掉。</p>
</blockquote>
<h2>12.5. /dev/null</h2>
<p>如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null。<code>command &gt; /dev/null</code></p>
<pre><code class="language-shell">cat users &gt; /dev/null
cat users &gt; /dev/null 2&gt;&amp;1
</code></pre>
<h1>13. set命令</h1>
<p>set指令能设置所使用shell的执行方式,可依照不同的需求来做设置。以下只列出常用的选项参数:</p>
<ul>
<li>-e 若指令传回值不等于0,则立即退出shell。</li>
<li>-f 取消使用通配符。</li>
<li>-n 只读取指令,而不实际执行。</li>
<li>-x 执行指令后,会先显示该指令及所下的参数。</li>
</ul>
#39;hello' ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ 'hello' = 'hello' ];then echo 'hello';fi
# hello
if [ 'hello' != 'ello' ];then echo 'hello';fi
# hello
if [ -z '' ];then echo 'hello';fi
# hello
if [ -n 'hello' ];then echo 'hello';fi
# hello
if [ <p>本文主要介绍shell编程的基本语法以及实际应用中的常见命令。</p>
<h1>1. 注释</h1>
<h2>1.1. 单行注释</h2>
<pre><code class="language-shell"># 这是单行注释
</code></pre>
<h2>1.2. 多行注释</h2>
<pre><code class="language-shell">:&lt;&lt;EOF
多行注释内容
多行注释内容
多行注释内容
EOF
</code></pre>
<p>多行注释<code>EOF</code>也可替换成<code>!</code>或<code>&#39;</code></p>
<pre><code class="language-shell">:&lt;&lt;&#39;
多行注释内容
多行注释内容
多行注释内容
&#39;
:&lt;&lt;!
多行注释内容
多行注释内容
多行注释内容
!
</code></pre>
<h1>2. 变量</h1>
<h2>2.1. 变量定义</h2>
<p>使用<code>VARIABLENAME=VALUE</code>的形式,VALUE如果是字符串的话,可以使用单引号、双引号或者不加引号。单引号内的任何字符都会原样输出,不能进行转义,单引号内不能单独出现一个单引号,但可成对出现,作为字符串拼接使用。双引号内可以有变量,可以出现转义字符。</p>
<h2>2.2. 变量使用</h2>
<p>只需要在变量前加<code>$</code>符号,变量加<code>{}</code>是可选的,方便解释器识别边界。将变量加上<code>{}</code>是一个好习惯,不容易出错。</p>
<pre><code class="language-shell">your_age=25
your_name=&quot;shinerio&quot;
your_name=shinerio
your_name=&#39;shinerio&#39;
echo $your_age # 输出25
echo $your_name # 输出shinerio
echo &quot;${your_name}hello&quot; &lt;span class=&quot;tag&quot;&gt;#这里&lt;/span&gt;{}必须添加,否则解释器认为是${your_namehello}
str=&#39;hello&#39;&#39; # 非法
str=&#39;hello&#39;__&#39;world&#39; # 成对出现的单引号做字符拼接
echo $str &lt;span class=&quot;tag&quot;&gt;#输出hello__world&lt;/span&gt;
str1=&#39;helloworld${your_age}\nnew line&#39;
str2=&quot;helloworld${your_age}\nnew line&quot;
echo $str1 # 输出helloworld${your_age}\nnew line
echo $str2 # 输出helloworld25\nnew line
echo -e $str2 # -e开启转义 \n表示换行 echo默认换行,通过\c强制不换行
&lt;span class=&quot;tag&quot;&gt;#helloworld25&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;#new&lt;/span&gt; line
</code></pre>
<h2>2.3. 只读变量</h2>
<p>使用<code>readonly VARIABLENAME</code>设置变量只读,只读变量的值不能更改</p>
<pre><code class="language-shell">readonly name=&#39;jack&#39;
name=&#39;kelly&#39;
zsh: read-only variable: name
</code></pre>
<h2>2.4. 删除变量</h2>
<p>使用<code>unset VARIABLENAME</code>删除变量。</p>
<h1>3. 字符串操作</h1>
<h2>3.1. 字符串拼接</h2>
<pre><code class="language-shell">str1=&quot;hello&quot;${your_name}&quot;world&quot;
str2=&quot;hello${your_name}world&quot;
str3=&#39;hello&#39;${your_name}&#39;world&#39;
</code></pre>
<h2>3.2. 字符串长度</h2>
<pre><code class="language-shell">str=&#39;hello&#39;
echo ${&lt;span class=&quot;tag&quot;&gt;#str&lt;/span&gt;}
5
</code></pre>
<h2>3.3. 字符串截取</h2>
<p><code>${string:start:length}</code>,索引从0开始,从start(包含)开始截取共计length长度的字符。</p>
<pre><code class="language-shell">str=&#39;helloworld&#39;
echo ${str:0:5}
hello
</code></pre>
<h2>3.4. 字符串运算符</h2>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>=</code></td>
<td>检测两个字符串是否相等,相等返回true</td>
<td><code>[ &#39;hello&#39; = &#39;hello&#39; ]</code></td>
</tr>
<tr>
<td><code>!=</code></td>
<td>检测两个字符串是否相等,不相等返回true</td>
<td><code>[ &#39;hello&#39; != &#39;ello&#39; ]</code></td>
</tr>
<tr>
<td><code>-z</code></td>
<td>检测字符串长度是否为0,为0返回true</td>
<td><code>[ -z &#39;&#39; ]</code></td>
</tr>
<tr>
<td><code>-n </code></td>
<td>检测字符串长度是否不为0,不为0返回true</td>
<td><code>[ -n &#39;hello&#39; ]</code></td>
</tr>
<tr>
<td><code>$</code></td>
<td>检测字符串是否为空,不为空返回true</td>
<td><code>[ $&#39;hello&#39; ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ &#39;hello&#39; = &#39;hello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ &#39;hello&#39; != &#39;ello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ -z &#39;&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ -n &#39;hello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ $&#39;hello&#39; ];then echo &#39;hello&#39;;fi
str=&#39;hello&#39;
if [ $str ];then echo &#39;hello&#39;;fi
# hello
</code></pre>
<p>注意字符串的等值判断是一个等号<code>&quot;=&quot;</code>,与下文要讲的逻辑运算符使用两个等号<code>&quot;==&quot;</code>做等值判断不一样。</p>
<h1>4. 文件测试运算符</h1>
<table>
<thead>
<tr>
<th>操作符</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>-b file</code></td>
<td>检测文件是否是块设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-c file</code></td>
<td>检测文件是否是字符设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-d file</code></td>
<td>检测文件是否是目录,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-f file</code></td>
<td>检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-g file</code></td>
<td>检测文件是否设置了<code>SGID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-k file</code></td>
<td>检测文件是否设置了粘着位(Sticky Bit),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-p file</code></td>
<td>检测文件是否是有名管道,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-u file</code></td>
<td>检测文件是否设置了<code>SUID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-r file</code></td>
<td>检测文件是否可读,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-w file</code></td>
<td>检测文件是否可写,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-x file</code></td>
<td>检测文件是否可执行,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-s file</code></td>
<td>检测文件是否为空(文件大小是否大于0),不为空返回true。</td>
</tr>
<tr>
<td><code>-e file</code></td>
<td>检测文件(包括目录)是否存在,如果是,则返回true。</td>
</tr>
</tbody></table>
<pre><code class="language-shell">if &lt;a href=&quot;f-home.html&quot; class=&quot;internal-link&quot;&gt; -f &#39;/home&#39; &lt;/a&gt;;then echo &#39;directory&#39;;else echo &#39;file&#39;;fi
# file
if &lt;a href=&quot;d-home.html&quot; class=&quot;internal-link&quot;&gt; -d &#39;/home&#39; &lt;/a&gt;;then echo &#39;directory&#39;;else echo &#39;file&#39;;fi
# directory
if &lt;a href=&quot;e-tmpfake-file.html&quot; class=&quot;internal-link&quot;&gt; -e &#39;/tmp/fake_file&#39; &lt;/a&gt;;then echo &#39;exist&#39;;else echo &#39;not exist&#39;;fi
# not exist
</code></pre>
<h1>5. 数组</h1>
<p><code>shell</code>只支持一维数组,用括号表示,元素通过空格分隔,形如<code>数组名=(值1 值2 ... 值n)</code>。<code>shell</code>数组下标从<code>1</code>开始。</p>
<ul>
<li><code>${数组名[下标]}</code>,读取指索引位置数组元素</li>
<li>使用<code>@</code>或<code>*</code>代替下标,获取数组中所有元素。</li>
<li>使用<code>{&lt;span class=&quot;tag&quot;&gt;#数组名&lt;/span&gt;[@]}</code>或<code>{&lt;span class=&quot;tag&quot;&gt;#数组名&lt;/span&gt;[*]}</code>获取数组元素个数。</li>
</ul>
<pre><code class="language-shell">arr=(value1 value2 value3 value4)
echo ${arr[3]}
# value3
echo ${arr[*]}
# value1 value2 value3 value4
echo ${arr[@]}
# value1 value2 value3 value4
arr[3]=&#39;new_value3&#39;
echo $arr[3]
# new_value3
echo ${&lt;span class=&quot;tag&quot;&gt;#arr&lt;/span&gt;[@]}
# 4
echo &quot;arr[1]的长度为:${&lt;span class=&quot;tag&quot;&gt;#arr&lt;/span&gt;[1]}&quot;
# arr[1]的长度为:6
</code></pre>
<h1>6. 运算符</h1>
<h2>6.1. 赋值运算符</h2>
<pre><code class="language-shell">a=10
b=$a
</code></pre>
<h2>6.2. 算术运算符</h2>
<p>算数运算符支持<code>+,-,*,/,%</code></p>
<h3>6.2.1. expr表示法</h3>
<pre><code class="language-shell">echo `expr 10 + 20`
# 30
echo $(expr 20 / 2)
# 10
echo $(expr 10 \* 20) # 使用expr进行乘法运算时必须使用\进行转义
# 200
</code></pre>
<blockquote>
<p>使用expr表示方法时,表达式和运算符之间必须有空格。</p>
</blockquote>
<h3>6.2.2. <code>$[]</code></h3>
<pre><code class="language-shell">echo $[10%3]
# 1
</code></pre>
<h3>6.2.3. <code>$(())</code></h3>
<pre><code class="language-shell">echo $((10*20))
# 200
</code></pre>
<h2>6.3. 关系运算符</h2>
<p>最常见的关系运算符是:<code>==,!=,&lt;,&gt;,&gt;=,&lt;=</code></p>
<pre><code class="language-shell">echo $[10==10]
# 1
flag=$[20==10]
echo $flag
# 1
echo $[10&gt;=10]
# 1
</code></pre>
<p>如下关系运算符只能使用在条件表达式<code>if、while</code>下,类似<code>flag=[ $a -eq $b ]</code>的直接赋值语句是非法的。关系运算符的条件表达式要放在<strong>一对</strong>方括号中,并且中间需要有空格。也可以使用<code>(())</code>替代<code>[]</code>,此时<code>-eq,-lt,-le</code>之类的需要使用<code>==,&lt;,&lt;=</code>等替换。</p>
<blockquote>
<p><code>[]</code>搭配<code>-eq -ne</code>等使用,<code>(())</code>搭配<code>|| &amp;&amp;</code>等使用。</p>
</blockquote>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>-eq</code></td>
<td>检测两个数是否相等,相等返回true。</td>
<td><code>[ $a -eq $b ]</code></td>
</tr>
<tr>
<td><code>-ne</code></td>
<td>检测两个数是否不相等,不相等返回 true。</td>
<td><code>[ $a -ne $b ]</code></td>
</tr>
<tr>
<td><code>-gt</code></td>
<td>检测左边的数是否大于右边的,如果是,则返回 true。</td>
<td><code>[ $a -gt $b ]</code></td>
</tr>
<tr>
<td><code>-lt</code></td>
<td>检测左边的数是否小于右边的,如果是,则返回 true。</td>
<td><code>[ $a -lt $b ]</code></td>
</tr>
<tr>
<td><code>-ge</code></td>
<td>检测左边的数是否大于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -ge $b ]</code></td>
</tr>
<tr>
<td><code>-le</code></td>
<td>检测左边的数是否小于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -le $b ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ 1 -eq 1 ];then echo &#39;hello&#39;;fi;
# hello
if ((10&gt;=10));then echo &#39;hello&#39;;fi;
# hello
</code></pre>
<h2>6.4. 布尔、逻辑运算符</h2>
<p>布尔、逻辑运算的条件表达式也要放在一对方括号中<code>[]</code>。</p>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>!</code></td>
<td>非运算,表达式为true则返回false,否则返回true。</td>
<td><code>[ ! 10 -eq 0 ]</code></td>
</tr>
<tr>
<td><code>-o</code></td>
<td>或运算,有一个表达式为true则返回true。</td>
<td><code>[ 10 -lt 20 -o 10 -gt 100 ]</code></td>
</tr>
<tr>
<td><code>-a</code></td>
<td>与运算,两个表达式都为true才返回true。</td>
<td><code>[ 10 -lt 20 -a 10 -gt 100 ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ ! 10 -eq 0 ];then echo &#39;hello&#39;;fi
# hello
if [ 10 -ge 10 -a 10 -ge 10 ];then echo &#39;hello&#39;;fi
# hello
if [ 10 -ge 20 -o 10 -ge 0 ];then echo &#39;hello&#39;;fi
# hello
</code></pre>
<p> <code>-o</code>也可以使用<code>||</code>替代,<code>-a</code>也可以使用<code>&amp;&amp;</code>替代,此时需要使用<code>(())</code>或<code>[[]]</code>替代<code>[]</code>。</p>
<pre><code class="language-shell">if &lt;a href=&quot;1010-55.html&quot; class=&quot;internal-link&quot;&gt; 10==10 &amp;&amp; 5==5 &lt;/a&gt;;then echo &#39;hello&#39;;fi
# hello
if ((10==10 &amp;&amp; 5==5));then echo &#39;hello&#39;;fi
# hello
</code></pre>
<h1>7. 传递参数</h1>
<p>在执行 <code>Shell</code>脚本时,向脚本传递参数,脚本内获取参数的格式为:<code>$n</code>。<code>n</code>代表一个数字,<code>1</code>为执行脚本的第一个参数,<code>2</code>为执行脚本的第二个参数,<code>$0</code>为执行的文件名。在为<code>shell</code>脚本传递的参数中如果包含空格,应该使用单引号或者双引号将该参数括起来,以便于脚本将这个参数作为整体来接收。另外,还有几个特殊字符用来处理参数:</p>
<table>
<thead>
<tr>
<th>参数处理</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>$#</code></td>
<td>传递到脚本的参数个数</td>
</tr>
<tr>
<td><code>$*</code></td>
<td>以一个单字符串显示所有向脚本传递的参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$$</code></td>
<td>脚本运行的当前进程ID号</td>
</tr>
<tr>
<td><code>$!</code></td>
<td>后台运行的最后一个进程的ID号</td>
</tr>
<tr>
<td><code>$@</code></td>
<td>与<code>$*</code>相同,但是使用时加引号,并在引号中返回每个参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$-</code></td>
<td>显示Shell使用的当前选项,与set功能相同。</td>
</tr>
<tr>
<td><code>$?</code></td>
<td>显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。</td>
</tr>
</tbody></table>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-bash">set -e
echo &quot;执行的文件名:$0&quot;
echo &quot;参数个数为$#&quot;
echo &quot;第一个参数为:$1&quot;
echo &quot;第二个参数为:$2&quot;
echo &quot;所有参数为:$@&quot;
echo &quot;进程ID号为:$$&quot;
echo &quot;当前shell选项为$-&quot;
echo &quot;上一个命令退出的状态为$?&quot;
</code></pre>
<p>执行结果如下:</p>
<pre><code class="language-shell">$ sh test.sh param1 &quot;param2 with space&quot;
执行的文件名:test.sh
参数个数为2
第一个参数为:param1
第二个参数为:param2 with space
所有参数为:param1 param2 with space
进程ID号为:3700
当前shell选项为ehB
上一个命令退出的状态为0
</code></pre>
<h1>8. 函数</h1>
<p>函数定义通过<code>function_name(){}</code>的形式定义,函数返回值可以显示用return返回,如果不加,将以最后一条命令的运行结果作为返回值,函数返回值只能是数字。函数也可以传递参数,但是函数定义的()中不需要申明。</p>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-shell">sayhello(){
echo &quot;hello&quot;
}
# 注意函数调用只需要函数名,不需要加()
sayhello
sayhellowithparam(){
echo &quot;hello, $1 $2 $3&quot;
return 1
}
sayhellowithparam zhangsan lisi wangwu
echo $?
</code></pre>
<p>输出如下:</p>
<blockquote>
<p>hello<br>hello, zhangsan lisi wangwu<br>1</p>
</blockquote>
<h1>9. 命令替换</h1>
<p>命令替换可以将一个命令的输出作为另外一个命令的参数。</p>
<pre><code class="language-shell"># command1 `command2`
cd `pwd` # 该命令将pwd命令列出的目录作为cd命令的参数,结果仍然是停留在当前目录下
cd `echo $HOME` # 将echo的输出作为cd的参数,即打开用户根目录
</code></pre>
<h1>10. let命令</h1>
<p>let 命令是 BASH 中用于计算的工具,用于执行一个或多个表达式,变量计算中不需要加上 $ 来表示变量。如果表达式中包含了空格或其他特殊字符,则必须引起来。</p>
<ul>
<li>自加操作:<code>let no++</code></li>
<li>自减操作:<code>let no--</code></li>
<li>简写形式 <code>let no+=10</code>,<code>let no-=20</code>,分别等同于<code>let no=no+10</code>,<code>let no=no-20</code></li>
</ul>
<h1>11. 流程控制</h1>
<h2>11.1. if</h2>
<pre><code class="language-shell">if ((10&lt;2));then
echo &quot;10小于2&quot;
elif ((10&gt;20));then
echo &quot;a大于10&quot;
else
echo &quot;10大于2且小于10&quot;
fi
</code></pre>
<h2>11.2. case</h2>
<p><code>case</code>每一种情况以右括号结尾,执行到<code>;;</code>结束</p>
<pre><code class="language-shell">case 10 in
0|1)
echo &quot;a为0或1&quot;
;;
11|12)
echo &quot;a为11或12&quot;
;;
*)
# *用来匹配所有情况
echo &quot;a为10&quot;
;;
esac
</code></pre>
<h2>11.3. while</h2>
<pre><code class="language-shell">count=0
while(($count&lt;5))
do
echo $count
let count++
done
</code></pre>
<h2>11.4. util</h2>
<pre><code class="language-shell">count=0
until(($count&gt;=5))
do
echo $count
let count++
done
</code></pre>
<h2>11.5. for</h2>
<pre><code class="language-shell"># for写法1
for ((count=0;$count&lt;5;count=$count+1))
do
echo $count
done
# for写法2
arr=(0 1 2 3 4)
for count in ${arr[*]}
do
echo $int
done
# for写法3
for int in 0 1 2 3 4
do
echo $int
done
</code></pre>
<h2>11.6. break和continue</h2>
<p>用法与一般编程语言类似,break跳出循环,continue跳出当前循环</p>
<pre><code class="language-shell">for ((count=0;$count&gt;=0;count=$count+1))
do
if (($count&gt;=5));then
break;
fi
echo $count
done
</code></pre>
<h1>12. 输入输出重定向</h1>
<h2>12.1. 输出重定向</h2>
<p><code>command &gt; file</code>将命令输出结果保存的file文件中。<code>&gt;</code>从文件头开始写,会覆盖旧内容,<code>&gt;&gt;</code>将内容追加到文件末尾</p>
<pre><code class="language-shell"># 将who命令的输出保存的users文件中,可以通过cat users查看
who &gt; users
# 将字符串hello world保存到text.txt文件中
echo &quot;hello world&quot; &gt; text.txt
</code></pre>
<h2>12.2. 输入重定向</h2>
<p><code>command &lt; file</code>从file文件获取输入</p>
<pre><code class="language-shell">wc -l /etc/passwd
# 123 /etc/passwd
wc -l &lt; users
# 123
# 第一个例子,会输出文件名;第二个不会,因为它仅仅知道从标准输入读取内容
# command &lt; infile &gt; outfile, 同时替换输入和输出,执行command,从文件infile读取内容,然后将输出写入到outfile中。
wc -l &lt; /etc/passwd &gt; result
cat result
# 123
</code></pre>
<h2>12.3. 文件描述符</h2>
<p>一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件</p>
<ul>
<li>标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。</li>
<li>标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。</li>
<li>标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。</li>
</ul>
<pre><code class="language-shell"># 将标准错误输出重定向到error_trace
cat /tmp/fake_file 2&gt;error_trace
cat error_trace
# cat: /tmp/fake_fule: No such file or directory
# 将标准输出和标准错误输出都重定向到result
cat /tmp/fake_file &amp;&gt;result
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准错误重定向到标准输出
ls /tmp/fake_file &gt; result 2&gt;&amp;1
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准输入重定向到result,将标准错误输出重定向到error_trace
cat /tmp/fake_file 1&gt;result 2&gt;error_trace
</code></pre>
<h2>12.4. Here Document</h2>
<p>将两个<code>EOF</code>之间的内容(document) 作为输入传递给<code>command</code></p>
<pre><code class="language-bash"># command &lt;&lt; EOF
# document
# EOF
cat &lt;&lt; EOF
hello
shinerio
learn shell
EOF
</code></pre>
<blockquote>
<p>结尾的<code>EOF</code>一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和<code>tab</code>缩进。开始的<code>EOF</code>前后的空格会被忽略掉。</p>
</blockquote>
<h2>12.5. /dev/null</h2>
<p>如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null。<code>command &gt; /dev/null</code></p>
<pre><code class="language-shell">cat users &gt; /dev/null
cat users &gt; /dev/null 2&gt;&amp;1
</code></pre>
<h1>13. set命令</h1>
<p>set指令能设置所使用shell的执行方式,可依照不同的需求来做设置。以下只列出常用的选项参数:</p>
<ul>
<li>-e 若指令传回值不等于0,则立即退出shell。</li>
<li>-f 取消使用通配符。</li>
<li>-n 只读取指令,而不实际执行。</li>
<li>-x 执行指令后,会先显示该指令及所下的参数。</li>
</ul>
#39;hello' ];then echo 'hello';fi
str='hello'
if [ $str ];then echo 'hello';fi
# hello
</code></pre>
<p>注意字符串的等值判断是一个等号<code>"="</code>,与下文要讲的逻辑运算符使用两个等号<code>"=="</code>做等值判断不一样。</p>
<h1>4. 文件测试运算符</h1>
<table>
<thead>
<tr>
<th>操作符</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>-b file</code></td>
<td>检测文件是否是块设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-c file</code></td>
<td>检测文件是否是字符设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-d file</code></td>
<td>检测文件是否是目录,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-f file</code></td>
<td>检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-g file</code></td>
<td>检测文件是否设置了<code>SGID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-k file</code></td>
<td>检测文件是否设置了粘着位(Sticky Bit),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-p file</code></td>
<td>检测文件是否是有名管道,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-u file</code></td>
<td>检测文件是否设置了<code>SUID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-r file</code></td>
<td>检测文件是否可读,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-w file</code></td>
<td>检测文件是否可写,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-x file</code></td>
<td>检测文件是否可执行,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-s file</code></td>
<td>检测文件是否为空(文件大小是否大于0),不为空返回true。</td>
</tr>
<tr>
<td><code>-e file</code></td>
<td>检测文件(包括目录)是否存在,如果是,则返回true。</td>
</tr>
</tbody></table>
<pre><code class="language-shell">if <a href="f-home.html" class="internal-link"> -f '/home' </a>;then echo 'directory';else echo 'file';fi
# file
if <a href="d-home.html" class="internal-link"> -d '/home' </a>;then echo 'directory';else echo 'file';fi
# directory
if <a href="e-tmpfake-file.html" class="internal-link"> -e '/tmp/fake_file' </a>;then echo 'exist';else echo 'not exist';fi
# not exist
</code></pre>
<h1>5. 数组</h1>
<p><code>shell</code>只支持一维数组,用括号表示,元素通过空格分隔,形如<code>数组名=(值1 值2 ... 值n)</code>。<code>shell</code>数组下标从<code>1</code>开始。</p>
<ul>
<li><code>${数组名[下标]}</code>,读取指索引位置数组元素</li>
<li>使用<code>@</code>或<code>*</code>代替下标,获取数组中所有元素。</li>
<li>使用<code>{<span class="tag">#数组名</span>[@]}</code>或<code>{<span class="tag">#数组名</span>[*]}</code>获取数组元素个数。</li>
</ul>
<pre><code class="language-shell">arr=(value1 value2 value3 value4)
echo ${arr[3]}
# value3
echo ${arr[*]}
# value1 value2 value3 value4
echo ${arr[@]}
# value1 value2 value3 value4
arr[3]='new_value3'
echo $arr[3]
# new_value3
echo ${<span class="tag">#arr</span>[@]}
# 4
echo "arr[1]的长度为:${<span class="tag">#arr</span>[1]}"
# arr[1]的长度为:6
</code></pre>
<h1>6. 运算符</h1>
<h2>6.1. 赋值运算符</h2>
<pre><code class="language-shell">a=10
b=$a
</code></pre>
<h2>6.2. 算术运算符</h2>
<p>算数运算符支持<code>+,-,*,/,%</code></p>
<h3>6.2.1. expr表示法</h3>
<pre><code class="language-shell">echo `expr 10 + 20`
# 30
echo $(expr 20 / 2)
# 10
echo $(expr 10 \* 20) # 使用expr进行乘法运算时必须使用\进行转义
# 200
</code></pre>
<blockquote>
<p>使用expr表示方法时,表达式和运算符之间必须有空格。</p>
</blockquote>
<h3>6.2.2. <code>$[]</code></h3>
<pre><code class="language-shell">echo $[10%3]
# 1
</code></pre>
<h3>6.2.3. <code>$(())</code></h3>
<pre><code class="language-shell">echo $((10*20))
# 200
</code></pre>
<h2>6.3. 关系运算符</h2>
<p>最常见的关系运算符是:<code>==,!=,<,>,>=,<=</code></p>
<pre><code class="language-shell">echo $[10==10]
# 1
flag=$[20==10]
echo $flag
# 1
echo $[10>=10]
# 1
</code></pre>
<p>如下关系运算符只能使用在条件表达式<code>if、while</code>下,类似<code>flag=[ $a -eq $b ]</code>的直接赋值语句是非法的。关系运算符的条件表达式要放在<strong>一对</strong>方括号中,并且中间需要有空格。也可以使用<code>(())</code>替代<code>[]</code>,此时<code>-eq,-lt,-le</code>之类的需要使用<code>==,<,<=</code>等替换。</p>
<blockquote>
<p><code>[]</code>搭配<code>-eq -ne</code>等使用,<code>(())</code>搭配<code>|| &&</code>等使用。</p>
</blockquote>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>-eq</code></td>
<td>检测两个数是否相等,相等返回true。</td>
<td><code>[ $a -eq $b ]</code></td>
</tr>
<tr>
<td><code>-ne</code></td>
<td>检测两个数是否不相等,不相等返回 true。</td>
<td><code>[ $a -ne $b ]</code></td>
</tr>
<tr>
<td><code>-gt</code></td>
<td>检测左边的数是否大于右边的,如果是,则返回 true。</td>
<td><code>[ $a -gt $b ]</code></td>
</tr>
<tr>
<td><code>-lt</code></td>
<td>检测左边的数是否小于右边的,如果是,则返回 true。</td>
<td><code>[ $a -lt $b ]</code></td>
</tr>
<tr>
<td><code>-ge</code></td>
<td>检测左边的数是否大于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -ge $b ]</code></td>
</tr>
<tr>
<td><code>-le</code></td>
<td>检测左边的数是否小于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -le $b ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ 1 -eq 1 ];then echo 'hello';fi;
# hello
if ((10>=10));then echo 'hello';fi;
# hello
</code></pre>
<h2>6.4. 布尔、逻辑运算符</h2>
<p>布尔、逻辑运算的条件表达式也要放在一对方括号中<code>[]</code>。</p>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>!</code></td>
<td>非运算,表达式为true则返回false,否则返回true。</td>
<td><code>[ ! 10 -eq 0 ]</code></td>
</tr>
<tr>
<td><code>-o</code></td>
<td>或运算,有一个表达式为true则返回true。</td>
<td><code>[ 10 -lt 20 -o 10 -gt 100 ]</code></td>
</tr>
<tr>
<td><code>-a</code></td>
<td>与运算,两个表达式都为true才返回true。</td>
<td><code>[ 10 -lt 20 -a 10 -gt 100 ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ ! 10 -eq 0 ];then echo 'hello';fi
# hello
if [ 10 -ge 10 -a 10 -ge 10 ];then echo 'hello';fi
# hello
if [ 10 -ge 20 -o 10 -ge 0 ];then echo 'hello';fi
# hello
</code></pre>
<p> <code>-o</code>也可以使用<code>||</code>替代,<code>-a</code>也可以使用<code>&&</code>替代,此时需要使用<code>(())</code>或<code>[[]]</code>替代<code>[]</code>。</p>
<pre><code class="language-shell">if <a href="1010-55.html" class="internal-link"> 10==10 && 5==5 </a>;then echo 'hello';fi
# hello
if ((10==10 && 5==5));then echo 'hello';fi
# hello
</code></pre>
<h1>7. 传递参数</h1>
<p>在执行 <code>Shell</code>脚本时,向脚本传递参数,脚本内获取参数的格式为:<code>$n</code>。<code>n</code>代表一个数字,<code>1</code>为执行脚本的第一个参数,<code>2</code>为执行脚本的第二个参数,<code>$0</code>为执行的文件名。在为<code>shell</code>脚本传递的参数中如果包含空格,应该使用单引号或者双引号将该参数括起来,以便于脚本将这个参数作为整体来接收。另外,还有几个特殊字符用来处理参数:</p>
<table>
<thead>
<tr>
<th>参数处理</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>$#</code></td>
<td>传递到脚本的参数个数</td>
</tr>
<tr>
<td><code>$*</code></td>
<td>以一个单字符串显示所有向脚本传递的参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$</code></td>
<td>脚本运行的当前进程ID号</td>
</tr>
<tr>
<td><code>$!</code></td>
<td>后台运行的最后一个进程的ID号</td>
</tr>
<tr>
<td><code>$@</code></td>
<td>与<code>$*</code>相同,但是使用时加引号,并在引号中返回每个参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$-</code></td>
<td>显示Shell使用的当前选项,与set功能相同。</td>
</tr>
<tr>
<td><code>$?</code></td>
<td>显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。</td>
</tr>
</tbody></table>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-bash">set -e
echo "执行的文件名:$0"
echo "参数个数为$#"
echo "第一个参数为:$1"
echo "第二个参数为:$2"
echo "所有参数为:$@"
echo "进程ID号为:$"
echo "当前shell选项为$-"
echo "上一个命令退出的状态为$?"
</code></pre>
<p>执行结果如下:</p>
<pre><code class="language-shell">$ sh test.sh param1 "param2 with space"
执行的文件名:test.sh
参数个数为2
第一个参数为:param1
第二个参数为:param2 with space
所有参数为:param1 param2 with space
进程ID号为:3700
当前shell选项为ehB
上一个命令退出的状态为0
</code></pre>
<h1>8. 函数</h1>
<p>函数定义通过<code>function_name(){}</code>的形式定义,函数返回值可以显示用return返回,如果不加,将以最后一条命令的运行结果作为返回值,函数返回值只能是数字。函数也可以传递参数,但是函数定义的()中不需要申明。</p>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-shell">sayhello(){
echo "hello"
}
# 注意函数调用只需要函数名,不需要加()
sayhello
sayhellowithparam(){
echo "hello, $1 $2 $3"
return 1
}
sayhellowithparam zhangsan lisi wangwu
echo $?
</code></pre>
<p>输出如下:</p>
<blockquote>
<p>hello<br>hello, zhangsan lisi wangwu<br>1</p>
</blockquote>
<h1>9. 命令替换</h1>
<p>命令替换可以将一个命令的输出作为另外一个命令的参数。</p>
<pre><code class="language-shell"># command1 `command2`
cd `pwd` # 该命令将pwd命令列出的目录作为cd命令的参数,结果仍然是停留在当前目录下
cd `echo $HOME` # 将echo的输出作为cd的参数,即打开用户根目录
</code></pre>
<h1>10. let命令</h1>
<p>let 命令是 BASH 中用于计算的工具,用于执行一个或多个表达式,变量计算中不需要加上 $ 来表示变量。如果表达式中包含了空格或其他特殊字符,则必须引起来。</p>
<ul>
<li>自加操作:<code>let no++</code></li>
<li>自减操作:<code>let no--</code></li>
<li>简写形式 <code>let no+=10</code>,<code>let no-=20</code>,分别等同于<code>let no=no+10</code>,<code>let no=no-20</code></li>
</ul>
<h1>11. 流程控制</h1>
<h2>11.1. if</h2>
<pre><code class="language-shell">if ((10<2));then
echo "10小于2"
elif ((10>20));then
echo "a大于10"
else
echo "10大于2且小于10"
fi
</code></pre>
<h2>11.2. case</h2>
<p><code>case</code>每一种情况以右括号结尾,执行到<code>;;</code>结束</p>
<pre><code class="language-shell">case 10 in
0|1)
echo "a为0或1"
;;
11|12)
echo "a为11或12"
;;
*)
# *用来匹配所有情况
echo "a为10"
;;
esac
</code></pre>
<h2>11.3. while</h2>
<pre><code class="language-shell">count=0
while(($count<5))
do
echo $count
let count++
done
</code></pre>
<h2>11.4. util</h2>
<pre><code class="language-shell">count=0
until(($count>=5))
do
echo $count
let count++
done
</code></pre>
<h2>11.5. for</h2>
<pre><code class="language-shell"># for写法1
for ((count=0;$count<5;count=$count+1))
do
echo $count
done
# for写法2
arr=(0 1 2 3 4)
for count in ${arr[*]}
do
echo $int
done
# for写法3
for int in 0 1 2 3 4
do
echo $int
done
</code></pre>
<h2>11.6. break和continue</h2>
<p>用法与一般编程语言类似,break跳出循环,continue跳出当前循环</p>
<pre><code class="language-shell">for ((count=0;$count>=0;count=$count+1))
do
if (($count>=5));then
break;
fi
echo $count
done
</code></pre>
<h1>12. 输入输出重定向</h1>
<h2>12.1. 输出重定向</h2>
<p><code>command > file</code>将命令输出结果保存的file文件中。<code>></code>从文件头开始写,会覆盖旧内容,<code>>></code>将内容追加到文件末尾</p>
<pre><code class="language-shell"># 将who命令的输出保存的users文件中,可以通过cat users查看
who > users
# 将字符串hello world保存到text.txt文件中
echo "hello world" > text.txt
</code></pre>
<h2>12.2. 输入重定向</h2>
<p><code>command < file</code>从file文件获取输入</p>
<pre><code class="language-shell">wc -l /etc/passwd
# 123 /etc/passwd
wc -l < users
# 123
# 第一个例子,会输出文件名;第二个不会,因为它仅仅知道从标准输入读取内容
# command < infile > outfile, 同时替换输入和输出,执行command,从文件infile读取内容,然后将输出写入到outfile中。
wc -l < /etc/passwd > result
cat result
# 123
</code></pre>
<h2>12.3. 文件描述符</h2>
<p>一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件</p>
<ul>
<li>标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。</li>
<li>标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。</li>
<li>标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。</li>
</ul>
<pre><code class="language-shell"># 将标准错误输出重定向到error_trace
cat /tmp/fake_file 2>error_trace
cat error_trace
# cat: /tmp/fake_fule: No such file or directory
# 将标准输出和标准错误输出都重定向到result
cat /tmp/fake_file &>result
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准错误重定向到标准输出
ls /tmp/fake_file > result 2>&1
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准输入重定向到result,将标准错误输出重定向到error_trace
cat /tmp/fake_file 1>result 2>error_trace
</code></pre>
<h2>12.4. Here Document</h2>
<p>将两个<code>EOF</code>之间的内容(document) 作为输入传递给<code>command</code></p>
<pre><code class="language-bash"># command << EOF
# document
# EOF
cat << EOF
hello
shinerio
learn shell
EOF
</code></pre>
<blockquote>
<p>结尾的<code>EOF</code>一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和<code>tab</code>缩进。开始的<code>EOF</code>前后的空格会被忽略掉。</p>
</blockquote>
<h2>12.5. /dev/null</h2>
<p>如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null。<code>command > /dev/null</code></p>
<pre><code class="language-shell">cat users > /dev/null
cat users > /dev/null 2>&1
</code></pre>
<h1>13. set命令</h1>
<p>set指令能设置所使用shell的执行方式,可依照不同的需求来做设置。以下只列出常用的选项参数:</p>
<ul>
<li>-e 若指令传回值不等于0,则立即退出shell。</li>
<li>-f 取消使用通配符。</li>
<li>-n 只读取指令,而不实际执行。</li>
<li>-x 执行指令后,会先显示该指令及所下的参数。</li>
</ul>
</section>
</article>amp;#39;hello' ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ 'hello' = 'hello' ];then echo 'hello';fi
# hello
if [ 'hello' != 'ello' ];then echo 'hello';fi
# hello
if [ -z '' ];then echo 'hello';fi
# hello
if [ -n 'hello' ];then echo 'hello';fi
# hello
if [ <article>
<header>
<h1>shell编程</h1>
<time datetime="2023-01-24T00:00:00.000Z">2023年1月24日</time>
<div class="tags">
<span class="tag">linux</span>
</div>
</header>
<section class="content">
<p>本文主要介绍shell编程的基本语法以及实际应用中的常见命令。</p>
<h1>1. 注释</h1>
<h2>1.1. 单行注释</h2>
<pre><code class="language-shell"># 这是单行注释
</code></pre>
<h2>1.2. 多行注释</h2>
<pre><code class="language-shell">:<<EOF
多行注释内容
多行注释内容
多行注释内容
EOF
</code></pre>
<p>多行注释<code>EOF</code>也可替换成<code>!</code>或<code>'</code></p>
<pre><code class="language-shell">:<<'
多行注释内容
多行注释内容
多行注释内容
'
:<<!
多行注释内容
多行注释内容
多行注释内容
!
</code></pre>
<h1>2. 变量</h1>
<h2>2.1. 变量定义</h2>
<p>使用<code>VARIABLENAME=VALUE</code>的形式,VALUE如果是字符串的话,可以使用单引号、双引号或者不加引号。单引号内的任何字符都会原样输出,不能进行转义,单引号内不能单独出现一个单引号,但可成对出现,作为字符串拼接使用。双引号内可以有变量,可以出现转义字符。</p>
<h2>2.2. 变量使用</h2>
<p>只需要在变量前加<code>$</code>符号,变量加<code>{}</code>是可选的,方便解释器识别边界。将变量加上<code>{}</code>是一个好习惯,不容易出错。</p>
<pre><code class="language-shell">your_age=25
your_name="shinerio"
your_name=shinerio
your_name='shinerio'
echo $your_age # 输出25
echo $your_name # 输出shinerio
echo "${your_name}hello" <span class="tag">#这里</span>{}必须添加,否则解释器认为是${your_namehello}
str='hello'' # 非法
str='hello'__'world' # 成对出现的单引号做字符拼接
echo $str <span class="tag">#输出hello__world</span>
str1='helloworld${your_age}\nnew line'
str2="helloworld${your_age}\nnew line"
echo $str1 # 输出helloworld${your_age}\nnew line
echo $str2 # 输出helloworld25\nnew line
echo -e $str2 # -e开启转义 \n表示换行 echo默认换行,通过\c强制不换行
<span class="tag">#helloworld25</span>
<span class="tag">#new</span> line
</code></pre>
<h2>2.3. 只读变量</h2>
<p>使用<code>readonly VARIABLENAME</code>设置变量只读,只读变量的值不能更改</p>
<pre><code class="language-shell">readonly name='jack'
name='kelly'
zsh: read-only variable: name
</code></pre>
<h2>2.4. 删除变量</h2>
<p>使用<code>unset VARIABLENAME</code>删除变量。</p>
<h1>3. 字符串操作</h1>
<h2>3.1. 字符串拼接</h2>
<pre><code class="language-shell">str1="hello"${your_name}"world"
str2="hello${your_name}world"
str3='hello'${your_name}'world'
</code></pre>
<h2>3.2. 字符串长度</h2>
<pre><code class="language-shell">str='hello'
echo ${<span class="tag">#str</span>}
5
</code></pre>
<h2>3.3. 字符串截取</h2>
<p><code>${string:start:length}</code>,索引从0开始,从start(包含)开始截取共计length长度的字符。</p>
<pre><code class="language-shell">str='helloworld'
echo ${str:0:5}
hello
</code></pre>
<h2>3.4. 字符串运算符</h2>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>=</code></td>
<td>检测两个字符串是否相等,相等返回true</td>
<td><code>[ 'hello' = 'hello' ]</code></td>
</tr>
<tr>
<td><code>!=</code></td>
<td>检测两个字符串是否相等,不相等返回true</td>
<td><code>[ 'hello' != 'ello' ]</code></td>
</tr>
<tr>
<td><code>-z</code></td>
<td>检测字符串长度是否为0,为0返回true</td>
<td><code>[ -z '' ]</code></td>
</tr>
<tr>
<td><code>-n </code></td>
<td>检测字符串长度是否不为0,不为0返回true</td>
<td><code>[ -n 'hello' ]</code></td>
</tr>
<tr>
<td><code>$</code></td>
<td>检测字符串是否为空,不为空返回true</td>
<td><code>[ <p>本文主要介绍shell编程的基本语法以及实际应用中的常见命令。</p>
<h1>1. 注释</h1>
<h2>1.1. 单行注释</h2>
<pre><code class="language-shell"># 这是单行注释
</code></pre>
<h2>1.2. 多行注释</h2>
<pre><code class="language-shell">:&lt;&lt;EOF
多行注释内容
多行注释内容
多行注释内容
EOF
</code></pre>
<p>多行注释<code>EOF</code>也可替换成<code>!</code>或<code>&#39;</code></p>
<pre><code class="language-shell">:&lt;&lt;&#39;
多行注释内容
多行注释内容
多行注释内容
&#39;
:&lt;&lt;!
多行注释内容
多行注释内容
多行注释内容
!
</code></pre>
<h1>2. 变量</h1>
<h2>2.1. 变量定义</h2>
<p>使用<code>VARIABLENAME=VALUE</code>的形式,VALUE如果是字符串的话,可以使用单引号、双引号或者不加引号。单引号内的任何字符都会原样输出,不能进行转义,单引号内不能单独出现一个单引号,但可成对出现,作为字符串拼接使用。双引号内可以有变量,可以出现转义字符。</p>
<h2>2.2. 变量使用</h2>
<p>只需要在变量前加<code>$</code>符号,变量加<code>{}</code>是可选的,方便解释器识别边界。将变量加上<code>{}</code>是一个好习惯,不容易出错。</p>
<pre><code class="language-shell">your_age=25
your_name=&quot;shinerio&quot;
your_name=shinerio
your_name=&#39;shinerio&#39;
echo $your_age # 输出25
echo $your_name # 输出shinerio
echo &quot;${your_name}hello&quot; &lt;span class=&quot;tag&quot;&gt;#这里&lt;/span&gt;{}必须添加,否则解释器认为是${your_namehello}
str=&#39;hello&#39;&#39; # 非法
str=&#39;hello&#39;__&#39;world&#39; # 成对出现的单引号做字符拼接
echo $str &lt;span class=&quot;tag&quot;&gt;#输出hello__world&lt;/span&gt;
str1=&#39;helloworld${your_age}\nnew line&#39;
str2=&quot;helloworld${your_age}\nnew line&quot;
echo $str1 # 输出helloworld${your_age}\nnew line
echo $str2 # 输出helloworld25\nnew line
echo -e $str2 # -e开启转义 \n表示换行 echo默认换行,通过\c强制不换行
&lt;span class=&quot;tag&quot;&gt;#helloworld25&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;#new&lt;/span&gt; line
</code></pre>
<h2>2.3. 只读变量</h2>
<p>使用<code>readonly VARIABLENAME</code>设置变量只读,只读变量的值不能更改</p>
<pre><code class="language-shell">readonly name=&#39;jack&#39;
name=&#39;kelly&#39;
zsh: read-only variable: name
</code></pre>
<h2>2.4. 删除变量</h2>
<p>使用<code>unset VARIABLENAME</code>删除变量。</p>
<h1>3. 字符串操作</h1>
<h2>3.1. 字符串拼接</h2>
<pre><code class="language-shell">str1=&quot;hello&quot;${your_name}&quot;world&quot;
str2=&quot;hello${your_name}world&quot;
str3=&#39;hello&#39;${your_name}&#39;world&#39;
</code></pre>
<h2>3.2. 字符串长度</h2>
<pre><code class="language-shell">str=&#39;hello&#39;
echo ${&lt;span class=&quot;tag&quot;&gt;#str&lt;/span&gt;}
5
</code></pre>
<h2>3.3. 字符串截取</h2>
<p><code>${string:start:length}</code>,索引从0开始,从start(包含)开始截取共计length长度的字符。</p>
<pre><code class="language-shell">str=&#39;helloworld&#39;
echo ${str:0:5}
hello
</code></pre>
<h2>3.4. 字符串运算符</h2>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>=</code></td>
<td>检测两个字符串是否相等,相等返回true</td>
<td><code>[ &#39;hello&#39; = &#39;hello&#39; ]</code></td>
</tr>
<tr>
<td><code>!=</code></td>
<td>检测两个字符串是否相等,不相等返回true</td>
<td><code>[ &#39;hello&#39; != &#39;ello&#39; ]</code></td>
</tr>
<tr>
<td><code>-z</code></td>
<td>检测字符串长度是否为0,为0返回true</td>
<td><code>[ -z &#39;&#39; ]</code></td>
</tr>
<tr>
<td><code>-n </code></td>
<td>检测字符串长度是否不为0,不为0返回true</td>
<td><code>[ -n &#39;hello&#39; ]</code></td>
</tr>
<tr>
<td><code>$</code></td>
<td>检测字符串是否为空,不为空返回true</td>
<td><code>[ $&#39;hello&#39; ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ &#39;hello&#39; = &#39;hello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ &#39;hello&#39; != &#39;ello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ -z &#39;&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ -n &#39;hello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ $&#39;hello&#39; ];then echo &#39;hello&#39;;fi
str=&#39;hello&#39;
if [ $str ];then echo &#39;hello&#39;;fi
# hello
</code></pre>
<p>注意字符串的等值判断是一个等号<code>&quot;=&quot;</code>,与下文要讲的逻辑运算符使用两个等号<code>&quot;==&quot;</code>做等值判断不一样。</p>
<h1>4. 文件测试运算符</h1>
<table>
<thead>
<tr>
<th>操作符</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>-b file</code></td>
<td>检测文件是否是块设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-c file</code></td>
<td>检测文件是否是字符设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-d file</code></td>
<td>检测文件是否是目录,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-f file</code></td>
<td>检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-g file</code></td>
<td>检测文件是否设置了<code>SGID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-k file</code></td>
<td>检测文件是否设置了粘着位(Sticky Bit),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-p file</code></td>
<td>检测文件是否是有名管道,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-u file</code></td>
<td>检测文件是否设置了<code>SUID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-r file</code></td>
<td>检测文件是否可读,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-w file</code></td>
<td>检测文件是否可写,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-x file</code></td>
<td>检测文件是否可执行,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-s file</code></td>
<td>检测文件是否为空(文件大小是否大于0),不为空返回true。</td>
</tr>
<tr>
<td><code>-e file</code></td>
<td>检测文件(包括目录)是否存在,如果是,则返回true。</td>
</tr>
</tbody></table>
<pre><code class="language-shell">if &lt;a href=&quot;f-home.html&quot; class=&quot;internal-link&quot;&gt; -f &#39;/home&#39; &lt;/a&gt;;then echo &#39;directory&#39;;else echo &#39;file&#39;;fi
# file
if &lt;a href=&quot;d-home.html&quot; class=&quot;internal-link&quot;&gt; -d &#39;/home&#39; &lt;/a&gt;;then echo &#39;directory&#39;;else echo &#39;file&#39;;fi
# directory
if &lt;a href=&quot;e-tmpfake-file.html&quot; class=&quot;internal-link&quot;&gt; -e &#39;/tmp/fake_file&#39; &lt;/a&gt;;then echo &#39;exist&#39;;else echo &#39;not exist&#39;;fi
# not exist
</code></pre>
<h1>5. 数组</h1>
<p><code>shell</code>只支持一维数组,用括号表示,元素通过空格分隔,形如<code>数组名=(值1 值2 ... 值n)</code>。<code>shell</code>数组下标从<code>1</code>开始。</p>
<ul>
<li><code>${数组名[下标]}</code>,读取指索引位置数组元素</li>
<li>使用<code>@</code>或<code>*</code>代替下标,获取数组中所有元素。</li>
<li>使用<code>{&lt;span class=&quot;tag&quot;&gt;#数组名&lt;/span&gt;[@]}</code>或<code>{&lt;span class=&quot;tag&quot;&gt;#数组名&lt;/span&gt;[*]}</code>获取数组元素个数。</li>
</ul>
<pre><code class="language-shell">arr=(value1 value2 value3 value4)
echo ${arr[3]}
# value3
echo ${arr[*]}
# value1 value2 value3 value4
echo ${arr[@]}
# value1 value2 value3 value4
arr[3]=&#39;new_value3&#39;
echo $arr[3]
# new_value3
echo ${&lt;span class=&quot;tag&quot;&gt;#arr&lt;/span&gt;[@]}
# 4
echo &quot;arr[1]的长度为:${&lt;span class=&quot;tag&quot;&gt;#arr&lt;/span&gt;[1]}&quot;
# arr[1]的长度为:6
</code></pre>
<h1>6. 运算符</h1>
<h2>6.1. 赋值运算符</h2>
<pre><code class="language-shell">a=10
b=$a
</code></pre>
<h2>6.2. 算术运算符</h2>
<p>算数运算符支持<code>+,-,*,/,%</code></p>
<h3>6.2.1. expr表示法</h3>
<pre><code class="language-shell">echo `expr 10 + 20`
# 30
echo $(expr 20 / 2)
# 10
echo $(expr 10 \* 20) # 使用expr进行乘法运算时必须使用\进行转义
# 200
</code></pre>
<blockquote>
<p>使用expr表示方法时,表达式和运算符之间必须有空格。</p>
</blockquote>
<h3>6.2.2. <code>$[]</code></h3>
<pre><code class="language-shell">echo $[10%3]
# 1
</code></pre>
<h3>6.2.3. <code>$(())</code></h3>
<pre><code class="language-shell">echo $((10*20))
# 200
</code></pre>
<h2>6.3. 关系运算符</h2>
<p>最常见的关系运算符是:<code>==,!=,&lt;,&gt;,&gt;=,&lt;=</code></p>
<pre><code class="language-shell">echo $[10==10]
# 1
flag=$[20==10]
echo $flag
# 1
echo $[10&gt;=10]
# 1
</code></pre>
<p>如下关系运算符只能使用在条件表达式<code>if、while</code>下,类似<code>flag=[ $a -eq $b ]</code>的直接赋值语句是非法的。关系运算符的条件表达式要放在<strong>一对</strong>方括号中,并且中间需要有空格。也可以使用<code>(())</code>替代<code>[]</code>,此时<code>-eq,-lt,-le</code>之类的需要使用<code>==,&lt;,&lt;=</code>等替换。</p>
<blockquote>
<p><code>[]</code>搭配<code>-eq -ne</code>等使用,<code>(())</code>搭配<code>|| &amp;&amp;</code>等使用。</p>
</blockquote>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>-eq</code></td>
<td>检测两个数是否相等,相等返回true。</td>
<td><code>[ $a -eq $b ]</code></td>
</tr>
<tr>
<td><code>-ne</code></td>
<td>检测两个数是否不相等,不相等返回 true。</td>
<td><code>[ $a -ne $b ]</code></td>
</tr>
<tr>
<td><code>-gt</code></td>
<td>检测左边的数是否大于右边的,如果是,则返回 true。</td>
<td><code>[ $a -gt $b ]</code></td>
</tr>
<tr>
<td><code>-lt</code></td>
<td>检测左边的数是否小于右边的,如果是,则返回 true。</td>
<td><code>[ $a -lt $b ]</code></td>
</tr>
<tr>
<td><code>-ge</code></td>
<td>检测左边的数是否大于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -ge $b ]</code></td>
</tr>
<tr>
<td><code>-le</code></td>
<td>检测左边的数是否小于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -le $b ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ 1 -eq 1 ];then echo &#39;hello&#39;;fi;
# hello
if ((10&gt;=10));then echo &#39;hello&#39;;fi;
# hello
</code></pre>
<h2>6.4. 布尔、逻辑运算符</h2>
<p>布尔、逻辑运算的条件表达式也要放在一对方括号中<code>[]</code>。</p>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>!</code></td>
<td>非运算,表达式为true则返回false,否则返回true。</td>
<td><code>[ ! 10 -eq 0 ]</code></td>
</tr>
<tr>
<td><code>-o</code></td>
<td>或运算,有一个表达式为true则返回true。</td>
<td><code>[ 10 -lt 20 -o 10 -gt 100 ]</code></td>
</tr>
<tr>
<td><code>-a</code></td>
<td>与运算,两个表达式都为true才返回true。</td>
<td><code>[ 10 -lt 20 -a 10 -gt 100 ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ ! 10 -eq 0 ];then echo &#39;hello&#39;;fi
# hello
if [ 10 -ge 10 -a 10 -ge 10 ];then echo &#39;hello&#39;;fi
# hello
if [ 10 -ge 20 -o 10 -ge 0 ];then echo &#39;hello&#39;;fi
# hello
</code></pre>
<p> <code>-o</code>也可以使用<code>||</code>替代,<code>-a</code>也可以使用<code>&amp;&amp;</code>替代,此时需要使用<code>(())</code>或<code>[[]]</code>替代<code>[]</code>。</p>
<pre><code class="language-shell">if &lt;a href=&quot;1010-55.html&quot; class=&quot;internal-link&quot;&gt; 10==10 &amp;&amp; 5==5 &lt;/a&gt;;then echo &#39;hello&#39;;fi
# hello
if ((10==10 &amp;&amp; 5==5));then echo &#39;hello&#39;;fi
# hello
</code></pre>
<h1>7. 传递参数</h1>
<p>在执行 <code>Shell</code>脚本时,向脚本传递参数,脚本内获取参数的格式为:<code>$n</code>。<code>n</code>代表一个数字,<code>1</code>为执行脚本的第一个参数,<code>2</code>为执行脚本的第二个参数,<code>$0</code>为执行的文件名。在为<code>shell</code>脚本传递的参数中如果包含空格,应该使用单引号或者双引号将该参数括起来,以便于脚本将这个参数作为整体来接收。另外,还有几个特殊字符用来处理参数:</p>
<table>
<thead>
<tr>
<th>参数处理</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>$#</code></td>
<td>传递到脚本的参数个数</td>
</tr>
<tr>
<td><code>$*</code></td>
<td>以一个单字符串显示所有向脚本传递的参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$$</code></td>
<td>脚本运行的当前进程ID号</td>
</tr>
<tr>
<td><code>$!</code></td>
<td>后台运行的最后一个进程的ID号</td>
</tr>
<tr>
<td><code>$@</code></td>
<td>与<code>$*</code>相同,但是使用时加引号,并在引号中返回每个参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$-</code></td>
<td>显示Shell使用的当前选项,与set功能相同。</td>
</tr>
<tr>
<td><code>$?</code></td>
<td>显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。</td>
</tr>
</tbody></table>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-bash">set -e
echo &quot;执行的文件名:$0&quot;
echo &quot;参数个数为$#&quot;
echo &quot;第一个参数为:$1&quot;
echo &quot;第二个参数为:$2&quot;
echo &quot;所有参数为:$@&quot;
echo &quot;进程ID号为:$$&quot;
echo &quot;当前shell选项为$-&quot;
echo &quot;上一个命令退出的状态为$?&quot;
</code></pre>
<p>执行结果如下:</p>
<pre><code class="language-shell">$ sh test.sh param1 &quot;param2 with space&quot;
执行的文件名:test.sh
参数个数为2
第一个参数为:param1
第二个参数为:param2 with space
所有参数为:param1 param2 with space
进程ID号为:3700
当前shell选项为ehB
上一个命令退出的状态为0
</code></pre>
<h1>8. 函数</h1>
<p>函数定义通过<code>function_name(){}</code>的形式定义,函数返回值可以显示用return返回,如果不加,将以最后一条命令的运行结果作为返回值,函数返回值只能是数字。函数也可以传递参数,但是函数定义的()中不需要申明。</p>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-shell">sayhello(){
echo &quot;hello&quot;
}
# 注意函数调用只需要函数名,不需要加()
sayhello
sayhellowithparam(){
echo &quot;hello, $1 $2 $3&quot;
return 1
}
sayhellowithparam zhangsan lisi wangwu
echo $?
</code></pre>
<p>输出如下:</p>
<blockquote>
<p>hello<br>hello, zhangsan lisi wangwu<br>1</p>
</blockquote>
<h1>9. 命令替换</h1>
<p>命令替换可以将一个命令的输出作为另外一个命令的参数。</p>
<pre><code class="language-shell"># command1 `command2`
cd `pwd` # 该命令将pwd命令列出的目录作为cd命令的参数,结果仍然是停留在当前目录下
cd `echo $HOME` # 将echo的输出作为cd的参数,即打开用户根目录
</code></pre>
<h1>10. let命令</h1>
<p>let 命令是 BASH 中用于计算的工具,用于执行一个或多个表达式,变量计算中不需要加上 $ 来表示变量。如果表达式中包含了空格或其他特殊字符,则必须引起来。</p>
<ul>
<li>自加操作:<code>let no++</code></li>
<li>自减操作:<code>let no--</code></li>
<li>简写形式 <code>let no+=10</code>,<code>let no-=20</code>,分别等同于<code>let no=no+10</code>,<code>let no=no-20</code></li>
</ul>
<h1>11. 流程控制</h1>
<h2>11.1. if</h2>
<pre><code class="language-shell">if ((10&lt;2));then
echo &quot;10小于2&quot;
elif ((10&gt;20));then
echo &quot;a大于10&quot;
else
echo &quot;10大于2且小于10&quot;
fi
</code></pre>
<h2>11.2. case</h2>
<p><code>case</code>每一种情况以右括号结尾,执行到<code>;;</code>结束</p>
<pre><code class="language-shell">case 10 in
0|1)
echo &quot;a为0或1&quot;
;;
11|12)
echo &quot;a为11或12&quot;
;;
*)
# *用来匹配所有情况
echo &quot;a为10&quot;
;;
esac
</code></pre>
<h2>11.3. while</h2>
<pre><code class="language-shell">count=0
while(($count&lt;5))
do
echo $count
let count++
done
</code></pre>
<h2>11.4. util</h2>
<pre><code class="language-shell">count=0
until(($count&gt;=5))
do
echo $count
let count++
done
</code></pre>
<h2>11.5. for</h2>
<pre><code class="language-shell"># for写法1
for ((count=0;$count&lt;5;count=$count+1))
do
echo $count
done
# for写法2
arr=(0 1 2 3 4)
for count in ${arr[*]}
do
echo $int
done
# for写法3
for int in 0 1 2 3 4
do
echo $int
done
</code></pre>
<h2>11.6. break和continue</h2>
<p>用法与一般编程语言类似,break跳出循环,continue跳出当前循环</p>
<pre><code class="language-shell">for ((count=0;$count&gt;=0;count=$count+1))
do
if (($count&gt;=5));then
break;
fi
echo $count
done
</code></pre>
<h1>12. 输入输出重定向</h1>
<h2>12.1. 输出重定向</h2>
<p><code>command &gt; file</code>将命令输出结果保存的file文件中。<code>&gt;</code>从文件头开始写,会覆盖旧内容,<code>&gt;&gt;</code>将内容追加到文件末尾</p>
<pre><code class="language-shell"># 将who命令的输出保存的users文件中,可以通过cat users查看
who &gt; users
# 将字符串hello world保存到text.txt文件中
echo &quot;hello world&quot; &gt; text.txt
</code></pre>
<h2>12.2. 输入重定向</h2>
<p><code>command &lt; file</code>从file文件获取输入</p>
<pre><code class="language-shell">wc -l /etc/passwd
# 123 /etc/passwd
wc -l &lt; users
# 123
# 第一个例子,会输出文件名;第二个不会,因为它仅仅知道从标准输入读取内容
# command &lt; infile &gt; outfile, 同时替换输入和输出,执行command,从文件infile读取内容,然后将输出写入到outfile中。
wc -l &lt; /etc/passwd &gt; result
cat result
# 123
</code></pre>
<h2>12.3. 文件描述符</h2>
<p>一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件</p>
<ul>
<li>标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。</li>
<li>标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。</li>
<li>标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。</li>
</ul>
<pre><code class="language-shell"># 将标准错误输出重定向到error_trace
cat /tmp/fake_file 2&gt;error_trace
cat error_trace
# cat: /tmp/fake_fule: No such file or directory
# 将标准输出和标准错误输出都重定向到result
cat /tmp/fake_file &amp;&gt;result
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准错误重定向到标准输出
ls /tmp/fake_file &gt; result 2&gt;&amp;1
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准输入重定向到result,将标准错误输出重定向到error_trace
cat /tmp/fake_file 1&gt;result 2&gt;error_trace
</code></pre>
<h2>12.4. Here Document</h2>
<p>将两个<code>EOF</code>之间的内容(document) 作为输入传递给<code>command</code></p>
<pre><code class="language-bash"># command &lt;&lt; EOF
# document
# EOF
cat &lt;&lt; EOF
hello
shinerio
learn shell
EOF
</code></pre>
<blockquote>
<p>结尾的<code>EOF</code>一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和<code>tab</code>缩进。开始的<code>EOF</code>前后的空格会被忽略掉。</p>
</blockquote>
<h2>12.5. /dev/null</h2>
<p>如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null。<code>command &gt; /dev/null</code></p>
<pre><code class="language-shell">cat users &gt; /dev/null
cat users &gt; /dev/null 2&gt;&amp;1
</code></pre>
<h1>13. set命令</h1>
<p>set指令能设置所使用shell的执行方式,可依照不同的需求来做设置。以下只列出常用的选项参数:</p>
<ul>
<li>-e 若指令传回值不等于0,则立即退出shell。</li>
<li>-f 取消使用通配符。</li>
<li>-n 只读取指令,而不实际执行。</li>
<li>-x 执行指令后,会先显示该指令及所下的参数。</li>
</ul>
#39;hello' ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ 'hello' = 'hello' ];then echo 'hello';fi
# hello
if [ 'hello' != 'ello' ];then echo 'hello';fi
# hello
if [ -z '' ];then echo 'hello';fi
# hello
if [ -n 'hello' ];then echo 'hello';fi
# hello
if [ <p>本文主要介绍shell编程的基本语法以及实际应用中的常见命令。</p>
<h1>1. 注释</h1>
<h2>1.1. 单行注释</h2>
<pre><code class="language-shell"># 这是单行注释
</code></pre>
<h2>1.2. 多行注释</h2>
<pre><code class="language-shell">:&lt;&lt;EOF
多行注释内容
多行注释内容
多行注释内容
EOF
</code></pre>
<p>多行注释<code>EOF</code>也可替换成<code>!</code>或<code>&#39;</code></p>
<pre><code class="language-shell">:&lt;&lt;&#39;
多行注释内容
多行注释内容
多行注释内容
&#39;
:&lt;&lt;!
多行注释内容
多行注释内容
多行注释内容
!
</code></pre>
<h1>2. 变量</h1>
<h2>2.1. 变量定义</h2>
<p>使用<code>VARIABLENAME=VALUE</code>的形式,VALUE如果是字符串的话,可以使用单引号、双引号或者不加引号。单引号内的任何字符都会原样输出,不能进行转义,单引号内不能单独出现一个单引号,但可成对出现,作为字符串拼接使用。双引号内可以有变量,可以出现转义字符。</p>
<h2>2.2. 变量使用</h2>
<p>只需要在变量前加<code>$</code>符号,变量加<code>{}</code>是可选的,方便解释器识别边界。将变量加上<code>{}</code>是一个好习惯,不容易出错。</p>
<pre><code class="language-shell">your_age=25
your_name=&quot;shinerio&quot;
your_name=shinerio
your_name=&#39;shinerio&#39;
echo $your_age # 输出25
echo $your_name # 输出shinerio
echo &quot;${your_name}hello&quot; &lt;span class=&quot;tag&quot;&gt;#这里&lt;/span&gt;{}必须添加,否则解释器认为是${your_namehello}
str=&#39;hello&#39;&#39; # 非法
str=&#39;hello&#39;__&#39;world&#39; # 成对出现的单引号做字符拼接
echo $str &lt;span class=&quot;tag&quot;&gt;#输出hello__world&lt;/span&gt;
str1=&#39;helloworld${your_age}\nnew line&#39;
str2=&quot;helloworld${your_age}\nnew line&quot;
echo $str1 # 输出helloworld${your_age}\nnew line
echo $str2 # 输出helloworld25\nnew line
echo -e $str2 # -e开启转义 \n表示换行 echo默认换行,通过\c强制不换行
&lt;span class=&quot;tag&quot;&gt;#helloworld25&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;#new&lt;/span&gt; line
</code></pre>
<h2>2.3. 只读变量</h2>
<p>使用<code>readonly VARIABLENAME</code>设置变量只读,只读变量的值不能更改</p>
<pre><code class="language-shell">readonly name=&#39;jack&#39;
name=&#39;kelly&#39;
zsh: read-only variable: name
</code></pre>
<h2>2.4. 删除变量</h2>
<p>使用<code>unset VARIABLENAME</code>删除变量。</p>
<h1>3. 字符串操作</h1>
<h2>3.1. 字符串拼接</h2>
<pre><code class="language-shell">str1=&quot;hello&quot;${your_name}&quot;world&quot;
str2=&quot;hello${your_name}world&quot;
str3=&#39;hello&#39;${your_name}&#39;world&#39;
</code></pre>
<h2>3.2. 字符串长度</h2>
<pre><code class="language-shell">str=&#39;hello&#39;
echo ${&lt;span class=&quot;tag&quot;&gt;#str&lt;/span&gt;}
5
</code></pre>
<h2>3.3. 字符串截取</h2>
<p><code>${string:start:length}</code>,索引从0开始,从start(包含)开始截取共计length长度的字符。</p>
<pre><code class="language-shell">str=&#39;helloworld&#39;
echo ${str:0:5}
hello
</code></pre>
<h2>3.4. 字符串运算符</h2>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>=</code></td>
<td>检测两个字符串是否相等,相等返回true</td>
<td><code>[ &#39;hello&#39; = &#39;hello&#39; ]</code></td>
</tr>
<tr>
<td><code>!=</code></td>
<td>检测两个字符串是否相等,不相等返回true</td>
<td><code>[ &#39;hello&#39; != &#39;ello&#39; ]</code></td>
</tr>
<tr>
<td><code>-z</code></td>
<td>检测字符串长度是否为0,为0返回true</td>
<td><code>[ -z &#39;&#39; ]</code></td>
</tr>
<tr>
<td><code>-n </code></td>
<td>检测字符串长度是否不为0,不为0返回true</td>
<td><code>[ -n &#39;hello&#39; ]</code></td>
</tr>
<tr>
<td><code>$</code></td>
<td>检测字符串是否为空,不为空返回true</td>
<td><code>[ $&#39;hello&#39; ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ &#39;hello&#39; = &#39;hello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ &#39;hello&#39; != &#39;ello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ -z &#39;&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ -n &#39;hello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ $&#39;hello&#39; ];then echo &#39;hello&#39;;fi
str=&#39;hello&#39;
if [ $str ];then echo &#39;hello&#39;;fi
# hello
</code></pre>
<p>注意字符串的等值判断是一个等号<code>&quot;=&quot;</code>,与下文要讲的逻辑运算符使用两个等号<code>&quot;==&quot;</code>做等值判断不一样。</p>
<h1>4. 文件测试运算符</h1>
<table>
<thead>
<tr>
<th>操作符</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>-b file</code></td>
<td>检测文件是否是块设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-c file</code></td>
<td>检测文件是否是字符设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-d file</code></td>
<td>检测文件是否是目录,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-f file</code></td>
<td>检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-g file</code></td>
<td>检测文件是否设置了<code>SGID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-k file</code></td>
<td>检测文件是否设置了粘着位(Sticky Bit),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-p file</code></td>
<td>检测文件是否是有名管道,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-u file</code></td>
<td>检测文件是否设置了<code>SUID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-r file</code></td>
<td>检测文件是否可读,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-w file</code></td>
<td>检测文件是否可写,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-x file</code></td>
<td>检测文件是否可执行,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-s file</code></td>
<td>检测文件是否为空(文件大小是否大于0),不为空返回true。</td>
</tr>
<tr>
<td><code>-e file</code></td>
<td>检测文件(包括目录)是否存在,如果是,则返回true。</td>
</tr>
</tbody></table>
<pre><code class="language-shell">if &lt;a href=&quot;f-home.html&quot; class=&quot;internal-link&quot;&gt; -f &#39;/home&#39; &lt;/a&gt;;then echo &#39;directory&#39;;else echo &#39;file&#39;;fi
# file
if &lt;a href=&quot;d-home.html&quot; class=&quot;internal-link&quot;&gt; -d &#39;/home&#39; &lt;/a&gt;;then echo &#39;directory&#39;;else echo &#39;file&#39;;fi
# directory
if &lt;a href=&quot;e-tmpfake-file.html&quot; class=&quot;internal-link&quot;&gt; -e &#39;/tmp/fake_file&#39; &lt;/a&gt;;then echo &#39;exist&#39;;else echo &#39;not exist&#39;;fi
# not exist
</code></pre>
<h1>5. 数组</h1>
<p><code>shell</code>只支持一维数组,用括号表示,元素通过空格分隔,形如<code>数组名=(值1 值2 ... 值n)</code>。<code>shell</code>数组下标从<code>1</code>开始。</p>
<ul>
<li><code>${数组名[下标]}</code>,读取指索引位置数组元素</li>
<li>使用<code>@</code>或<code>*</code>代替下标,获取数组中所有元素。</li>
<li>使用<code>{&lt;span class=&quot;tag&quot;&gt;#数组名&lt;/span&gt;[@]}</code>或<code>{&lt;span class=&quot;tag&quot;&gt;#数组名&lt;/span&gt;[*]}</code>获取数组元素个数。</li>
</ul>
<pre><code class="language-shell">arr=(value1 value2 value3 value4)
echo ${arr[3]}
# value3
echo ${arr[*]}
# value1 value2 value3 value4
echo ${arr[@]}
# value1 value2 value3 value4
arr[3]=&#39;new_value3&#39;
echo $arr[3]
# new_value3
echo ${&lt;span class=&quot;tag&quot;&gt;#arr&lt;/span&gt;[@]}
# 4
echo &quot;arr[1]的长度为:${&lt;span class=&quot;tag&quot;&gt;#arr&lt;/span&gt;[1]}&quot;
# arr[1]的长度为:6
</code></pre>
<h1>6. 运算符</h1>
<h2>6.1. 赋值运算符</h2>
<pre><code class="language-shell">a=10
b=$a
</code></pre>
<h2>6.2. 算术运算符</h2>
<p>算数运算符支持<code>+,-,*,/,%</code></p>
<h3>6.2.1. expr表示法</h3>
<pre><code class="language-shell">echo `expr 10 + 20`
# 30
echo $(expr 20 / 2)
# 10
echo $(expr 10 \* 20) # 使用expr进行乘法运算时必须使用\进行转义
# 200
</code></pre>
<blockquote>
<p>使用expr表示方法时,表达式和运算符之间必须有空格。</p>
</blockquote>
<h3>6.2.2. <code>$[]</code></h3>
<pre><code class="language-shell">echo $[10%3]
# 1
</code></pre>
<h3>6.2.3. <code>$(())</code></h3>
<pre><code class="language-shell">echo $((10*20))
# 200
</code></pre>
<h2>6.3. 关系运算符</h2>
<p>最常见的关系运算符是:<code>==,!=,&lt;,&gt;,&gt;=,&lt;=</code></p>
<pre><code class="language-shell">echo $[10==10]
# 1
flag=$[20==10]
echo $flag
# 1
echo $[10&gt;=10]
# 1
</code></pre>
<p>如下关系运算符只能使用在条件表达式<code>if、while</code>下,类似<code>flag=[ $a -eq $b ]</code>的直接赋值语句是非法的。关系运算符的条件表达式要放在<strong>一对</strong>方括号中,并且中间需要有空格。也可以使用<code>(())</code>替代<code>[]</code>,此时<code>-eq,-lt,-le</code>之类的需要使用<code>==,&lt;,&lt;=</code>等替换。</p>
<blockquote>
<p><code>[]</code>搭配<code>-eq -ne</code>等使用,<code>(())</code>搭配<code>|| &amp;&amp;</code>等使用。</p>
</blockquote>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>-eq</code></td>
<td>检测两个数是否相等,相等返回true。</td>
<td><code>[ $a -eq $b ]</code></td>
</tr>
<tr>
<td><code>-ne</code></td>
<td>检测两个数是否不相等,不相等返回 true。</td>
<td><code>[ $a -ne $b ]</code></td>
</tr>
<tr>
<td><code>-gt</code></td>
<td>检测左边的数是否大于右边的,如果是,则返回 true。</td>
<td><code>[ $a -gt $b ]</code></td>
</tr>
<tr>
<td><code>-lt</code></td>
<td>检测左边的数是否小于右边的,如果是,则返回 true。</td>
<td><code>[ $a -lt $b ]</code></td>
</tr>
<tr>
<td><code>-ge</code></td>
<td>检测左边的数是否大于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -ge $b ]</code></td>
</tr>
<tr>
<td><code>-le</code></td>
<td>检测左边的数是否小于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -le $b ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ 1 -eq 1 ];then echo &#39;hello&#39;;fi;
# hello
if ((10&gt;=10));then echo &#39;hello&#39;;fi;
# hello
</code></pre>
<h2>6.4. 布尔、逻辑运算符</h2>
<p>布尔、逻辑运算的条件表达式也要放在一对方括号中<code>[]</code>。</p>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>!</code></td>
<td>非运算,表达式为true则返回false,否则返回true。</td>
<td><code>[ ! 10 -eq 0 ]</code></td>
</tr>
<tr>
<td><code>-o</code></td>
<td>或运算,有一个表达式为true则返回true。</td>
<td><code>[ 10 -lt 20 -o 10 -gt 100 ]</code></td>
</tr>
<tr>
<td><code>-a</code></td>
<td>与运算,两个表达式都为true才返回true。</td>
<td><code>[ 10 -lt 20 -a 10 -gt 100 ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ ! 10 -eq 0 ];then echo &#39;hello&#39;;fi
# hello
if [ 10 -ge 10 -a 10 -ge 10 ];then echo &#39;hello&#39;;fi
# hello
if [ 10 -ge 20 -o 10 -ge 0 ];then echo &#39;hello&#39;;fi
# hello
</code></pre>
<p> <code>-o</code>也可以使用<code>||</code>替代,<code>-a</code>也可以使用<code>&amp;&amp;</code>替代,此时需要使用<code>(())</code>或<code>[[]]</code>替代<code>[]</code>。</p>
<pre><code class="language-shell">if &lt;a href=&quot;1010-55.html&quot; class=&quot;internal-link&quot;&gt; 10==10 &amp;&amp; 5==5 &lt;/a&gt;;then echo &#39;hello&#39;;fi
# hello
if ((10==10 &amp;&amp; 5==5));then echo &#39;hello&#39;;fi
# hello
</code></pre>
<h1>7. 传递参数</h1>
<p>在执行 <code>Shell</code>脚本时,向脚本传递参数,脚本内获取参数的格式为:<code>$n</code>。<code>n</code>代表一个数字,<code>1</code>为执行脚本的第一个参数,<code>2</code>为执行脚本的第二个参数,<code>$0</code>为执行的文件名。在为<code>shell</code>脚本传递的参数中如果包含空格,应该使用单引号或者双引号将该参数括起来,以便于脚本将这个参数作为整体来接收。另外,还有几个特殊字符用来处理参数:</p>
<table>
<thead>
<tr>
<th>参数处理</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>$#</code></td>
<td>传递到脚本的参数个数</td>
</tr>
<tr>
<td><code>$*</code></td>
<td>以一个单字符串显示所有向脚本传递的参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$$</code></td>
<td>脚本运行的当前进程ID号</td>
</tr>
<tr>
<td><code>$!</code></td>
<td>后台运行的最后一个进程的ID号</td>
</tr>
<tr>
<td><code>$@</code></td>
<td>与<code>$*</code>相同,但是使用时加引号,并在引号中返回每个参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$-</code></td>
<td>显示Shell使用的当前选项,与set功能相同。</td>
</tr>
<tr>
<td><code>$?</code></td>
<td>显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。</td>
</tr>
</tbody></table>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-bash">set -e
echo &quot;执行的文件名:$0&quot;
echo &quot;参数个数为$#&quot;
echo &quot;第一个参数为:$1&quot;
echo &quot;第二个参数为:$2&quot;
echo &quot;所有参数为:$@&quot;
echo &quot;进程ID号为:$$&quot;
echo &quot;当前shell选项为$-&quot;
echo &quot;上一个命令退出的状态为$?&quot;
</code></pre>
<p>执行结果如下:</p>
<pre><code class="language-shell">$ sh test.sh param1 &quot;param2 with space&quot;
执行的文件名:test.sh
参数个数为2
第一个参数为:param1
第二个参数为:param2 with space
所有参数为:param1 param2 with space
进程ID号为:3700
当前shell选项为ehB
上一个命令退出的状态为0
</code></pre>
<h1>8. 函数</h1>
<p>函数定义通过<code>function_name(){}</code>的形式定义,函数返回值可以显示用return返回,如果不加,将以最后一条命令的运行结果作为返回值,函数返回值只能是数字。函数也可以传递参数,但是函数定义的()中不需要申明。</p>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-shell">sayhello(){
echo &quot;hello&quot;
}
# 注意函数调用只需要函数名,不需要加()
sayhello
sayhellowithparam(){
echo &quot;hello, $1 $2 $3&quot;
return 1
}
sayhellowithparam zhangsan lisi wangwu
echo $?
</code></pre>
<p>输出如下:</p>
<blockquote>
<p>hello<br>hello, zhangsan lisi wangwu<br>1</p>
</blockquote>
<h1>9. 命令替换</h1>
<p>命令替换可以将一个命令的输出作为另外一个命令的参数。</p>
<pre><code class="language-shell"># command1 `command2`
cd `pwd` # 该命令将pwd命令列出的目录作为cd命令的参数,结果仍然是停留在当前目录下
cd `echo $HOME` # 将echo的输出作为cd的参数,即打开用户根目录
</code></pre>
<h1>10. let命令</h1>
<p>let 命令是 BASH 中用于计算的工具,用于执行一个或多个表达式,变量计算中不需要加上 $ 来表示变量。如果表达式中包含了空格或其他特殊字符,则必须引起来。</p>
<ul>
<li>自加操作:<code>let no++</code></li>
<li>自减操作:<code>let no--</code></li>
<li>简写形式 <code>let no+=10</code>,<code>let no-=20</code>,分别等同于<code>let no=no+10</code>,<code>let no=no-20</code></li>
</ul>
<h1>11. 流程控制</h1>
<h2>11.1. if</h2>
<pre><code class="language-shell">if ((10&lt;2));then
echo &quot;10小于2&quot;
elif ((10&gt;20));then
echo &quot;a大于10&quot;
else
echo &quot;10大于2且小于10&quot;
fi
</code></pre>
<h2>11.2. case</h2>
<p><code>case</code>每一种情况以右括号结尾,执行到<code>;;</code>结束</p>
<pre><code class="language-shell">case 10 in
0|1)
echo &quot;a为0或1&quot;
;;
11|12)
echo &quot;a为11或12&quot;
;;
*)
# *用来匹配所有情况
echo &quot;a为10&quot;
;;
esac
</code></pre>
<h2>11.3. while</h2>
<pre><code class="language-shell">count=0
while(($count&lt;5))
do
echo $count
let count++
done
</code></pre>
<h2>11.4. util</h2>
<pre><code class="language-shell">count=0
until(($count&gt;=5))
do
echo $count
let count++
done
</code></pre>
<h2>11.5. for</h2>
<pre><code class="language-shell"># for写法1
for ((count=0;$count&lt;5;count=$count+1))
do
echo $count
done
# for写法2
arr=(0 1 2 3 4)
for count in ${arr[*]}
do
echo $int
done
# for写法3
for int in 0 1 2 3 4
do
echo $int
done
</code></pre>
<h2>11.6. break和continue</h2>
<p>用法与一般编程语言类似,break跳出循环,continue跳出当前循环</p>
<pre><code class="language-shell">for ((count=0;$count&gt;=0;count=$count+1))
do
if (($count&gt;=5));then
break;
fi
echo $count
done
</code></pre>
<h1>12. 输入输出重定向</h1>
<h2>12.1. 输出重定向</h2>
<p><code>command &gt; file</code>将命令输出结果保存的file文件中。<code>&gt;</code>从文件头开始写,会覆盖旧内容,<code>&gt;&gt;</code>将内容追加到文件末尾</p>
<pre><code class="language-shell"># 将who命令的输出保存的users文件中,可以通过cat users查看
who &gt; users
# 将字符串hello world保存到text.txt文件中
echo &quot;hello world&quot; &gt; text.txt
</code></pre>
<h2>12.2. 输入重定向</h2>
<p><code>command &lt; file</code>从file文件获取输入</p>
<pre><code class="language-shell">wc -l /etc/passwd
# 123 /etc/passwd
wc -l &lt; users
# 123
# 第一个例子,会输出文件名;第二个不会,因为它仅仅知道从标准输入读取内容
# command &lt; infile &gt; outfile, 同时替换输入和输出,执行command,从文件infile读取内容,然后将输出写入到outfile中。
wc -l &lt; /etc/passwd &gt; result
cat result
# 123
</code></pre>
<h2>12.3. 文件描述符</h2>
<p>一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件</p>
<ul>
<li>标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。</li>
<li>标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。</li>
<li>标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。</li>
</ul>
<pre><code class="language-shell"># 将标准错误输出重定向到error_trace
cat /tmp/fake_file 2&gt;error_trace
cat error_trace
# cat: /tmp/fake_fule: No such file or directory
# 将标准输出和标准错误输出都重定向到result
cat /tmp/fake_file &amp;&gt;result
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准错误重定向到标准输出
ls /tmp/fake_file &gt; result 2&gt;&amp;1
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准输入重定向到result,将标准错误输出重定向到error_trace
cat /tmp/fake_file 1&gt;result 2&gt;error_trace
</code></pre>
<h2>12.4. Here Document</h2>
<p>将两个<code>EOF</code>之间的内容(document) 作为输入传递给<code>command</code></p>
<pre><code class="language-bash"># command &lt;&lt; EOF
# document
# EOF
cat &lt;&lt; EOF
hello
shinerio
learn shell
EOF
</code></pre>
<blockquote>
<p>结尾的<code>EOF</code>一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和<code>tab</code>缩进。开始的<code>EOF</code>前后的空格会被忽略掉。</p>
</blockquote>
<h2>12.5. /dev/null</h2>
<p>如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null。<code>command &gt; /dev/null</code></p>
<pre><code class="language-shell">cat users &gt; /dev/null
cat users &gt; /dev/null 2&gt;&amp;1
</code></pre>
<h1>13. set命令</h1>
<p>set指令能设置所使用shell的执行方式,可依照不同的需求来做设置。以下只列出常用的选项参数:</p>
<ul>
<li>-e 若指令传回值不等于0,则立即退出shell。</li>
<li>-f 取消使用通配符。</li>
<li>-n 只读取指令,而不实际执行。</li>
<li>-x 执行指令后,会先显示该指令及所下的参数。</li>
</ul>
#39;hello' ];then echo 'hello';fi
str='hello'
if [ $str ];then echo 'hello';fi
# hello
</code></pre>
<p>注意字符串的等值判断是一个等号<code>"="</code>,与下文要讲的逻辑运算符使用两个等号<code>"=="</code>做等值判断不一样。</p>
<h1>4. 文件测试运算符</h1>
<table>
<thead>
<tr>
<th>操作符</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>-b file</code></td>
<td>检测文件是否是块设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-c file</code></td>
<td>检测文件是否是字符设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-d file</code></td>
<td>检测文件是否是目录,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-f file</code></td>
<td>检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-g file</code></td>
<td>检测文件是否设置了<code>SGID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-k file</code></td>
<td>检测文件是否设置了粘着位(Sticky Bit),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-p file</code></td>
<td>检测文件是否是有名管道,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-u file</code></td>
<td>检测文件是否设置了<code>SUID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-r file</code></td>
<td>检测文件是否可读,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-w file</code></td>
<td>检测文件是否可写,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-x file</code></td>
<td>检测文件是否可执行,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-s file</code></td>
<td>检测文件是否为空(文件大小是否大于0),不为空返回true。</td>
</tr>
<tr>
<td><code>-e file</code></td>
<td>检测文件(包括目录)是否存在,如果是,则返回true。</td>
</tr>
</tbody></table>
<pre><code class="language-shell">if <a href="f-home.html" class="internal-link"> -f '/home' </a>;then echo 'directory';else echo 'file';fi
# file
if <a href="d-home.html" class="internal-link"> -d '/home' </a>;then echo 'directory';else echo 'file';fi
# directory
if <a href="e-tmpfake-file.html" class="internal-link"> -e '/tmp/fake_file' </a>;then echo 'exist';else echo 'not exist';fi
# not exist
</code></pre>
<h1>5. 数组</h1>
<p><code>shell</code>只支持一维数组,用括号表示,元素通过空格分隔,形如<code>数组名=(值1 值2 ... 值n)</code>。<code>shell</code>数组下标从<code>1</code>开始。</p>
<ul>
<li><code>${数组名[下标]}</code>,读取指索引位置数组元素</li>
<li>使用<code>@</code>或<code>*</code>代替下标,获取数组中所有元素。</li>
<li>使用<code>{<span class="tag">#数组名</span>[@]}</code>或<code>{<span class="tag">#数组名</span>[*]}</code>获取数组元素个数。</li>
</ul>
<pre><code class="language-shell">arr=(value1 value2 value3 value4)
echo ${arr[3]}
# value3
echo ${arr[*]}
# value1 value2 value3 value4
echo ${arr[@]}
# value1 value2 value3 value4
arr[3]='new_value3'
echo $arr[3]
# new_value3
echo ${<span class="tag">#arr</span>[@]}
# 4
echo "arr[1]的长度为:${<span class="tag">#arr</span>[1]}"
# arr[1]的长度为:6
</code></pre>
<h1>6. 运算符</h1>
<h2>6.1. 赋值运算符</h2>
<pre><code class="language-shell">a=10
b=$a
</code></pre>
<h2>6.2. 算术运算符</h2>
<p>算数运算符支持<code>+,-,*,/,%</code></p>
<h3>6.2.1. expr表示法</h3>
<pre><code class="language-shell">echo `expr 10 + 20`
# 30
echo $(expr 20 / 2)
# 10
echo $(expr 10 \* 20) # 使用expr进行乘法运算时必须使用\进行转义
# 200
</code></pre>
<blockquote>
<p>使用expr表示方法时,表达式和运算符之间必须有空格。</p>
</blockquote>
<h3>6.2.2. <code>$[]</code></h3>
<pre><code class="language-shell">echo $[10%3]
# 1
</code></pre>
<h3>6.2.3. <code>$(())</code></h3>
<pre><code class="language-shell">echo $((10*20))
# 200
</code></pre>
<h2>6.3. 关系运算符</h2>
<p>最常见的关系运算符是:<code>==,!=,<,>,>=,<=</code></p>
<pre><code class="language-shell">echo $[10==10]
# 1
flag=$[20==10]
echo $flag
# 1
echo $[10>=10]
# 1
</code></pre>
<p>如下关系运算符只能使用在条件表达式<code>if、while</code>下,类似<code>flag=[ $a -eq $b ]</code>的直接赋值语句是非法的。关系运算符的条件表达式要放在<strong>一对</strong>方括号中,并且中间需要有空格。也可以使用<code>(())</code>替代<code>[]</code>,此时<code>-eq,-lt,-le</code>之类的需要使用<code>==,<,<=</code>等替换。</p>
<blockquote>
<p><code>[]</code>搭配<code>-eq -ne</code>等使用,<code>(())</code>搭配<code>|| &&</code>等使用。</p>
</blockquote>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>-eq</code></td>
<td>检测两个数是否相等,相等返回true。</td>
<td><code>[ $a -eq $b ]</code></td>
</tr>
<tr>
<td><code>-ne</code></td>
<td>检测两个数是否不相等,不相等返回 true。</td>
<td><code>[ $a -ne $b ]</code></td>
</tr>
<tr>
<td><code>-gt</code></td>
<td>检测左边的数是否大于右边的,如果是,则返回 true。</td>
<td><code>[ $a -gt $b ]</code></td>
</tr>
<tr>
<td><code>-lt</code></td>
<td>检测左边的数是否小于右边的,如果是,则返回 true。</td>
<td><code>[ $a -lt $b ]</code></td>
</tr>
<tr>
<td><code>-ge</code></td>
<td>检测左边的数是否大于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -ge $b ]</code></td>
</tr>
<tr>
<td><code>-le</code></td>
<td>检测左边的数是否小于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -le $b ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ 1 -eq 1 ];then echo 'hello';fi;
# hello
if ((10>=10));then echo 'hello';fi;
# hello
</code></pre>
<h2>6.4. 布尔、逻辑运算符</h2>
<p>布尔、逻辑运算的条件表达式也要放在一对方括号中<code>[]</code>。</p>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>!</code></td>
<td>非运算,表达式为true则返回false,否则返回true。</td>
<td><code>[ ! 10 -eq 0 ]</code></td>
</tr>
<tr>
<td><code>-o</code></td>
<td>或运算,有一个表达式为true则返回true。</td>
<td><code>[ 10 -lt 20 -o 10 -gt 100 ]</code></td>
</tr>
<tr>
<td><code>-a</code></td>
<td>与运算,两个表达式都为true才返回true。</td>
<td><code>[ 10 -lt 20 -a 10 -gt 100 ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ ! 10 -eq 0 ];then echo 'hello';fi
# hello
if [ 10 -ge 10 -a 10 -ge 10 ];then echo 'hello';fi
# hello
if [ 10 -ge 20 -o 10 -ge 0 ];then echo 'hello';fi
# hello
</code></pre>
<p> <code>-o</code>也可以使用<code>||</code>替代,<code>-a</code>也可以使用<code>&&</code>替代,此时需要使用<code>(())</code>或<code>[[]]</code>替代<code>[]</code>。</p>
<pre><code class="language-shell">if <a href="1010-55.html" class="internal-link"> 10==10 && 5==5 </a>;then echo 'hello';fi
# hello
if ((10==10 && 5==5));then echo 'hello';fi
# hello
</code></pre>
<h1>7. 传递参数</h1>
<p>在执行 <code>Shell</code>脚本时,向脚本传递参数,脚本内获取参数的格式为:<code>$n</code>。<code>n</code>代表一个数字,<code>1</code>为执行脚本的第一个参数,<code>2</code>为执行脚本的第二个参数,<code>$0</code>为执行的文件名。在为<code>shell</code>脚本传递的参数中如果包含空格,应该使用单引号或者双引号将该参数括起来,以便于脚本将这个参数作为整体来接收。另外,还有几个特殊字符用来处理参数:</p>
<table>
<thead>
<tr>
<th>参数处理</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>$#</code></td>
<td>传递到脚本的参数个数</td>
</tr>
<tr>
<td><code>$*</code></td>
<td>以一个单字符串显示所有向脚本传递的参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$</code></td>
<td>脚本运行的当前进程ID号</td>
</tr>
<tr>
<td><code>$!</code></td>
<td>后台运行的最后一个进程的ID号</td>
</tr>
<tr>
<td><code>$@</code></td>
<td>与<code>$*</code>相同,但是使用时加引号,并在引号中返回每个参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$-</code></td>
<td>显示Shell使用的当前选项,与set功能相同。</td>
</tr>
<tr>
<td><code>$?</code></td>
<td>显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。</td>
</tr>
</tbody></table>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-bash">set -e
echo "执行的文件名:$0"
echo "参数个数为$#"
echo "第一个参数为:$1"
echo "第二个参数为:$2"
echo "所有参数为:$@"
echo "进程ID号为:$"
echo "当前shell选项为$-"
echo "上一个命令退出的状态为$?"
</code></pre>
<p>执行结果如下:</p>
<pre><code class="language-shell">$ sh test.sh param1 "param2 with space"
执行的文件名:test.sh
参数个数为2
第一个参数为:param1
第二个参数为:param2 with space
所有参数为:param1 param2 with space
进程ID号为:3700
当前shell选项为ehB
上一个命令退出的状态为0
</code></pre>
<h1>8. 函数</h1>
<p>函数定义通过<code>function_name(){}</code>的形式定义,函数返回值可以显示用return返回,如果不加,将以最后一条命令的运行结果作为返回值,函数返回值只能是数字。函数也可以传递参数,但是函数定义的()中不需要申明。</p>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-shell">sayhello(){
echo "hello"
}
# 注意函数调用只需要函数名,不需要加()
sayhello
sayhellowithparam(){
echo "hello, $1 $2 $3"
return 1
}
sayhellowithparam zhangsan lisi wangwu
echo $?
</code></pre>
<p>输出如下:</p>
<blockquote>
<p>hello<br>hello, zhangsan lisi wangwu<br>1</p>
</blockquote>
<h1>9. 命令替换</h1>
<p>命令替换可以将一个命令的输出作为另外一个命令的参数。</p>
<pre><code class="language-shell"># command1 `command2`
cd `pwd` # 该命令将pwd命令列出的目录作为cd命令的参数,结果仍然是停留在当前目录下
cd `echo $HOME` # 将echo的输出作为cd的参数,即打开用户根目录
</code></pre>
<h1>10. let命令</h1>
<p>let 命令是 BASH 中用于计算的工具,用于执行一个或多个表达式,变量计算中不需要加上 $ 来表示变量。如果表达式中包含了空格或其他特殊字符,则必须引起来。</p>
<ul>
<li>自加操作:<code>let no++</code></li>
<li>自减操作:<code>let no--</code></li>
<li>简写形式 <code>let no+=10</code>,<code>let no-=20</code>,分别等同于<code>let no=no+10</code>,<code>let no=no-20</code></li>
</ul>
<h1>11. 流程控制</h1>
<h2>11.1. if</h2>
<pre><code class="language-shell">if ((10<2));then
echo "10小于2"
elif ((10>20));then
echo "a大于10"
else
echo "10大于2且小于10"
fi
</code></pre>
<h2>11.2. case</h2>
<p><code>case</code>每一种情况以右括号结尾,执行到<code>;;</code>结束</p>
<pre><code class="language-shell">case 10 in
0|1)
echo "a为0或1"
;;
11|12)
echo "a为11或12"
;;
*)
# *用来匹配所有情况
echo "a为10"
;;
esac
</code></pre>
<h2>11.3. while</h2>
<pre><code class="language-shell">count=0
while(($count<5))
do
echo $count
let count++
done
</code></pre>
<h2>11.4. util</h2>
<pre><code class="language-shell">count=0
until(($count>=5))
do
echo $count
let count++
done
</code></pre>
<h2>11.5. for</h2>
<pre><code class="language-shell"># for写法1
for ((count=0;$count<5;count=$count+1))
do
echo $count
done
# for写法2
arr=(0 1 2 3 4)
for count in ${arr[*]}
do
echo $int
done
# for写法3
for int in 0 1 2 3 4
do
echo $int
done
</code></pre>
<h2>11.6. break和continue</h2>
<p>用法与一般编程语言类似,break跳出循环,continue跳出当前循环</p>
<pre><code class="language-shell">for ((count=0;$count>=0;count=$count+1))
do
if (($count>=5));then
break;
fi
echo $count
done
</code></pre>
<h1>12. 输入输出重定向</h1>
<h2>12.1. 输出重定向</h2>
<p><code>command > file</code>将命令输出结果保存的file文件中。<code>></code>从文件头开始写,会覆盖旧内容,<code>>></code>将内容追加到文件末尾</p>
<pre><code class="language-shell"># 将who命令的输出保存的users文件中,可以通过cat users查看
who > users
# 将字符串hello world保存到text.txt文件中
echo "hello world" > text.txt
</code></pre>
<h2>12.2. 输入重定向</h2>
<p><code>command < file</code>从file文件获取输入</p>
<pre><code class="language-shell">wc -l /etc/passwd
# 123 /etc/passwd
wc -l < users
# 123
# 第一个例子,会输出文件名;第二个不会,因为它仅仅知道从标准输入读取内容
# command < infile > outfile, 同时替换输入和输出,执行command,从文件infile读取内容,然后将输出写入到outfile中。
wc -l < /etc/passwd > result
cat result
# 123
</code></pre>
<h2>12.3. 文件描述符</h2>
<p>一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件</p>
<ul>
<li>标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。</li>
<li>标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。</li>
<li>标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。</li>
</ul>
<pre><code class="language-shell"># 将标准错误输出重定向到error_trace
cat /tmp/fake_file 2>error_trace
cat error_trace
# cat: /tmp/fake_fule: No such file or directory
# 将标准输出和标准错误输出都重定向到result
cat /tmp/fake_file &>result
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准错误重定向到标准输出
ls /tmp/fake_file > result 2>&1
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准输入重定向到result,将标准错误输出重定向到error_trace
cat /tmp/fake_file 1>result 2>error_trace
</code></pre>
<h2>12.4. Here Document</h2>
<p>将两个<code>EOF</code>之间的内容(document) 作为输入传递给<code>command</code></p>
<pre><code class="language-bash"># command << EOF
# document
# EOF
cat << EOF
hello
shinerio
learn shell
EOF
</code></pre>
<blockquote>
<p>结尾的<code>EOF</code>一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和<code>tab</code>缩进。开始的<code>EOF</code>前后的空格会被忽略掉。</p>
</blockquote>
<h2>12.5. /dev/null</h2>
<p>如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null。<code>command > /dev/null</code></p>
<pre><code class="language-shell">cat users > /dev/null
cat users > /dev/null 2>&1
</code></pre>
<h1>13. set命令</h1>
<p>set指令能设置所使用shell的执行方式,可依照不同的需求来做设置。以下只列出常用的选项参数:</p>
<ul>
<li>-e 若指令传回值不等于0,则立即退出shell。</li>
<li>-f 取消使用通配符。</li>
<li>-n 只读取指令,而不实际执行。</li>
<li>-x 执行指令后,会先显示该指令及所下的参数。</li>
</ul>
</section>
</article>amp;#39;hello' ];then echo 'hello';fi
str='hello'
if [ $str ];then echo 'hello';fi
# hello
</code></pre>
<p>注意字符串的等值判断是一个等号<code>"="</code>,与下文要讲的逻辑运算符使用两个等号<code>"=="</code>做等值判断不一样。</p>
<h1>4. 文件测试运算符</h1>
<table>
<thead>
<tr>
<th>操作符</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>-b file</code></td>
<td>检测文件是否是块设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-c file</code></td>
<td>检测文件是否是字符设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-d file</code></td>
<td>检测文件是否是目录,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-f file</code></td>
<td>检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-g file</code></td>
<td>检测文件是否设置了<code>SGID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-k file</code></td>
<td>检测文件是否设置了粘着位(Sticky Bit),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-p file</code></td>
<td>检测文件是否是有名管道,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-u file</code></td>
<td>检测文件是否设置了<code>SUID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-r file</code></td>
<td>检测文件是否可读,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-w file</code></td>
<td>检测文件是否可写,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-x file</code></td>
<td>检测文件是否可执行,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-s file</code></td>
<td>检测文件是否为空(文件大小是否大于0),不为空返回true。</td>
</tr>
<tr>
<td><code>-e file</code></td>
<td>检测文件(包括目录)是否存在,如果是,则返回true。</td>
</tr>
</tbody></table>
<pre><code class="language-shell">if <a href="f-home.html" class="internal-link"> -f '/home' </a>;then echo 'directory';else echo 'file';fi
# file
if <a href="d-home.html" class="internal-link"> -d '/home' </a>;then echo 'directory';else echo 'file';fi
# directory
if <a href="e-tmpfake-file.html" class="internal-link"> -e '/tmp/fake_file' </a>;then echo 'exist';else echo 'not exist';fi
# not exist
</code></pre>
<h1>5. 数组</h1>
<p><code>shell</code>只支持一维数组,用括号表示,元素通过空格分隔,形如<code>数组名=(值1 值2 ... 值n)</code>。<code>shell</code>数组下标从<code>1</code>开始。</p>
<ul>
<li><code>${数组名[下标]}</code>,读取指索引位置数组元素</li>
<li>使用<code>@</code>或<code>*</code>代替下标,获取数组中所有元素。</li>
<li>使用<code>{<span class="tag">#数组名</span>[@]}</code>或<code>{<span class="tag">#数组名</span>[*]}</code>获取数组元素个数。</li>
</ul>
<pre><code class="language-shell">arr=(value1 value2 value3 value4)
echo ${arr[3]}
# value3
echo ${arr[*]}
# value1 value2 value3 value4
echo ${arr[@]}
# value1 value2 value3 value4
arr[3]='new_value3'
echo $arr[3]
# new_value3
echo ${<span class="tag">#arr</span>[@]}
# 4
echo "arr[1]的长度为:${<span class="tag">#arr</span>[1]}"
# arr[1]的长度为:6
</code></pre>
<h1>6. 运算符</h1>
<h2>6.1. 赋值运算符</h2>
<pre><code class="language-shell">a=10
b=$a
</code></pre>
<h2>6.2. 算术运算符</h2>
<p>算数运算符支持<code>+,-,*,/,%</code></p>
<h3>6.2.1. expr表示法</h3>
<pre><code class="language-shell">echo `expr 10 + 20`
# 30
echo $(expr 20 / 2)
# 10
echo $(expr 10 \* 20) # 使用expr进行乘法运算时必须使用\进行转义
# 200
</code></pre>
<blockquote>
<p>使用expr表示方法时,表达式和运算符之间必须有空格。</p>
</blockquote>
<h3>6.2.2. <code>$[]</code></h3>
<pre><code class="language-shell">echo $[10%3]
# 1
</code></pre>
<h3>6.2.3. <code>$(())</code></h3>
<pre><code class="language-shell">echo $((10*20))
# 200
</code></pre>
<h2>6.3. 关系运算符</h2>
<p>最常见的关系运算符是:<code>==,!=,<,>,>=,<=</code></p>
<pre><code class="language-shell">echo $[10==10]
# 1
flag=$[20==10]
echo $flag
# 1
echo $[10>=10]
# 1
</code></pre>
<p>如下关系运算符只能使用在条件表达式<code>if、while</code>下,类似<code>flag=[ $a -eq $b ]</code>的直接赋值语句是非法的。关系运算符的条件表达式要放在<strong>一对</strong>方括号中,并且中间需要有空格。也可以使用<code>(())</code>替代<code>[]</code>,此时<code>-eq,-lt,-le</code>之类的需要使用<code>==,<,<=</code>等替换。</p>
<blockquote>
<p><code>[]</code>搭配<code>-eq -ne</code>等使用,<code>(())</code>搭配<code>|| &&</code>等使用。</p>
</blockquote>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>-eq</code></td>
<td>检测两个数是否相等,相等返回true。</td>
<td><code>[ $a -eq $b ]</code></td>
</tr>
<tr>
<td><code>-ne</code></td>
<td>检测两个数是否不相等,不相等返回 true。</td>
<td><code>[ $a -ne $b ]</code></td>
</tr>
<tr>
<td><code>-gt</code></td>
<td>检测左边的数是否大于右边的,如果是,则返回 true。</td>
<td><code>[ $a -gt $b ]</code></td>
</tr>
<tr>
<td><code>-lt</code></td>
<td>检测左边的数是否小于右边的,如果是,则返回 true。</td>
<td><code>[ $a -lt $b ]</code></td>
</tr>
<tr>
<td><code>-ge</code></td>
<td>检测左边的数是否大于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -ge $b ]</code></td>
</tr>
<tr>
<td><code>-le</code></td>
<td>检测左边的数是否小于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -le $b ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ 1 -eq 1 ];then echo 'hello';fi;
# hello
if ((10>=10));then echo 'hello';fi;
# hello
</code></pre>
<h2>6.4. 布尔、逻辑运算符</h2>
<p>布尔、逻辑运算的条件表达式也要放在一对方括号中<code>[]</code>。</p>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>!</code></td>
<td>非运算,表达式为true则返回false,否则返回true。</td>
<td><code>[ ! 10 -eq 0 ]</code></td>
</tr>
<tr>
<td><code>-o</code></td>
<td>或运算,有一个表达式为true则返回true。</td>
<td><code>[ 10 -lt 20 -o 10 -gt 100 ]</code></td>
</tr>
<tr>
<td><code>-a</code></td>
<td>与运算,两个表达式都为true才返回true。</td>
<td><code>[ 10 -lt 20 -a 10 -gt 100 ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ ! 10 -eq 0 ];then echo 'hello';fi
# hello
if [ 10 -ge 10 -a 10 -ge 10 ];then echo 'hello';fi
# hello
if [ 10 -ge 20 -o 10 -ge 0 ];then echo 'hello';fi
# hello
</code></pre>
<p> <code>-o</code>也可以使用<code>||</code>替代,<code>-a</code>也可以使用<code>&&</code>替代,此时需要使用<code>(())</code>或<code>[[]]</code>替代<code>[]</code>。</p>
<pre><code class="language-shell">if <a href="1010-55.html" class="internal-link"> 10==10 && 5==5 </a>;then echo 'hello';fi
# hello
if ((10==10 && 5==5));then echo 'hello';fi
# hello
</code></pre>
<h1>7. 传递参数</h1>
<p>在执行 <code>Shell</code>脚本时,向脚本传递参数,脚本内获取参数的格式为:<code>$n</code>。<code>n</code>代表一个数字,<code>1</code>为执行脚本的第一个参数,<code>2</code>为执行脚本的第二个参数,<code>$0</code>为执行的文件名。在为<code>shell</code>脚本传递的参数中如果包含空格,应该使用单引号或者双引号将该参数括起来,以便于脚本将这个参数作为整体来接收。另外,还有几个特殊字符用来处理参数:</p>
<table>
<thead>
<tr>
<th>参数处理</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>$#</code></td>
<td>传递到脚本的参数个数</td>
</tr>
<tr>
<td><code>$*</code></td>
<td>以一个单字符串显示所有向脚本传递的参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$</code></td>
<td>脚本运行的当前进程ID号</td>
</tr>
<tr>
<td><code>$!</code></td>
<td>后台运行的最后一个进程的ID号</td>
</tr>
<tr>
<td><code>$@</code></td>
<td>与<code>$*</code>相同,但是使用时加引号,并在引号中返回每个参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$-</code></td>
<td>显示Shell使用的当前选项,与set功能相同。</td>
</tr>
<tr>
<td><code>$?</code></td>
<td>显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。</td>
</tr>
</tbody></table>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-bash">set -e
echo "执行的文件名:$0"
echo "参数个数为$#"
echo "第一个参数为:$1"
echo "第二个参数为:$2"
echo "所有参数为:$@"
echo "进程ID号为:$"
echo "当前shell选项为$-"
echo "上一个命令退出的状态为$?"
</code></pre>
<p>执行结果如下:</p>
<pre><code class="language-shell">$ sh test.sh param1 "param2 with space"
执行的文件名:test.sh
参数个数为2
第一个参数为:param1
第二个参数为:param2 with space
所有参数为:param1 param2 with space
进程ID号为:3700
当前shell选项为ehB
上一个命令退出的状态为0
</code></pre>
<h1>8. 函数</h1>
<p>函数定义通过<code>function_name(){}</code>的形式定义,函数返回值可以显示用return返回,如果不加,将以最后一条命令的运行结果作为返回值,函数返回值只能是数字。函数也可以传递参数,但是函数定义的()中不需要申明。</p>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-shell">sayhello(){
echo "hello"
}
# 注意函数调用只需要函数名,不需要加()
sayhello
sayhellowithparam(){
echo "hello, $1 $2 $3"
return 1
}
sayhellowithparam zhangsan lisi wangwu
echo $?
</code></pre>
<p>输出如下:</p>
<blockquote>
<p>hello<br>hello, zhangsan lisi wangwu<br>1</p>
</blockquote>
<h1>9. 命令替换</h1>
<p>命令替换可以将一个命令的输出作为另外一个命令的参数。</p>
<pre><code class="language-shell"># command1 `command2`
cd `pwd` # 该命令将pwd命令列出的目录作为cd命令的参数,结果仍然是停留在当前目录下
cd `echo $HOME` # 将echo的输出作为cd的参数,即打开用户根目录
</code></pre>
<h1>10. let命令</h1>
<p>let 命令是 BASH 中用于计算的工具,用于执行一个或多个表达式,变量计算中不需要加上 $ 来表示变量。如果表达式中包含了空格或其他特殊字符,则必须引起来。</p>
<ul>
<li>自加操作:<code>let no++</code></li>
<li>自减操作:<code>let no--</code></li>
<li>简写形式 <code>let no+=10</code>,<code>let no-=20</code>,分别等同于<code>let no=no+10</code>,<code>let no=no-20</code></li>
</ul>
<h1>11. 流程控制</h1>
<h2>11.1. if</h2>
<pre><code class="language-shell">if ((10<2));then
echo "10小于2"
elif ((10>20));then
echo "a大于10"
else
echo "10大于2且小于10"
fi
</code></pre>
<h2>11.2. case</h2>
<p><code>case</code>每一种情况以右括号结尾,执行到<code>;;</code>结束</p>
<pre><code class="language-shell">case 10 in
0|1)
echo "a为0或1"
;;
11|12)
echo "a为11或12"
;;
*)
# *用来匹配所有情况
echo "a为10"
;;
esac
</code></pre>
<h2>11.3. while</h2>
<pre><code class="language-shell">count=0
while(($count<5))
do
echo $count
let count++
done
</code></pre>
<h2>11.4. util</h2>
<pre><code class="language-shell">count=0
until(($count>=5))
do
echo $count
let count++
done
</code></pre>
<h2>11.5. for</h2>
<pre><code class="language-shell"># for写法1
for ((count=0;$count<5;count=$count+1))
do
echo $count
done
# for写法2
arr=(0 1 2 3 4)
for count in ${arr[*]}
do
echo $int
done
# for写法3
for int in 0 1 2 3 4
do
echo $int
done
</code></pre>
<h2>11.6. break和continue</h2>
<p>用法与一般编程语言类似,break跳出循环,continue跳出当前循环</p>
<pre><code class="language-shell">for ((count=0;$count>=0;count=$count+1))
do
if (($count>=5));then
break;
fi
echo $count
done
</code></pre>
<h1>12. 输入输出重定向</h1>
<h2>12.1. 输出重定向</h2>
<p><code>command > file</code>将命令输出结果保存的file文件中。<code>></code>从文件头开始写,会覆盖旧内容,<code>>></code>将内容追加到文件末尾</p>
<pre><code class="language-shell"># 将who命令的输出保存的users文件中,可以通过cat users查看
who > users
# 将字符串hello world保存到text.txt文件中
echo "hello world" > text.txt
</code></pre>
<h2>12.2. 输入重定向</h2>
<p><code>command < file</code>从file文件获取输入</p>
<pre><code class="language-shell">wc -l /etc/passwd
# 123 /etc/passwd
wc -l < users
# 123
# 第一个例子,会输出文件名;第二个不会,因为它仅仅知道从标准输入读取内容
# command < infile > outfile, 同时替换输入和输出,执行command,从文件infile读取内容,然后将输出写入到outfile中。
wc -l < /etc/passwd > result
cat result
# 123
</code></pre>
<h2>12.3. 文件描述符</h2>
<p>一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件</p>
<ul>
<li>标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。</li>
<li>标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。</li>
<li>标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。</li>
</ul>
<pre><code class="language-shell"># 将标准错误输出重定向到error_trace
cat /tmp/fake_file 2>error_trace
cat error_trace
# cat: /tmp/fake_fule: No such file or directory
# 将标准输出和标准错误输出都重定向到result
cat /tmp/fake_file &>result
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准错误重定向到标准输出
ls /tmp/fake_file > result 2>&1
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准输入重定向到result,将标准错误输出重定向到error_trace
cat /tmp/fake_file 1>result 2>error_trace
</code></pre>
<h2>12.4. Here Document</h2>
<p>将两个<code>EOF</code>之间的内容(document) 作为输入传递给<code>command</code></p>
<pre><code class="language-bash"># command << EOF
# document
# EOF
cat << EOF
hello
shinerio
learn shell
EOF
</code></pre>
<blockquote>
<p>结尾的<code>EOF</code>一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和<code>tab</code>缩进。开始的<code>EOF</code>前后的空格会被忽略掉。</p>
</blockquote>
<h2>12.5. /dev/null</h2>
<p>如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null。<code>command > /dev/null</code></p>
<pre><code class="language-shell">cat users > /dev/null
cat users > /dev/null 2>&1
</code></pre>
<h1>13. set命令</h1>
<p>set指令能设置所使用shell的执行方式,可依照不同的需求来做设置。以下只列出常用的选项参数:</p>
<ul>
<li>-e 若指令传回值不等于0,则立即退出shell。</li>
<li>-f 取消使用通配符。</li>
<li>-n 只读取指令,而不实际执行。</li>
<li>-x 执行指令后,会先显示该指令及所下的参数。</li>
</ul>
#39;hello' ];then echo 'hello';fi
str='hello'
if [ $str ];then echo 'hello';fi
# hello
注意字符串的等值判断是一个等号"=",与下文要讲的逻辑运算符使用两个等号"=="做等值判断不一样。
4. 文件测试运算符
| 操作符 | 说明 |
|---|---|
-b file |
检测文件是否是块设备文件,如果是,则返回true。 |
-c file |
检测文件是否是字符设备文件,如果是,则返回true。 |
-d file |
检测文件是否是目录,如果是,则返回true。 |
-f file |
检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回true。 |
-g file |
检测文件是否设置了SGID位,如果是,则返回true。 |
-k file |
检测文件是否设置了粘着位(Sticky Bit),如果是,则返回true。 |
-p file |
检测文件是否是有名管道,如果是,则返回true。 |
-u file |
检测文件是否设置了SUID位,如果是,则返回true。 |
-r file |
检测文件是否可读,如果是,则返回true。 |
-w file |
检测文件是否可写,如果是,则返回true。 |
-x file |
检测文件是否可执行,如果是,则返回true。 |
-s file |
检测文件是否为空(文件大小是否大于0),不为空返回true。 |
-e file |
检测文件(包括目录)是否存在,如果是,则返回true。 |
if <a href="f-home.html" class="internal-link"> -f '/home' </a>;then echo 'directory';else echo 'file';fi
# file
if <a href="d-home.html" class="internal-link"> -d '/home' </a>;then echo 'directory';else echo 'file';fi
# directory
if <a href="e-tmpfake-file.html" class="internal-link"> -e '/tmp/fake_file' </a>;then echo 'exist';else echo 'not exist';fi
# not exist
5. 数组
shell只支持一维数组,用括号表示,元素通过空格分隔,形如数组名=(值1 值2 ... 值n)。shell数组下标从1开始。
${数组名[下标]},读取指索引位置数组元素- 使用
@或*代替下标,获取数组中所有元素。 - 使用
{<span class="tag">#数组名</span>[@]}或{<span class="tag">#数组名</span>[*]}获取数组元素个数。
arr=(value1 value2 value3 value4)
echo ${arr[3]}
# value3
echo ${arr[*]}
# value1 value2 value3 value4
echo ${arr[@]}
# value1 value2 value3 value4
arr[3]='new_value3'
echo $arr[3]
# new_value3
echo ${<span class="tag">#arr</span>[@]}
# 4
echo "arr[1]的长度为:${<span class="tag">#arr</span>[1]}"
# arr[1]的长度为:6
6. 运算符
6.1. 赋值运算符
a=10
b=$a
6.2. 算术运算符
算数运算符支持+,-,*,/,%
6.2.1. expr表示法
echo `expr 10 + 20`
# 30
echo $(expr 20 / 2)
# 10
echo $(expr 10 \* 20) # 使用expr进行乘法运算时必须使用\进行转义
# 200
使用expr表示方法时,表达式和运算符之间必须有空格。
6.2.2. $[]
echo $[10%3]
# 1
6.2.3. $(())
echo $((10*20))
# 200
6.3. 关系运算符
最常见的关系运算符是:==,!=,<,>,>=,<=
echo $[10==10]
# 1
flag=$[20==10]
echo $flag
# 1
echo $[10>=10]
# 1
如下关系运算符只能使用在条件表达式if、while下,类似flag=[ $a -eq $b ]的直接赋值语句是非法的。关系运算符的条件表达式要放在一对方括号中,并且中间需要有空格。也可以使用(())替代[],此时-eq,-lt,-le之类的需要使用==,<,<=等替换。
[]搭配-eq -ne等使用,(())搭配|| &&等使用。
| 运算符 | 说明 | 举例 |
|---|---|---|
-eq |
检测两个数是否相等,相等返回true。 | [ $a -eq $b ] |
-ne |
检测两个数是否不相等,不相等返回 true。 | [ $a -ne $b ] |
-gt |
检测左边的数是否大于右边的,如果是,则返回 true。 | [ $a -gt $b ] |
-lt |
检测左边的数是否小于右边的,如果是,则返回 true。 | [ $a -lt $b ] |
-ge |
检测左边的数是否大于等于右边的,如果是,则返回 true。 | [ $a -ge $b ] |
-le |
检测左边的数是否小于等于右边的,如果是,则返回 true。 | [ $a -le $b ] |
if [ 1 -eq 1 ];then echo 'hello';fi;
# hello
if ((10>=10));then echo 'hello';fi;
# hello
6.4. 布尔、逻辑运算符
布尔、逻辑运算的条件表达式也要放在一对方括号中[]。
| 运算符 | 说明 | 举例 |
|---|---|---|
! |
非运算,表达式为true则返回false,否则返回true。 | [ ! 10 -eq 0 ] |
-o |
或运算,有一个表达式为true则返回true。 | [ 10 -lt 20 -o 10 -gt 100 ] |
-a |
与运算,两个表达式都为true才返回true。 | [ 10 -lt 20 -a 10 -gt 100 ] |
if [ ! 10 -eq 0 ];then echo 'hello';fi
# hello
if [ 10 -ge 10 -a 10 -ge 10 ];then echo 'hello';fi
# hello
if [ 10 -ge 20 -o 10 -ge 0 ];then echo 'hello';fi
# hello
-o也可以使用||替代,-a也可以使用&&替代,此时需要使用(())或[[]]替代[]。
if <a href="1010-55.html" class="internal-link"> 10==10 && 5==5 </a>;then echo 'hello';fi
# hello
if ((10==10 && 5==5));then echo 'hello';fi
# hello
7. 传递参数
在执行 Shell脚本时,向脚本传递参数,脚本内获取参数的格式为:$n。n代表一个数字,1为执行脚本的第一个参数,2为执行脚本的第二个参数,$0为执行的文件名。在为shell脚本传递的参数中如果包含空格,应该使用单引号或者双引号将该参数括起来,以便于脚本将这个参数作为整体来接收。另外,还有几个特殊字符用来处理参数:
| 参数处理 | 说明 |
|---|---|
$# |
传递到脚本的参数个数 |
$* |
以一个单字符串显示所有向脚本传递的参数,以$1 $2 … $n的形式输出所有参数。 |
$ |
脚本运行的当前进程ID号 |
$! |
后台运行的最后一个进程的ID号 |
$@ |
与$*相同,但是使用时加引号,并在引号中返回每个参数,以$1 $2 … $n的形式输出所有参数。 |
$- |
显示Shell使用的当前选项,与set功能相同。 |
$? |
显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。 |
编写shell脚本如下:
set -e
echo "执行的文件名:$0"
echo "参数个数为$#"
echo "第一个参数为:$1"
echo "第二个参数为:$2"
echo "所有参数为:$@"
echo "进程ID号为:<article>
<header>
<h1>shell编程</h1>
<time datetime="2023-01-24T00:00:00.000Z">2023年1月24日</time>
<div class="tags">
<span class="tag">linux</span>
</div>
</header>
<section class="content">
<p>本文主要介绍shell编程的基本语法以及实际应用中的常见命令。</p>
<h1>1. 注释</h1>
<h2>1.1. 单行注释</h2>
<pre><code class="language-shell"># 这是单行注释
</code></pre>
<h2>1.2. 多行注释</h2>
<pre><code class="language-shell">:<<EOF
多行注释内容
多行注释内容
多行注释内容
EOF
</code></pre>
<p>多行注释<code>EOF</code>也可替换成<code>!</code>或<code>'</code></p>
<pre><code class="language-shell">:<<'
多行注释内容
多行注释内容
多行注释内容
'
:<<!
多行注释内容
多行注释内容
多行注释内容
!
</code></pre>
<h1>2. 变量</h1>
<h2>2.1. 变量定义</h2>
<p>使用<code>VARIABLENAME=VALUE</code>的形式,VALUE如果是字符串的话,可以使用单引号、双引号或者不加引号。单引号内的任何字符都会原样输出,不能进行转义,单引号内不能单独出现一个单引号,但可成对出现,作为字符串拼接使用。双引号内可以有变量,可以出现转义字符。</p>
<h2>2.2. 变量使用</h2>
<p>只需要在变量前加<code>$</code>符号,变量加<code>{}</code>是可选的,方便解释器识别边界。将变量加上<code>{}</code>是一个好习惯,不容易出错。</p>
<pre><code class="language-shell">your_age=25
your_name="shinerio"
your_name=shinerio
your_name='shinerio'
echo $your_age # 输出25
echo $your_name # 输出shinerio
echo "${your_name}hello" <span class="tag">#这里</span>{}必须添加,否则解释器认为是${your_namehello}
str='hello'' # 非法
str='hello'__'world' # 成对出现的单引号做字符拼接
echo $str <span class="tag">#输出hello__world</span>
str1='helloworld${your_age}\nnew line'
str2="helloworld${your_age}\nnew line"
echo $str1 # 输出helloworld${your_age}\nnew line
echo $str2 # 输出helloworld25\nnew line
echo -e $str2 # -e开启转义 \n表示换行 echo默认换行,通过\c强制不换行
<span class="tag">#helloworld25</span>
<span class="tag">#new</span> line
</code></pre>
<h2>2.3. 只读变量</h2>
<p>使用<code>readonly VARIABLENAME</code>设置变量只读,只读变量的值不能更改</p>
<pre><code class="language-shell">readonly name='jack'
name='kelly'
zsh: read-only variable: name
</code></pre>
<h2>2.4. 删除变量</h2>
<p>使用<code>unset VARIABLENAME</code>删除变量。</p>
<h1>3. 字符串操作</h1>
<h2>3.1. 字符串拼接</h2>
<pre><code class="language-shell">str1="hello"${your_name}"world"
str2="hello${your_name}world"
str3='hello'${your_name}'world'
</code></pre>
<h2>3.2. 字符串长度</h2>
<pre><code class="language-shell">str='hello'
echo ${<span class="tag">#str</span>}
5
</code></pre>
<h2>3.3. 字符串截取</h2>
<p><code>${string:start:length}</code>,索引从0开始,从start(包含)开始截取共计length长度的字符。</p>
<pre><code class="language-shell">str='helloworld'
echo ${str:0:5}
hello
</code></pre>
<h2>3.4. 字符串运算符</h2>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>=</code></td>
<td>检测两个字符串是否相等,相等返回true</td>
<td><code>[ 'hello' = 'hello' ]</code></td>
</tr>
<tr>
<td><code>!=</code></td>
<td>检测两个字符串是否相等,不相等返回true</td>
<td><code>[ 'hello' != 'ello' ]</code></td>
</tr>
<tr>
<td><code>-z</code></td>
<td>检测字符串长度是否为0,为0返回true</td>
<td><code>[ -z '' ]</code></td>
</tr>
<tr>
<td><code>-n </code></td>
<td>检测字符串长度是否不为0,不为0返回true</td>
<td><code>[ -n 'hello' ]</code></td>
</tr>
<tr>
<td><code>$</code></td>
<td>检测字符串是否为空,不为空返回true</td>
<td><code>[ <p>本文主要介绍shell编程的基本语法以及实际应用中的常见命令。</p>
<h1>1. 注释</h1>
<h2>1.1. 单行注释</h2>
<pre><code class="language-shell"># 这是单行注释
</code></pre>
<h2>1.2. 多行注释</h2>
<pre><code class="language-shell">:&lt;&lt;EOF
多行注释内容
多行注释内容
多行注释内容
EOF
</code></pre>
<p>多行注释<code>EOF</code>也可替换成<code>!</code>或<code>&#39;</code></p>
<pre><code class="language-shell">:&lt;&lt;&#39;
多行注释内容
多行注释内容
多行注释内容
&#39;
:&lt;&lt;!
多行注释内容
多行注释内容
多行注释内容
!
</code></pre>
<h1>2. 变量</h1>
<h2>2.1. 变量定义</h2>
<p>使用<code>VARIABLENAME=VALUE</code>的形式,VALUE如果是字符串的话,可以使用单引号、双引号或者不加引号。单引号内的任何字符都会原样输出,不能进行转义,单引号内不能单独出现一个单引号,但可成对出现,作为字符串拼接使用。双引号内可以有变量,可以出现转义字符。</p>
<h2>2.2. 变量使用</h2>
<p>只需要在变量前加<code>$</code>符号,变量加<code>{}</code>是可选的,方便解释器识别边界。将变量加上<code>{}</code>是一个好习惯,不容易出错。</p>
<pre><code class="language-shell">your_age=25
your_name=&quot;shinerio&quot;
your_name=shinerio
your_name=&#39;shinerio&#39;
echo $your_age # 输出25
echo $your_name # 输出shinerio
echo &quot;${your_name}hello&quot; &lt;span class=&quot;tag&quot;&gt;#这里&lt;/span&gt;{}必须添加,否则解释器认为是${your_namehello}
str=&#39;hello&#39;&#39; # 非法
str=&#39;hello&#39;__&#39;world&#39; # 成对出现的单引号做字符拼接
echo $str &lt;span class=&quot;tag&quot;&gt;#输出hello__world&lt;/span&gt;
str1=&#39;helloworld${your_age}\nnew line&#39;
str2=&quot;helloworld${your_age}\nnew line&quot;
echo $str1 # 输出helloworld${your_age}\nnew line
echo $str2 # 输出helloworld25\nnew line
echo -e $str2 # -e开启转义 \n表示换行 echo默认换行,通过\c强制不换行
&lt;span class=&quot;tag&quot;&gt;#helloworld25&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;#new&lt;/span&gt; line
</code></pre>
<h2>2.3. 只读变量</h2>
<p>使用<code>readonly VARIABLENAME</code>设置变量只读,只读变量的值不能更改</p>
<pre><code class="language-shell">readonly name=&#39;jack&#39;
name=&#39;kelly&#39;
zsh: read-only variable: name
</code></pre>
<h2>2.4. 删除变量</h2>
<p>使用<code>unset VARIABLENAME</code>删除变量。</p>
<h1>3. 字符串操作</h1>
<h2>3.1. 字符串拼接</h2>
<pre><code class="language-shell">str1=&quot;hello&quot;${your_name}&quot;world&quot;
str2=&quot;hello${your_name}world&quot;
str3=&#39;hello&#39;${your_name}&#39;world&#39;
</code></pre>
<h2>3.2. 字符串长度</h2>
<pre><code class="language-shell">str=&#39;hello&#39;
echo ${&lt;span class=&quot;tag&quot;&gt;#str&lt;/span&gt;}
5
</code></pre>
<h2>3.3. 字符串截取</h2>
<p><code>${string:start:length}</code>,索引从0开始,从start(包含)开始截取共计length长度的字符。</p>
<pre><code class="language-shell">str=&#39;helloworld&#39;
echo ${str:0:5}
hello
</code></pre>
<h2>3.4. 字符串运算符</h2>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>=</code></td>
<td>检测两个字符串是否相等,相等返回true</td>
<td><code>[ &#39;hello&#39; = &#39;hello&#39; ]</code></td>
</tr>
<tr>
<td><code>!=</code></td>
<td>检测两个字符串是否相等,不相等返回true</td>
<td><code>[ &#39;hello&#39; != &#39;ello&#39; ]</code></td>
</tr>
<tr>
<td><code>-z</code></td>
<td>检测字符串长度是否为0,为0返回true</td>
<td><code>[ -z &#39;&#39; ]</code></td>
</tr>
<tr>
<td><code>-n </code></td>
<td>检测字符串长度是否不为0,不为0返回true</td>
<td><code>[ -n &#39;hello&#39; ]</code></td>
</tr>
<tr>
<td><code>$</code></td>
<td>检测字符串是否为空,不为空返回true</td>
<td><code>[ $&#39;hello&#39; ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ &#39;hello&#39; = &#39;hello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ &#39;hello&#39; != &#39;ello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ -z &#39;&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ -n &#39;hello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ $&#39;hello&#39; ];then echo &#39;hello&#39;;fi
str=&#39;hello&#39;
if [ $str ];then echo &#39;hello&#39;;fi
# hello
</code></pre>
<p>注意字符串的等值判断是一个等号<code>&quot;=&quot;</code>,与下文要讲的逻辑运算符使用两个等号<code>&quot;==&quot;</code>做等值判断不一样。</p>
<h1>4. 文件测试运算符</h1>
<table>
<thead>
<tr>
<th>操作符</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>-b file</code></td>
<td>检测文件是否是块设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-c file</code></td>
<td>检测文件是否是字符设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-d file</code></td>
<td>检测文件是否是目录,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-f file</code></td>
<td>检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-g file</code></td>
<td>检测文件是否设置了<code>SGID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-k file</code></td>
<td>检测文件是否设置了粘着位(Sticky Bit),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-p file</code></td>
<td>检测文件是否是有名管道,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-u file</code></td>
<td>检测文件是否设置了<code>SUID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-r file</code></td>
<td>检测文件是否可读,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-w file</code></td>
<td>检测文件是否可写,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-x file</code></td>
<td>检测文件是否可执行,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-s file</code></td>
<td>检测文件是否为空(文件大小是否大于0),不为空返回true。</td>
</tr>
<tr>
<td><code>-e file</code></td>
<td>检测文件(包括目录)是否存在,如果是,则返回true。</td>
</tr>
</tbody></table>
<pre><code class="language-shell">if &lt;a href=&quot;f-home.html&quot; class=&quot;internal-link&quot;&gt; -f &#39;/home&#39; &lt;/a&gt;;then echo &#39;directory&#39;;else echo &#39;file&#39;;fi
# file
if &lt;a href=&quot;d-home.html&quot; class=&quot;internal-link&quot;&gt; -d &#39;/home&#39; &lt;/a&gt;;then echo &#39;directory&#39;;else echo &#39;file&#39;;fi
# directory
if &lt;a href=&quot;e-tmpfake-file.html&quot; class=&quot;internal-link&quot;&gt; -e &#39;/tmp/fake_file&#39; &lt;/a&gt;;then echo &#39;exist&#39;;else echo &#39;not exist&#39;;fi
# not exist
</code></pre>
<h1>5. 数组</h1>
<p><code>shell</code>只支持一维数组,用括号表示,元素通过空格分隔,形如<code>数组名=(值1 值2 ... 值n)</code>。<code>shell</code>数组下标从<code>1</code>开始。</p>
<ul>
<li><code>${数组名[下标]}</code>,读取指索引位置数组元素</li>
<li>使用<code>@</code>或<code>*</code>代替下标,获取数组中所有元素。</li>
<li>使用<code>{&lt;span class=&quot;tag&quot;&gt;#数组名&lt;/span&gt;[@]}</code>或<code>{&lt;span class=&quot;tag&quot;&gt;#数组名&lt;/span&gt;[*]}</code>获取数组元素个数。</li>
</ul>
<pre><code class="language-shell">arr=(value1 value2 value3 value4)
echo ${arr[3]}
# value3
echo ${arr[*]}
# value1 value2 value3 value4
echo ${arr[@]}
# value1 value2 value3 value4
arr[3]=&#39;new_value3&#39;
echo $arr[3]
# new_value3
echo ${&lt;span class=&quot;tag&quot;&gt;#arr&lt;/span&gt;[@]}
# 4
echo &quot;arr[1]的长度为:${&lt;span class=&quot;tag&quot;&gt;#arr&lt;/span&gt;[1]}&quot;
# arr[1]的长度为:6
</code></pre>
<h1>6. 运算符</h1>
<h2>6.1. 赋值运算符</h2>
<pre><code class="language-shell">a=10
b=$a
</code></pre>
<h2>6.2. 算术运算符</h2>
<p>算数运算符支持<code>+,-,*,/,%</code></p>
<h3>6.2.1. expr表示法</h3>
<pre><code class="language-shell">echo `expr 10 + 20`
# 30
echo $(expr 20 / 2)
# 10
echo $(expr 10 \* 20) # 使用expr进行乘法运算时必须使用\进行转义
# 200
</code></pre>
<blockquote>
<p>使用expr表示方法时,表达式和运算符之间必须有空格。</p>
</blockquote>
<h3>6.2.2. <code>$[]</code></h3>
<pre><code class="language-shell">echo $[10%3]
# 1
</code></pre>
<h3>6.2.3. <code>$(())</code></h3>
<pre><code class="language-shell">echo $((10*20))
# 200
</code></pre>
<h2>6.3. 关系运算符</h2>
<p>最常见的关系运算符是:<code>==,!=,&lt;,&gt;,&gt;=,&lt;=</code></p>
<pre><code class="language-shell">echo $[10==10]
# 1
flag=$[20==10]
echo $flag
# 1
echo $[10&gt;=10]
# 1
</code></pre>
<p>如下关系运算符只能使用在条件表达式<code>if、while</code>下,类似<code>flag=[ $a -eq $b ]</code>的直接赋值语句是非法的。关系运算符的条件表达式要放在<strong>一对</strong>方括号中,并且中间需要有空格。也可以使用<code>(())</code>替代<code>[]</code>,此时<code>-eq,-lt,-le</code>之类的需要使用<code>==,&lt;,&lt;=</code>等替换。</p>
<blockquote>
<p><code>[]</code>搭配<code>-eq -ne</code>等使用,<code>(())</code>搭配<code>|| &amp;&amp;</code>等使用。</p>
</blockquote>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>-eq</code></td>
<td>检测两个数是否相等,相等返回true。</td>
<td><code>[ $a -eq $b ]</code></td>
</tr>
<tr>
<td><code>-ne</code></td>
<td>检测两个数是否不相等,不相等返回 true。</td>
<td><code>[ $a -ne $b ]</code></td>
</tr>
<tr>
<td><code>-gt</code></td>
<td>检测左边的数是否大于右边的,如果是,则返回 true。</td>
<td><code>[ $a -gt $b ]</code></td>
</tr>
<tr>
<td><code>-lt</code></td>
<td>检测左边的数是否小于右边的,如果是,则返回 true。</td>
<td><code>[ $a -lt $b ]</code></td>
</tr>
<tr>
<td><code>-ge</code></td>
<td>检测左边的数是否大于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -ge $b ]</code></td>
</tr>
<tr>
<td><code>-le</code></td>
<td>检测左边的数是否小于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -le $b ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ 1 -eq 1 ];then echo &#39;hello&#39;;fi;
# hello
if ((10&gt;=10));then echo &#39;hello&#39;;fi;
# hello
</code></pre>
<h2>6.4. 布尔、逻辑运算符</h2>
<p>布尔、逻辑运算的条件表达式也要放在一对方括号中<code>[]</code>。</p>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>!</code></td>
<td>非运算,表达式为true则返回false,否则返回true。</td>
<td><code>[ ! 10 -eq 0 ]</code></td>
</tr>
<tr>
<td><code>-o</code></td>
<td>或运算,有一个表达式为true则返回true。</td>
<td><code>[ 10 -lt 20 -o 10 -gt 100 ]</code></td>
</tr>
<tr>
<td><code>-a</code></td>
<td>与运算,两个表达式都为true才返回true。</td>
<td><code>[ 10 -lt 20 -a 10 -gt 100 ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ ! 10 -eq 0 ];then echo &#39;hello&#39;;fi
# hello
if [ 10 -ge 10 -a 10 -ge 10 ];then echo &#39;hello&#39;;fi
# hello
if [ 10 -ge 20 -o 10 -ge 0 ];then echo &#39;hello&#39;;fi
# hello
</code></pre>
<p> <code>-o</code>也可以使用<code>||</code>替代,<code>-a</code>也可以使用<code>&amp;&amp;</code>替代,此时需要使用<code>(())</code>或<code>[[]]</code>替代<code>[]</code>。</p>
<pre><code class="language-shell">if &lt;a href=&quot;1010-55.html&quot; class=&quot;internal-link&quot;&gt; 10==10 &amp;&amp; 5==5 &lt;/a&gt;;then echo &#39;hello&#39;;fi
# hello
if ((10==10 &amp;&amp; 5==5));then echo &#39;hello&#39;;fi
# hello
</code></pre>
<h1>7. 传递参数</h1>
<p>在执行 <code>Shell</code>脚本时,向脚本传递参数,脚本内获取参数的格式为:<code>$n</code>。<code>n</code>代表一个数字,<code>1</code>为执行脚本的第一个参数,<code>2</code>为执行脚本的第二个参数,<code>$0</code>为执行的文件名。在为<code>shell</code>脚本传递的参数中如果包含空格,应该使用单引号或者双引号将该参数括起来,以便于脚本将这个参数作为整体来接收。另外,还有几个特殊字符用来处理参数:</p>
<table>
<thead>
<tr>
<th>参数处理</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>$#</code></td>
<td>传递到脚本的参数个数</td>
</tr>
<tr>
<td><code>$*</code></td>
<td>以一个单字符串显示所有向脚本传递的参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$$</code></td>
<td>脚本运行的当前进程ID号</td>
</tr>
<tr>
<td><code>$!</code></td>
<td>后台运行的最后一个进程的ID号</td>
</tr>
<tr>
<td><code>$@</code></td>
<td>与<code>$*</code>相同,但是使用时加引号,并在引号中返回每个参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$-</code></td>
<td>显示Shell使用的当前选项,与set功能相同。</td>
</tr>
<tr>
<td><code>$?</code></td>
<td>显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。</td>
</tr>
</tbody></table>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-bash">set -e
echo &quot;执行的文件名:$0&quot;
echo &quot;参数个数为$#&quot;
echo &quot;第一个参数为:$1&quot;
echo &quot;第二个参数为:$2&quot;
echo &quot;所有参数为:$@&quot;
echo &quot;进程ID号为:$$&quot;
echo &quot;当前shell选项为$-&quot;
echo &quot;上一个命令退出的状态为$?&quot;
</code></pre>
<p>执行结果如下:</p>
<pre><code class="language-shell">$ sh test.sh param1 &quot;param2 with space&quot;
执行的文件名:test.sh
参数个数为2
第一个参数为:param1
第二个参数为:param2 with space
所有参数为:param1 param2 with space
进程ID号为:3700
当前shell选项为ehB
上一个命令退出的状态为0
</code></pre>
<h1>8. 函数</h1>
<p>函数定义通过<code>function_name(){}</code>的形式定义,函数返回值可以显示用return返回,如果不加,将以最后一条命令的运行结果作为返回值,函数返回值只能是数字。函数也可以传递参数,但是函数定义的()中不需要申明。</p>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-shell">sayhello(){
echo &quot;hello&quot;
}
# 注意函数调用只需要函数名,不需要加()
sayhello
sayhellowithparam(){
echo &quot;hello, $1 $2 $3&quot;
return 1
}
sayhellowithparam zhangsan lisi wangwu
echo $?
</code></pre>
<p>输出如下:</p>
<blockquote>
<p>hello<br>hello, zhangsan lisi wangwu<br>1</p>
</blockquote>
<h1>9. 命令替换</h1>
<p>命令替换可以将一个命令的输出作为另外一个命令的参数。</p>
<pre><code class="language-shell"># command1 `command2`
cd `pwd` # 该命令将pwd命令列出的目录作为cd命令的参数,结果仍然是停留在当前目录下
cd `echo $HOME` # 将echo的输出作为cd的参数,即打开用户根目录
</code></pre>
<h1>10. let命令</h1>
<p>let 命令是 BASH 中用于计算的工具,用于执行一个或多个表达式,变量计算中不需要加上 $ 来表示变量。如果表达式中包含了空格或其他特殊字符,则必须引起来。</p>
<ul>
<li>自加操作:<code>let no++</code></li>
<li>自减操作:<code>let no--</code></li>
<li>简写形式 <code>let no+=10</code>,<code>let no-=20</code>,分别等同于<code>let no=no+10</code>,<code>let no=no-20</code></li>
</ul>
<h1>11. 流程控制</h1>
<h2>11.1. if</h2>
<pre><code class="language-shell">if ((10&lt;2));then
echo &quot;10小于2&quot;
elif ((10&gt;20));then
echo &quot;a大于10&quot;
else
echo &quot;10大于2且小于10&quot;
fi
</code></pre>
<h2>11.2. case</h2>
<p><code>case</code>每一种情况以右括号结尾,执行到<code>;;</code>结束</p>
<pre><code class="language-shell">case 10 in
0|1)
echo &quot;a为0或1&quot;
;;
11|12)
echo &quot;a为11或12&quot;
;;
*)
# *用来匹配所有情况
echo &quot;a为10&quot;
;;
esac
</code></pre>
<h2>11.3. while</h2>
<pre><code class="language-shell">count=0
while(($count&lt;5))
do
echo $count
let count++
done
</code></pre>
<h2>11.4. util</h2>
<pre><code class="language-shell">count=0
until(($count&gt;=5))
do
echo $count
let count++
done
</code></pre>
<h2>11.5. for</h2>
<pre><code class="language-shell"># for写法1
for ((count=0;$count&lt;5;count=$count+1))
do
echo $count
done
# for写法2
arr=(0 1 2 3 4)
for count in ${arr[*]}
do
echo $int
done
# for写法3
for int in 0 1 2 3 4
do
echo $int
done
</code></pre>
<h2>11.6. break和continue</h2>
<p>用法与一般编程语言类似,break跳出循环,continue跳出当前循环</p>
<pre><code class="language-shell">for ((count=0;$count&gt;=0;count=$count+1))
do
if (($count&gt;=5));then
break;
fi
echo $count
done
</code></pre>
<h1>12. 输入输出重定向</h1>
<h2>12.1. 输出重定向</h2>
<p><code>command &gt; file</code>将命令输出结果保存的file文件中。<code>&gt;</code>从文件头开始写,会覆盖旧内容,<code>&gt;&gt;</code>将内容追加到文件末尾</p>
<pre><code class="language-shell"># 将who命令的输出保存的users文件中,可以通过cat users查看
who &gt; users
# 将字符串hello world保存到text.txt文件中
echo &quot;hello world&quot; &gt; text.txt
</code></pre>
<h2>12.2. 输入重定向</h2>
<p><code>command &lt; file</code>从file文件获取输入</p>
<pre><code class="language-shell">wc -l /etc/passwd
# 123 /etc/passwd
wc -l &lt; users
# 123
# 第一个例子,会输出文件名;第二个不会,因为它仅仅知道从标准输入读取内容
# command &lt; infile &gt; outfile, 同时替换输入和输出,执行command,从文件infile读取内容,然后将输出写入到outfile中。
wc -l &lt; /etc/passwd &gt; result
cat result
# 123
</code></pre>
<h2>12.3. 文件描述符</h2>
<p>一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件</p>
<ul>
<li>标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。</li>
<li>标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。</li>
<li>标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。</li>
</ul>
<pre><code class="language-shell"># 将标准错误输出重定向到error_trace
cat /tmp/fake_file 2&gt;error_trace
cat error_trace
# cat: /tmp/fake_fule: No such file or directory
# 将标准输出和标准错误输出都重定向到result
cat /tmp/fake_file &amp;&gt;result
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准错误重定向到标准输出
ls /tmp/fake_file &gt; result 2&gt;&amp;1
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准输入重定向到result,将标准错误输出重定向到error_trace
cat /tmp/fake_file 1&gt;result 2&gt;error_trace
</code></pre>
<h2>12.4. Here Document</h2>
<p>将两个<code>EOF</code>之间的内容(document) 作为输入传递给<code>command</code></p>
<pre><code class="language-bash"># command &lt;&lt; EOF
# document
# EOF
cat &lt;&lt; EOF
hello
shinerio
learn shell
EOF
</code></pre>
<blockquote>
<p>结尾的<code>EOF</code>一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和<code>tab</code>缩进。开始的<code>EOF</code>前后的空格会被忽略掉。</p>
</blockquote>
<h2>12.5. /dev/null</h2>
<p>如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null。<code>command &gt; /dev/null</code></p>
<pre><code class="language-shell">cat users &gt; /dev/null
cat users &gt; /dev/null 2&gt;&amp;1
</code></pre>
<h1>13. set命令</h1>
<p>set指令能设置所使用shell的执行方式,可依照不同的需求来做设置。以下只列出常用的选项参数:</p>
<ul>
<li>-e 若指令传回值不等于0,则立即退出shell。</li>
<li>-f 取消使用通配符。</li>
<li>-n 只读取指令,而不实际执行。</li>
<li>-x 执行指令后,会先显示该指令及所下的参数。</li>
</ul>
#39;hello' ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ 'hello' = 'hello' ];then echo 'hello';fi
# hello
if [ 'hello' != 'ello' ];then echo 'hello';fi
# hello
if [ -z '' ];then echo 'hello';fi
# hello
if [ -n 'hello' ];then echo 'hello';fi
# hello
if [ <p>本文主要介绍shell编程的基本语法以及实际应用中的常见命令。</p>
<h1>1. 注释</h1>
<h2>1.1. 单行注释</h2>
<pre><code class="language-shell"># 这是单行注释
</code></pre>
<h2>1.2. 多行注释</h2>
<pre><code class="language-shell">:&lt;&lt;EOF
多行注释内容
多行注释内容
多行注释内容
EOF
</code></pre>
<p>多行注释<code>EOF</code>也可替换成<code>!</code>或<code>&#39;</code></p>
<pre><code class="language-shell">:&lt;&lt;&#39;
多行注释内容
多行注释内容
多行注释内容
&#39;
:&lt;&lt;!
多行注释内容
多行注释内容
多行注释内容
!
</code></pre>
<h1>2. 变量</h1>
<h2>2.1. 变量定义</h2>
<p>使用<code>VARIABLENAME=VALUE</code>的形式,VALUE如果是字符串的话,可以使用单引号、双引号或者不加引号。单引号内的任何字符都会原样输出,不能进行转义,单引号内不能单独出现一个单引号,但可成对出现,作为字符串拼接使用。双引号内可以有变量,可以出现转义字符。</p>
<h2>2.2. 变量使用</h2>
<p>只需要在变量前加<code>$</code>符号,变量加<code>{}</code>是可选的,方便解释器识别边界。将变量加上<code>{}</code>是一个好习惯,不容易出错。</p>
<pre><code class="language-shell">your_age=25
your_name=&quot;shinerio&quot;
your_name=shinerio
your_name=&#39;shinerio&#39;
echo $your_age # 输出25
echo $your_name # 输出shinerio
echo &quot;${your_name}hello&quot; &lt;span class=&quot;tag&quot;&gt;#这里&lt;/span&gt;{}必须添加,否则解释器认为是${your_namehello}
str=&#39;hello&#39;&#39; # 非法
str=&#39;hello&#39;__&#39;world&#39; # 成对出现的单引号做字符拼接
echo $str &lt;span class=&quot;tag&quot;&gt;#输出hello__world&lt;/span&gt;
str1=&#39;helloworld${your_age}\nnew line&#39;
str2=&quot;helloworld${your_age}\nnew line&quot;
echo $str1 # 输出helloworld${your_age}\nnew line
echo $str2 # 输出helloworld25\nnew line
echo -e $str2 # -e开启转义 \n表示换行 echo默认换行,通过\c强制不换行
&lt;span class=&quot;tag&quot;&gt;#helloworld25&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;#new&lt;/span&gt; line
</code></pre>
<h2>2.3. 只读变量</h2>
<p>使用<code>readonly VARIABLENAME</code>设置变量只读,只读变量的值不能更改</p>
<pre><code class="language-shell">readonly name=&#39;jack&#39;
name=&#39;kelly&#39;
zsh: read-only variable: name
</code></pre>
<h2>2.4. 删除变量</h2>
<p>使用<code>unset VARIABLENAME</code>删除变量。</p>
<h1>3. 字符串操作</h1>
<h2>3.1. 字符串拼接</h2>
<pre><code class="language-shell">str1=&quot;hello&quot;${your_name}&quot;world&quot;
str2=&quot;hello${your_name}world&quot;
str3=&#39;hello&#39;${your_name}&#39;world&#39;
</code></pre>
<h2>3.2. 字符串长度</h2>
<pre><code class="language-shell">str=&#39;hello&#39;
echo ${&lt;span class=&quot;tag&quot;&gt;#str&lt;/span&gt;}
5
</code></pre>
<h2>3.3. 字符串截取</h2>
<p><code>${string:start:length}</code>,索引从0开始,从start(包含)开始截取共计length长度的字符。</p>
<pre><code class="language-shell">str=&#39;helloworld&#39;
echo ${str:0:5}
hello
</code></pre>
<h2>3.4. 字符串运算符</h2>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>=</code></td>
<td>检测两个字符串是否相等,相等返回true</td>
<td><code>[ &#39;hello&#39; = &#39;hello&#39; ]</code></td>
</tr>
<tr>
<td><code>!=</code></td>
<td>检测两个字符串是否相等,不相等返回true</td>
<td><code>[ &#39;hello&#39; != &#39;ello&#39; ]</code></td>
</tr>
<tr>
<td><code>-z</code></td>
<td>检测字符串长度是否为0,为0返回true</td>
<td><code>[ -z &#39;&#39; ]</code></td>
</tr>
<tr>
<td><code>-n </code></td>
<td>检测字符串长度是否不为0,不为0返回true</td>
<td><code>[ -n &#39;hello&#39; ]</code></td>
</tr>
<tr>
<td><code>$</code></td>
<td>检测字符串是否为空,不为空返回true</td>
<td><code>[ $&#39;hello&#39; ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ &#39;hello&#39; = &#39;hello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ &#39;hello&#39; != &#39;ello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ -z &#39;&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ -n &#39;hello&#39; ];then echo &#39;hello&#39;;fi
# hello
if [ $&#39;hello&#39; ];then echo &#39;hello&#39;;fi
str=&#39;hello&#39;
if [ $str ];then echo &#39;hello&#39;;fi
# hello
</code></pre>
<p>注意字符串的等值判断是一个等号<code>&quot;=&quot;</code>,与下文要讲的逻辑运算符使用两个等号<code>&quot;==&quot;</code>做等值判断不一样。</p>
<h1>4. 文件测试运算符</h1>
<table>
<thead>
<tr>
<th>操作符</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>-b file</code></td>
<td>检测文件是否是块设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-c file</code></td>
<td>检测文件是否是字符设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-d file</code></td>
<td>检测文件是否是目录,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-f file</code></td>
<td>检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-g file</code></td>
<td>检测文件是否设置了<code>SGID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-k file</code></td>
<td>检测文件是否设置了粘着位(Sticky Bit),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-p file</code></td>
<td>检测文件是否是有名管道,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-u file</code></td>
<td>检测文件是否设置了<code>SUID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-r file</code></td>
<td>检测文件是否可读,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-w file</code></td>
<td>检测文件是否可写,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-x file</code></td>
<td>检测文件是否可执行,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-s file</code></td>
<td>检测文件是否为空(文件大小是否大于0),不为空返回true。</td>
</tr>
<tr>
<td><code>-e file</code></td>
<td>检测文件(包括目录)是否存在,如果是,则返回true。</td>
</tr>
</tbody></table>
<pre><code class="language-shell">if &lt;a href=&quot;f-home.html&quot; class=&quot;internal-link&quot;&gt; -f &#39;/home&#39; &lt;/a&gt;;then echo &#39;directory&#39;;else echo &#39;file&#39;;fi
# file
if &lt;a href=&quot;d-home.html&quot; class=&quot;internal-link&quot;&gt; -d &#39;/home&#39; &lt;/a&gt;;then echo &#39;directory&#39;;else echo &#39;file&#39;;fi
# directory
if &lt;a href=&quot;e-tmpfake-file.html&quot; class=&quot;internal-link&quot;&gt; -e &#39;/tmp/fake_file&#39; &lt;/a&gt;;then echo &#39;exist&#39;;else echo &#39;not exist&#39;;fi
# not exist
</code></pre>
<h1>5. 数组</h1>
<p><code>shell</code>只支持一维数组,用括号表示,元素通过空格分隔,形如<code>数组名=(值1 值2 ... 值n)</code>。<code>shell</code>数组下标从<code>1</code>开始。</p>
<ul>
<li><code>${数组名[下标]}</code>,读取指索引位置数组元素</li>
<li>使用<code>@</code>或<code>*</code>代替下标,获取数组中所有元素。</li>
<li>使用<code>{&lt;span class=&quot;tag&quot;&gt;#数组名&lt;/span&gt;[@]}</code>或<code>{&lt;span class=&quot;tag&quot;&gt;#数组名&lt;/span&gt;[*]}</code>获取数组元素个数。</li>
</ul>
<pre><code class="language-shell">arr=(value1 value2 value3 value4)
echo ${arr[3]}
# value3
echo ${arr[*]}
# value1 value2 value3 value4
echo ${arr[@]}
# value1 value2 value3 value4
arr[3]=&#39;new_value3&#39;
echo $arr[3]
# new_value3
echo ${&lt;span class=&quot;tag&quot;&gt;#arr&lt;/span&gt;[@]}
# 4
echo &quot;arr[1]的长度为:${&lt;span class=&quot;tag&quot;&gt;#arr&lt;/span&gt;[1]}&quot;
# arr[1]的长度为:6
</code></pre>
<h1>6. 运算符</h1>
<h2>6.1. 赋值运算符</h2>
<pre><code class="language-shell">a=10
b=$a
</code></pre>
<h2>6.2. 算术运算符</h2>
<p>算数运算符支持<code>+,-,*,/,%</code></p>
<h3>6.2.1. expr表示法</h3>
<pre><code class="language-shell">echo `expr 10 + 20`
# 30
echo $(expr 20 / 2)
# 10
echo $(expr 10 \* 20) # 使用expr进行乘法运算时必须使用\进行转义
# 200
</code></pre>
<blockquote>
<p>使用expr表示方法时,表达式和运算符之间必须有空格。</p>
</blockquote>
<h3>6.2.2. <code>$[]</code></h3>
<pre><code class="language-shell">echo $[10%3]
# 1
</code></pre>
<h3>6.2.3. <code>$(())</code></h3>
<pre><code class="language-shell">echo $((10*20))
# 200
</code></pre>
<h2>6.3. 关系运算符</h2>
<p>最常见的关系运算符是:<code>==,!=,&lt;,&gt;,&gt;=,&lt;=</code></p>
<pre><code class="language-shell">echo $[10==10]
# 1
flag=$[20==10]
echo $flag
# 1
echo $[10&gt;=10]
# 1
</code></pre>
<p>如下关系运算符只能使用在条件表达式<code>if、while</code>下,类似<code>flag=[ $a -eq $b ]</code>的直接赋值语句是非法的。关系运算符的条件表达式要放在<strong>一对</strong>方括号中,并且中间需要有空格。也可以使用<code>(())</code>替代<code>[]</code>,此时<code>-eq,-lt,-le</code>之类的需要使用<code>==,&lt;,&lt;=</code>等替换。</p>
<blockquote>
<p><code>[]</code>搭配<code>-eq -ne</code>等使用,<code>(())</code>搭配<code>|| &amp;&amp;</code>等使用。</p>
</blockquote>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>-eq</code></td>
<td>检测两个数是否相等,相等返回true。</td>
<td><code>[ $a -eq $b ]</code></td>
</tr>
<tr>
<td><code>-ne</code></td>
<td>检测两个数是否不相等,不相等返回 true。</td>
<td><code>[ $a -ne $b ]</code></td>
</tr>
<tr>
<td><code>-gt</code></td>
<td>检测左边的数是否大于右边的,如果是,则返回 true。</td>
<td><code>[ $a -gt $b ]</code></td>
</tr>
<tr>
<td><code>-lt</code></td>
<td>检测左边的数是否小于右边的,如果是,则返回 true。</td>
<td><code>[ $a -lt $b ]</code></td>
</tr>
<tr>
<td><code>-ge</code></td>
<td>检测左边的数是否大于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -ge $b ]</code></td>
</tr>
<tr>
<td><code>-le</code></td>
<td>检测左边的数是否小于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -le $b ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ 1 -eq 1 ];then echo &#39;hello&#39;;fi;
# hello
if ((10&gt;=10));then echo &#39;hello&#39;;fi;
# hello
</code></pre>
<h2>6.4. 布尔、逻辑运算符</h2>
<p>布尔、逻辑运算的条件表达式也要放在一对方括号中<code>[]</code>。</p>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>!</code></td>
<td>非运算,表达式为true则返回false,否则返回true。</td>
<td><code>[ ! 10 -eq 0 ]</code></td>
</tr>
<tr>
<td><code>-o</code></td>
<td>或运算,有一个表达式为true则返回true。</td>
<td><code>[ 10 -lt 20 -o 10 -gt 100 ]</code></td>
</tr>
<tr>
<td><code>-a</code></td>
<td>与运算,两个表达式都为true才返回true。</td>
<td><code>[ 10 -lt 20 -a 10 -gt 100 ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ ! 10 -eq 0 ];then echo &#39;hello&#39;;fi
# hello
if [ 10 -ge 10 -a 10 -ge 10 ];then echo &#39;hello&#39;;fi
# hello
if [ 10 -ge 20 -o 10 -ge 0 ];then echo &#39;hello&#39;;fi
# hello
</code></pre>
<p> <code>-o</code>也可以使用<code>||</code>替代,<code>-a</code>也可以使用<code>&amp;&amp;</code>替代,此时需要使用<code>(())</code>或<code>[[]]</code>替代<code>[]</code>。</p>
<pre><code class="language-shell">if &lt;a href=&quot;1010-55.html&quot; class=&quot;internal-link&quot;&gt; 10==10 &amp;&amp; 5==5 &lt;/a&gt;;then echo &#39;hello&#39;;fi
# hello
if ((10==10 &amp;&amp; 5==5));then echo &#39;hello&#39;;fi
# hello
</code></pre>
<h1>7. 传递参数</h1>
<p>在执行 <code>Shell</code>脚本时,向脚本传递参数,脚本内获取参数的格式为:<code>$n</code>。<code>n</code>代表一个数字,<code>1</code>为执行脚本的第一个参数,<code>2</code>为执行脚本的第二个参数,<code>$0</code>为执行的文件名。在为<code>shell</code>脚本传递的参数中如果包含空格,应该使用单引号或者双引号将该参数括起来,以便于脚本将这个参数作为整体来接收。另外,还有几个特殊字符用来处理参数:</p>
<table>
<thead>
<tr>
<th>参数处理</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>$#</code></td>
<td>传递到脚本的参数个数</td>
</tr>
<tr>
<td><code>$*</code></td>
<td>以一个单字符串显示所有向脚本传递的参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$$</code></td>
<td>脚本运行的当前进程ID号</td>
</tr>
<tr>
<td><code>$!</code></td>
<td>后台运行的最后一个进程的ID号</td>
</tr>
<tr>
<td><code>$@</code></td>
<td>与<code>$*</code>相同,但是使用时加引号,并在引号中返回每个参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$-</code></td>
<td>显示Shell使用的当前选项,与set功能相同。</td>
</tr>
<tr>
<td><code>$?</code></td>
<td>显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。</td>
</tr>
</tbody></table>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-bash">set -e
echo &quot;执行的文件名:$0&quot;
echo &quot;参数个数为$#&quot;
echo &quot;第一个参数为:$1&quot;
echo &quot;第二个参数为:$2&quot;
echo &quot;所有参数为:$@&quot;
echo &quot;进程ID号为:$$&quot;
echo &quot;当前shell选项为$-&quot;
echo &quot;上一个命令退出的状态为$?&quot;
</code></pre>
<p>执行结果如下:</p>
<pre><code class="language-shell">$ sh test.sh param1 &quot;param2 with space&quot;
执行的文件名:test.sh
参数个数为2
第一个参数为:param1
第二个参数为:param2 with space
所有参数为:param1 param2 with space
进程ID号为:3700
当前shell选项为ehB
上一个命令退出的状态为0
</code></pre>
<h1>8. 函数</h1>
<p>函数定义通过<code>function_name(){}</code>的形式定义,函数返回值可以显示用return返回,如果不加,将以最后一条命令的运行结果作为返回值,函数返回值只能是数字。函数也可以传递参数,但是函数定义的()中不需要申明。</p>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-shell">sayhello(){
echo &quot;hello&quot;
}
# 注意函数调用只需要函数名,不需要加()
sayhello
sayhellowithparam(){
echo &quot;hello, $1 $2 $3&quot;
return 1
}
sayhellowithparam zhangsan lisi wangwu
echo $?
</code></pre>
<p>输出如下:</p>
<blockquote>
<p>hello<br>hello, zhangsan lisi wangwu<br>1</p>
</blockquote>
<h1>9. 命令替换</h1>
<p>命令替换可以将一个命令的输出作为另外一个命令的参数。</p>
<pre><code class="language-shell"># command1 `command2`
cd `pwd` # 该命令将pwd命令列出的目录作为cd命令的参数,结果仍然是停留在当前目录下
cd `echo $HOME` # 将echo的输出作为cd的参数,即打开用户根目录
</code></pre>
<h1>10. let命令</h1>
<p>let 命令是 BASH 中用于计算的工具,用于执行一个或多个表达式,变量计算中不需要加上 $ 来表示变量。如果表达式中包含了空格或其他特殊字符,则必须引起来。</p>
<ul>
<li>自加操作:<code>let no++</code></li>
<li>自减操作:<code>let no--</code></li>
<li>简写形式 <code>let no+=10</code>,<code>let no-=20</code>,分别等同于<code>let no=no+10</code>,<code>let no=no-20</code></li>
</ul>
<h1>11. 流程控制</h1>
<h2>11.1. if</h2>
<pre><code class="language-shell">if ((10&lt;2));then
echo &quot;10小于2&quot;
elif ((10&gt;20));then
echo &quot;a大于10&quot;
else
echo &quot;10大于2且小于10&quot;
fi
</code></pre>
<h2>11.2. case</h2>
<p><code>case</code>每一种情况以右括号结尾,执行到<code>;;</code>结束</p>
<pre><code class="language-shell">case 10 in
0|1)
echo &quot;a为0或1&quot;
;;
11|12)
echo &quot;a为11或12&quot;
;;
*)
# *用来匹配所有情况
echo &quot;a为10&quot;
;;
esac
</code></pre>
<h2>11.3. while</h2>
<pre><code class="language-shell">count=0
while(($count&lt;5))
do
echo $count
let count++
done
</code></pre>
<h2>11.4. util</h2>
<pre><code class="language-shell">count=0
until(($count&gt;=5))
do
echo $count
let count++
done
</code></pre>
<h2>11.5. for</h2>
<pre><code class="language-shell"># for写法1
for ((count=0;$count&lt;5;count=$count+1))
do
echo $count
done
# for写法2
arr=(0 1 2 3 4)
for count in ${arr[*]}
do
echo $int
done
# for写法3
for int in 0 1 2 3 4
do
echo $int
done
</code></pre>
<h2>11.6. break和continue</h2>
<p>用法与一般编程语言类似,break跳出循环,continue跳出当前循环</p>
<pre><code class="language-shell">for ((count=0;$count&gt;=0;count=$count+1))
do
if (($count&gt;=5));then
break;
fi
echo $count
done
</code></pre>
<h1>12. 输入输出重定向</h1>
<h2>12.1. 输出重定向</h2>
<p><code>command &gt; file</code>将命令输出结果保存的file文件中。<code>&gt;</code>从文件头开始写,会覆盖旧内容,<code>&gt;&gt;</code>将内容追加到文件末尾</p>
<pre><code class="language-shell"># 将who命令的输出保存的users文件中,可以通过cat users查看
who &gt; users
# 将字符串hello world保存到text.txt文件中
echo &quot;hello world&quot; &gt; text.txt
</code></pre>
<h2>12.2. 输入重定向</h2>
<p><code>command &lt; file</code>从file文件获取输入</p>
<pre><code class="language-shell">wc -l /etc/passwd
# 123 /etc/passwd
wc -l &lt; users
# 123
# 第一个例子,会输出文件名;第二个不会,因为它仅仅知道从标准输入读取内容
# command &lt; infile &gt; outfile, 同时替换输入和输出,执行command,从文件infile读取内容,然后将输出写入到outfile中。
wc -l &lt; /etc/passwd &gt; result
cat result
# 123
</code></pre>
<h2>12.3. 文件描述符</h2>
<p>一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件</p>
<ul>
<li>标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。</li>
<li>标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。</li>
<li>标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。</li>
</ul>
<pre><code class="language-shell"># 将标准错误输出重定向到error_trace
cat /tmp/fake_file 2&gt;error_trace
cat error_trace
# cat: /tmp/fake_fule: No such file or directory
# 将标准输出和标准错误输出都重定向到result
cat /tmp/fake_file &amp;&gt;result
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准错误重定向到标准输出
ls /tmp/fake_file &gt; result 2&gt;&amp;1
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准输入重定向到result,将标准错误输出重定向到error_trace
cat /tmp/fake_file 1&gt;result 2&gt;error_trace
</code></pre>
<h2>12.4. Here Document</h2>
<p>将两个<code>EOF</code>之间的内容(document) 作为输入传递给<code>command</code></p>
<pre><code class="language-bash"># command &lt;&lt; EOF
# document
# EOF
cat &lt;&lt; EOF
hello
shinerio
learn shell
EOF
</code></pre>
<blockquote>
<p>结尾的<code>EOF</code>一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和<code>tab</code>缩进。开始的<code>EOF</code>前后的空格会被忽略掉。</p>
</blockquote>
<h2>12.5. /dev/null</h2>
<p>如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null。<code>command &gt; /dev/null</code></p>
<pre><code class="language-shell">cat users &gt; /dev/null
cat users &gt; /dev/null 2&gt;&amp;1
</code></pre>
<h1>13. set命令</h1>
<p>set指令能设置所使用shell的执行方式,可依照不同的需求来做设置。以下只列出常用的选项参数:</p>
<ul>
<li>-e 若指令传回值不等于0,则立即退出shell。</li>
<li>-f 取消使用通配符。</li>
<li>-n 只读取指令,而不实际执行。</li>
<li>-x 执行指令后,会先显示该指令及所下的参数。</li>
</ul>
#39;hello' ];then echo 'hello';fi
str='hello'
if [ $str ];then echo 'hello';fi
# hello
</code></pre>
<p>注意字符串的等值判断是一个等号<code>"="</code>,与下文要讲的逻辑运算符使用两个等号<code>"=="</code>做等值判断不一样。</p>
<h1>4. 文件测试运算符</h1>
<table>
<thead>
<tr>
<th>操作符</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>-b file</code></td>
<td>检测文件是否是块设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-c file</code></td>
<td>检测文件是否是字符设备文件,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-d file</code></td>
<td>检测文件是否是目录,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-f file</code></td>
<td>检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-g file</code></td>
<td>检测文件是否设置了<code>SGID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-k file</code></td>
<td>检测文件是否设置了粘着位(Sticky Bit),如果是,则返回true。</td>
</tr>
<tr>
<td><code>-p file</code></td>
<td>检测文件是否是有名管道,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-u file</code></td>
<td>检测文件是否设置了<code>SUID</code>位,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-r file</code></td>
<td>检测文件是否可读,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-w file</code></td>
<td>检测文件是否可写,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-x file</code></td>
<td>检测文件是否可执行,如果是,则返回true。</td>
</tr>
<tr>
<td><code>-s file</code></td>
<td>检测文件是否为空(文件大小是否大于0),不为空返回true。</td>
</tr>
<tr>
<td><code>-e file</code></td>
<td>检测文件(包括目录)是否存在,如果是,则返回true。</td>
</tr>
</tbody></table>
<pre><code class="language-shell">if <a href="f-home.html" class="internal-link"> -f '/home' </a>;then echo 'directory';else echo 'file';fi
# file
if <a href="d-home.html" class="internal-link"> -d '/home' </a>;then echo 'directory';else echo 'file';fi
# directory
if <a href="e-tmpfake-file.html" class="internal-link"> -e '/tmp/fake_file' </a>;then echo 'exist';else echo 'not exist';fi
# not exist
</code></pre>
<h1>5. 数组</h1>
<p><code>shell</code>只支持一维数组,用括号表示,元素通过空格分隔,形如<code>数组名=(值1 值2 ... 值n)</code>。<code>shell</code>数组下标从<code>1</code>开始。</p>
<ul>
<li><code>${数组名[下标]}</code>,读取指索引位置数组元素</li>
<li>使用<code>@</code>或<code>*</code>代替下标,获取数组中所有元素。</li>
<li>使用<code>{<span class="tag">#数组名</span>[@]}</code>或<code>{<span class="tag">#数组名</span>[*]}</code>获取数组元素个数。</li>
</ul>
<pre><code class="language-shell">arr=(value1 value2 value3 value4)
echo ${arr[3]}
# value3
echo ${arr[*]}
# value1 value2 value3 value4
echo ${arr[@]}
# value1 value2 value3 value4
arr[3]='new_value3'
echo $arr[3]
# new_value3
echo ${<span class="tag">#arr</span>[@]}
# 4
echo "arr[1]的长度为:${<span class="tag">#arr</span>[1]}"
# arr[1]的长度为:6
</code></pre>
<h1>6. 运算符</h1>
<h2>6.1. 赋值运算符</h2>
<pre><code class="language-shell">a=10
b=$a
</code></pre>
<h2>6.2. 算术运算符</h2>
<p>算数运算符支持<code>+,-,*,/,%</code></p>
<h3>6.2.1. expr表示法</h3>
<pre><code class="language-shell">echo `expr 10 + 20`
# 30
echo $(expr 20 / 2)
# 10
echo $(expr 10 \* 20) # 使用expr进行乘法运算时必须使用\进行转义
# 200
</code></pre>
<blockquote>
<p>使用expr表示方法时,表达式和运算符之间必须有空格。</p>
</blockquote>
<h3>6.2.2. <code>$[]</code></h3>
<pre><code class="language-shell">echo $[10%3]
# 1
</code></pre>
<h3>6.2.3. <code>$(())</code></h3>
<pre><code class="language-shell">echo $((10*20))
# 200
</code></pre>
<h2>6.3. 关系运算符</h2>
<p>最常见的关系运算符是:<code>==,!=,<,>,>=,<=</code></p>
<pre><code class="language-shell">echo $[10==10]
# 1
flag=$[20==10]
echo $flag
# 1
echo $[10>=10]
# 1
</code></pre>
<p>如下关系运算符只能使用在条件表达式<code>if、while</code>下,类似<code>flag=[ $a -eq $b ]</code>的直接赋值语句是非法的。关系运算符的条件表达式要放在<strong>一对</strong>方括号中,并且中间需要有空格。也可以使用<code>(())</code>替代<code>[]</code>,此时<code>-eq,-lt,-le</code>之类的需要使用<code>==,<,<=</code>等替换。</p>
<blockquote>
<p><code>[]</code>搭配<code>-eq -ne</code>等使用,<code>(())</code>搭配<code>|| &&</code>等使用。</p>
</blockquote>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>-eq</code></td>
<td>检测两个数是否相等,相等返回true。</td>
<td><code>[ $a -eq $b ]</code></td>
</tr>
<tr>
<td><code>-ne</code></td>
<td>检测两个数是否不相等,不相等返回 true。</td>
<td><code>[ $a -ne $b ]</code></td>
</tr>
<tr>
<td><code>-gt</code></td>
<td>检测左边的数是否大于右边的,如果是,则返回 true。</td>
<td><code>[ $a -gt $b ]</code></td>
</tr>
<tr>
<td><code>-lt</code></td>
<td>检测左边的数是否小于右边的,如果是,则返回 true。</td>
<td><code>[ $a -lt $b ]</code></td>
</tr>
<tr>
<td><code>-ge</code></td>
<td>检测左边的数是否大于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -ge $b ]</code></td>
</tr>
<tr>
<td><code>-le</code></td>
<td>检测左边的数是否小于等于右边的,如果是,则返回 true。</td>
<td><code>[ $a -le $b ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ 1 -eq 1 ];then echo 'hello';fi;
# hello
if ((10>=10));then echo 'hello';fi;
# hello
</code></pre>
<h2>6.4. 布尔、逻辑运算符</h2>
<p>布尔、逻辑运算的条件表达式也要放在一对方括号中<code>[]</code>。</p>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
<th>举例</th>
</tr>
</thead>
<tbody><tr>
<td><code>!</code></td>
<td>非运算,表达式为true则返回false,否则返回true。</td>
<td><code>[ ! 10 -eq 0 ]</code></td>
</tr>
<tr>
<td><code>-o</code></td>
<td>或运算,有一个表达式为true则返回true。</td>
<td><code>[ 10 -lt 20 -o 10 -gt 100 ]</code></td>
</tr>
<tr>
<td><code>-a</code></td>
<td>与运算,两个表达式都为true才返回true。</td>
<td><code>[ 10 -lt 20 -a 10 -gt 100 ]</code></td>
</tr>
</tbody></table>
<pre><code class="language-shell">if [ ! 10 -eq 0 ];then echo 'hello';fi
# hello
if [ 10 -ge 10 -a 10 -ge 10 ];then echo 'hello';fi
# hello
if [ 10 -ge 20 -o 10 -ge 0 ];then echo 'hello';fi
# hello
</code></pre>
<p> <code>-o</code>也可以使用<code>||</code>替代,<code>-a</code>也可以使用<code>&&</code>替代,此时需要使用<code>(())</code>或<code>[[]]</code>替代<code>[]</code>。</p>
<pre><code class="language-shell">if <a href="1010-55.html" class="internal-link"> 10==10 && 5==5 </a>;then echo 'hello';fi
# hello
if ((10==10 && 5==5));then echo 'hello';fi
# hello
</code></pre>
<h1>7. 传递参数</h1>
<p>在执行 <code>Shell</code>脚本时,向脚本传递参数,脚本内获取参数的格式为:<code>$n</code>。<code>n</code>代表一个数字,<code>1</code>为执行脚本的第一个参数,<code>2</code>为执行脚本的第二个参数,<code>$0</code>为执行的文件名。在为<code>shell</code>脚本传递的参数中如果包含空格,应该使用单引号或者双引号将该参数括起来,以便于脚本将这个参数作为整体来接收。另外,还有几个特殊字符用来处理参数:</p>
<table>
<thead>
<tr>
<th>参数处理</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>$#</code></td>
<td>传递到脚本的参数个数</td>
</tr>
<tr>
<td><code>$*</code></td>
<td>以一个单字符串显示所有向脚本传递的参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$</code></td>
<td>脚本运行的当前进程ID号</td>
</tr>
<tr>
<td><code>$!</code></td>
<td>后台运行的最后一个进程的ID号</td>
</tr>
<tr>
<td><code>$@</code></td>
<td>与<code>$*</code>相同,但是使用时加引号,并在引号中返回每个参数,以<code>$1 $2 … $n</code>的形式输出所有参数。</td>
</tr>
<tr>
<td><code>$-</code></td>
<td>显示Shell使用的当前选项,与set功能相同。</td>
</tr>
<tr>
<td><code>$?</code></td>
<td>显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。</td>
</tr>
</tbody></table>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-bash">set -e
echo "执行的文件名:$0"
echo "参数个数为$#"
echo "第一个参数为:$1"
echo "第二个参数为:$2"
echo "所有参数为:$@"
echo "进程ID号为:$"
echo "当前shell选项为$-"
echo "上一个命令退出的状态为$?"
</code></pre>
<p>执行结果如下:</p>
<pre><code class="language-shell">$ sh test.sh param1 "param2 with space"
执行的文件名:test.sh
参数个数为2
第一个参数为:param1
第二个参数为:param2 with space
所有参数为:param1 param2 with space
进程ID号为:3700
当前shell选项为ehB
上一个命令退出的状态为0
</code></pre>
<h1>8. 函数</h1>
<p>函数定义通过<code>function_name(){}</code>的形式定义,函数返回值可以显示用return返回,如果不加,将以最后一条命令的运行结果作为返回值,函数返回值只能是数字。函数也可以传递参数,但是函数定义的()中不需要申明。</p>
<p>编写<code>shell</code>脚本如下:</p>
<pre><code class="language-shell">sayhello(){
echo "hello"
}
# 注意函数调用只需要函数名,不需要加()
sayhello
sayhellowithparam(){
echo "hello, $1 $2 $3"
return 1
}
sayhellowithparam zhangsan lisi wangwu
echo $?
</code></pre>
<p>输出如下:</p>
<blockquote>
<p>hello<br>hello, zhangsan lisi wangwu<br>1</p>
</blockquote>
<h1>9. 命令替换</h1>
<p>命令替换可以将一个命令的输出作为另外一个命令的参数。</p>
<pre><code class="language-shell"># command1 `command2`
cd `pwd` # 该命令将pwd命令列出的目录作为cd命令的参数,结果仍然是停留在当前目录下
cd `echo $HOME` # 将echo的输出作为cd的参数,即打开用户根目录
</code></pre>
<h1>10. let命令</h1>
<p>let 命令是 BASH 中用于计算的工具,用于执行一个或多个表达式,变量计算中不需要加上 $ 来表示变量。如果表达式中包含了空格或其他特殊字符,则必须引起来。</p>
<ul>
<li>自加操作:<code>let no++</code></li>
<li>自减操作:<code>let no--</code></li>
<li>简写形式 <code>let no+=10</code>,<code>let no-=20</code>,分别等同于<code>let no=no+10</code>,<code>let no=no-20</code></li>
</ul>
<h1>11. 流程控制</h1>
<h2>11.1. if</h2>
<pre><code class="language-shell">if ((10<2));then
echo "10小于2"
elif ((10>20));then
echo "a大于10"
else
echo "10大于2且小于10"
fi
</code></pre>
<h2>11.2. case</h2>
<p><code>case</code>每一种情况以右括号结尾,执行到<code>;;</code>结束</p>
<pre><code class="language-shell">case 10 in
0|1)
echo "a为0或1"
;;
11|12)
echo "a为11或12"
;;
*)
# *用来匹配所有情况
echo "a为10"
;;
esac
</code></pre>
<h2>11.3. while</h2>
<pre><code class="language-shell">count=0
while(($count<5))
do
echo $count
let count++
done
</code></pre>
<h2>11.4. util</h2>
<pre><code class="language-shell">count=0
until(($count>=5))
do
echo $count
let count++
done
</code></pre>
<h2>11.5. for</h2>
<pre><code class="language-shell"># for写法1
for ((count=0;$count<5;count=$count+1))
do
echo $count
done
# for写法2
arr=(0 1 2 3 4)
for count in ${arr[*]}
do
echo $int
done
# for写法3
for int in 0 1 2 3 4
do
echo $int
done
</code></pre>
<h2>11.6. break和continue</h2>
<p>用法与一般编程语言类似,break跳出循环,continue跳出当前循环</p>
<pre><code class="language-shell">for ((count=0;$count>=0;count=$count+1))
do
if (($count>=5));then
break;
fi
echo $count
done
</code></pre>
<h1>12. 输入输出重定向</h1>
<h2>12.1. 输出重定向</h2>
<p><code>command > file</code>将命令输出结果保存的file文件中。<code>></code>从文件头开始写,会覆盖旧内容,<code>>></code>将内容追加到文件末尾</p>
<pre><code class="language-shell"># 将who命令的输出保存的users文件中,可以通过cat users查看
who > users
# 将字符串hello world保存到text.txt文件中
echo "hello world" > text.txt
</code></pre>
<h2>12.2. 输入重定向</h2>
<p><code>command < file</code>从file文件获取输入</p>
<pre><code class="language-shell">wc -l /etc/passwd
# 123 /etc/passwd
wc -l < users
# 123
# 第一个例子,会输出文件名;第二个不会,因为它仅仅知道从标准输入读取内容
# command < infile > outfile, 同时替换输入和输出,执行command,从文件infile读取内容,然后将输出写入到outfile中。
wc -l < /etc/passwd > result
cat result
# 123
</code></pre>
<h2>12.3. 文件描述符</h2>
<p>一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件</p>
<ul>
<li>标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。</li>
<li>标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。</li>
<li>标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。</li>
</ul>
<pre><code class="language-shell"># 将标准错误输出重定向到error_trace
cat /tmp/fake_file 2>error_trace
cat error_trace
# cat: /tmp/fake_fule: No such file or directory
# 将标准输出和标准错误输出都重定向到result
cat /tmp/fake_file &>result
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准错误重定向到标准输出
ls /tmp/fake_file > result 2>&1
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准输入重定向到result,将标准错误输出重定向到error_trace
cat /tmp/fake_file 1>result 2>error_trace
</code></pre>
<h2>12.4. Here Document</h2>
<p>将两个<code>EOF</code>之间的内容(document) 作为输入传递给<code>command</code></p>
<pre><code class="language-bash"># command << EOF
# document
# EOF
cat << EOF
hello
shinerio
learn shell
EOF
</code></pre>
<blockquote>
<p>结尾的<code>EOF</code>一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和<code>tab</code>缩进。开始的<code>EOF</code>前后的空格会被忽略掉。</p>
</blockquote>
<h2>12.5. /dev/null</h2>
<p>如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null。<code>command > /dev/null</code></p>
<pre><code class="language-shell">cat users > /dev/null
cat users > /dev/null 2>&1
</code></pre>
<h1>13. set命令</h1>
<p>set指令能设置所使用shell的执行方式,可依照不同的需求来做设置。以下只列出常用的选项参数:</p>
<ul>
<li>-e 若指令传回值不等于0,则立即退出shell。</li>
<li>-f 取消使用通配符。</li>
<li>-n 只读取指令,而不实际执行。</li>
<li>-x 执行指令后,会先显示该指令及所下的参数。</li>
</ul>
</section>
</article>quot;
echo "当前shell选项为$-"
echo "上一个命令退出的状态为$?"
执行结果如下:
$ sh test.sh param1 "param2 with space"
执行的文件名:test.sh
参数个数为2
第一个参数为:param1
第二个参数为:param2 with space
所有参数为:param1 param2 with space
进程ID号为:3700
当前shell选项为ehB
上一个命令退出的状态为0
8. 函数
函数定义通过function_name(){}的形式定义,函数返回值可以显示用return返回,如果不加,将以最后一条命令的运行结果作为返回值,函数返回值只能是数字。函数也可以传递参数,但是函数定义的()中不需要申明。
编写shell脚本如下:
sayhello(){
echo "hello"
}
# 注意函数调用只需要函数名,不需要加()
sayhello
sayhellowithparam(){
echo "hello, $1 $2 $3"
return 1
}
sayhellowithparam zhangsan lisi wangwu
echo $?
输出如下:
hello
hello, zhangsan lisi wangwu
1
9. 命令替换
命令替换可以将一个命令的输出作为另外一个命令的参数。
# command1 `command2`
cd `pwd` # 该命令将pwd命令列出的目录作为cd命令的参数,结果仍然是停留在当前目录下
cd `echo $HOME` # 将echo的输出作为cd的参数,即打开用户根目录
10. let命令
let 命令是 BASH 中用于计算的工具,用于执行一个或多个表达式,变量计算中不需要加上 $ 来表示变量。如果表达式中包含了空格或其他特殊字符,则必须引起来。
- 自加操作:
let no++ - 自减操作:
let no-- - 简写形式
let no+=10,let no-=20,分别等同于let no=no+10,let no=no-20
11. 流程控制
11.1. if
if ((10<2));then
echo "10小于2"
elif ((10>20));then
echo "a大于10"
else
echo "10大于2且小于10"
fi
11.2. case
case每一种情况以右括号结尾,执行到;;结束
case 10 in
0|1)
echo "a为0或1"
;;
11|12)
echo "a为11或12"
;;
*)
# *用来匹配所有情况
echo "a为10"
;;
esac
11.3. while
count=0
while(($count<5))
do
echo $count
let count++
done
11.4. util
count=0
until(($count>=5))
do
echo $count
let count++
done
11.5. for
# for写法1
for ((count=0;$count<5;count=$count+1))
do
echo $count
done
# for写法2
arr=(0 1 2 3 4)
for count in ${arr[*]}
do
echo $int
done
# for写法3
for int in 0 1 2 3 4
do
echo $int
done
11.6. break和continue
用法与一般编程语言类似,break跳出循环,continue跳出当前循环
for ((count=0;$count>=0;count=$count+1))
do
if (($count>=5));then
break;
fi
echo $count
done
12. 输入输出重定向
12.1. 输出重定向
command > file将命令输出结果保存的file文件中。>从文件头开始写,会覆盖旧内容,>>将内容追加到文件末尾
# 将who命令的输出保存的users文件中,可以通过cat users查看
who > users
# 将字符串hello world保存到text.txt文件中
echo "hello world" > text.txt
12.2. 输入重定向
command < file从file文件获取输入
wc -l /etc/passwd
# 123 /etc/passwd
wc -l < users
# 123
# 第一个例子,会输出文件名;第二个不会,因为它仅仅知道从标准输入读取内容
# command < infile > outfile, 同时替换输入和输出,执行command,从文件infile读取内容,然后将输出写入到outfile中。
wc -l < /etc/passwd > result
cat result
# 123
12.3. 文件描述符
一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件
- 标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。
- 标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。
- 标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。
# 将标准错误输出重定向到error_trace
cat /tmp/fake_file 2>error_trace
cat error_trace
# cat: /tmp/fake_fule: No such file or directory
# 将标准输出和标准错误输出都重定向到result
cat /tmp/fake_file &>result
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准错误重定向到标准输出
ls /tmp/fake_file > result 2>&1
cat result
# cat: /tmp/fake_fule: No such file or directory
# 将标准输入重定向到result,将标准错误输出重定向到error_trace
cat /tmp/fake_file 1>result 2>error_trace
12.4. Here Document
将两个EOF之间的内容(document) 作为输入传递给command
# command << EOF
# document
# EOF
cat << EOF
hello
shinerio
learn shell
EOF
结尾的
EOF一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和tab缩进。开始的EOF前后的空格会被忽略掉。
12.5. /dev/null
如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null。command > /dev/null
cat users > /dev/null
cat users > /dev/null 2>&1
13. set命令
set指令能设置所使用shell的执行方式,可依照不同的需求来做设置。以下只列出常用的选项参数:
- -e 若指令传回值不等于0,则立即退出shell。
- -f 取消使用通配符。
- -n 只读取指令,而不实际执行。
- -x 执行指令后,会先显示该指令及所下的参数。