|
|
第1行: |
第1行: |
| 本文作者:[http://127.0.0.1:8000/Leal Leal]
| | 本文作者:Leal |
| | |
|
| |
|
| 授权许可: | | 授权许可: |
| | * [http://creativecommons.org/licenses/by-sa/2.0/ 创作共享协议] |
| | * [http://www.gnu.org/copyleft/fdl.html GNU自由文档许可证] |
|
| |
|
| *
| | 编辑人员:FireHare, Dbzhang800 |
| [http://creativecommons.org/licenses/by-sa/2.0/ 创作共享协议Attribution-ShareAlike 2.0]
| |
|
| |
| *
| |
| [http://www.gnu.org/copyleft/fdl.html GNU自由文档许可证]
| |
| | |
| | |
| 编辑人员:[http://127.0.0.1:8000/FireHare FireHare]
| |
| | |
| 校对人员:
| |
| | |
| 适用版本:
| |
| | |
| 文章状态:
| |
| | |
| 参考文献:
| |
|
| |
|
| | 校对人员:Dbzhang800 |
| ---- | | ---- |
|
| |
|
|
| | == 基本格式 == |
| <div> </div>
| | 我们可以使用任意一种文字编辑器,比如nedit、kedit、emacs、vi等来编写shell脚本,它必须以如下行开始(必须放在文件的第一行): |
|
| | # !/bin/sh |
| | | |
|
| | ... |
| | |
| == 1. 基本格式 == | |
| | |
|
| |
| | |
| 编
| |
| | |
| # !/bin/sh<br> | |
| | |
| <br> ...
| |
|
| |
|
| 符号#!用来告诉系统执行该脚本的程序,本例使用/bin/sh。编辑结束并保存後,如果要执行该脚本,必须先使其可执行: | | 符号#!用来告诉系统执行该脚本的程序,本例使用/bin/sh。编辑结束并保存後,如果要执行该脚本,必须先使其可执行: |
|
| |
|
| <address>chmod +x filename
| | chmod +x filename |
|
| |
|
| 此後在该脚本所在目录下,输入 ./filename 即可执行该脚本。 | | 此後在该脚本所在目录下,输入 ./filename 即可执行该脚本。 |
|
| |
|
|
| | === 合理使用注释 === |
| | |
| === 1.1. 合理使用注释 === | |
| | |
|
| |
|
| |
|
| shell 脚本中以# 开始的行表示注释,直到该行的结束。我们强烈建议你在脚本中进行适当/合理的注释,这样一来,即便你在相当长时间内没有使用该脚本,也能在短时间内就明白 它的作用和工作原理。此外,还有一个很重要的原因是,在注释的帮助下,别人可以快速有效的分享你的脚本,并提出自己的意见和改进。 | | shell 脚本中以# 开始的行表示注释,直到该行的结束。我们强烈建议你在脚本中进行适当/合理的注释,这样一来,即便你在相当长时间内没有使用该脚本,也能在短时间内就明白 它的作用和工作原理。此外,还有一个很重要的原因是,在注释的帮助下,别人可以快速有效的分享你的脚本,并提出自己的意见和改进。 |
|
| |
|
|
| | === 变量赋值和引用 === |
| | |
| === 1.2. 变量赋值和引用 === | |
| | |
|
| |
|
| |
|
| Shell编程中,使用变量无需事先声明,同时变量名的命名须遵循如下规则: | | Shell编程中,使用变量无需事先声明,同时变量名的命名须遵循如下规则: |
第67行: |
第36行: |
|
| |
|
| 需要给变量赋值时,可以这么写: | | 需要给变量赋值时,可以这么写: |
| <pre>变量名=值</pre>
| | 变量名=值 |
|
| |
|
| |
|
| 要取用一个变量的值,只需在变量名前面加一个$: | | 要取用一个变量的值,只需在变量名前面加一个$: |
|
| |
|
| <address>#!/bin/sh<br>
| | #!/bin/sh |
| | | # 对变量赋值: |
| # 对变量赋值:<br> | | a="hello world" |
| | | # 打印变量a的值: |
| a="hello world"<br> <br> | | echo "A is:" $a |
| | |
| # 打印变量a的值:<br> | |
| | |
| echo "A is:" $a | |
|
| |
|
| 挑个自己喜欢的编辑器,输入上述内容,并保存为文件first,然後执行 chmod +x first 使其可执行,最後输入 ./first 执行该脚本。其输出结果如下: | | 挑个自己喜欢的编辑器,输入上述内容,并保存为文件first,然後执行 chmod +x first 使其可执行,最後输入 ./first 执行该脚本。其输出结果如下: |
|
| |
|
| <address>A is: hello world
| | A is: hello world |
|
| |
|
| 有时候变量名可能会和其它文字混淆,比如: | | 有时候变量名可能会和其它文字混淆,比如: |
|
| |
|
| </address> <address>num=2<br> echo "this is the $numnd"
| | num=2 |
| | echo "this is the $numnd" |
|
| |
|
| 上述脚本并不会输出"this is the 2nd"而是"this is the ";这是由于shell会去搜索变量numnd的值,而实际上这个变量此时并没有值。这时,我们可以用花括号来告诉shell要打印的是num变量: | | 上述脚本并不会输出"this is the 2nd"而是"this is the ";这是由于shell会去搜索变量numnd的值,而实际上这个变量此时并没有值。这时,我们可以用花括号来告诉shell要打印的是num变量: |
|
| |
|
| <address>num=2<br> echo "this is the ${num}nd"
| | num=2 |
| | echo "this is the ${num}nd" |
|
| |
|
| 其输出结果为:this is the 2nd | | 其输出结果为:this is the 2nd |
第98行: |
第64行: |
| Shell脚本中有许多变量是系统自动设定的,我们将在用到这些变量时再作说明。除了只在脚本内有效的普通shell变量外,还有环境变量,即那些由export关键字处理过的变量。本文不讨论环境变量,因为它们一般只在登录脚本中用到。 | | Shell脚本中有许多变量是系统自动设定的,我们将在用到这些变量时再作说明。除了只在脚本内有效的普通shell变量外,还有环境变量,即那些由export关键字处理过的变量。本文不讨论环境变量,因为它们一般只在登录脚本中用到。 |
|
| |
|
|
| | == Shell里的命令 == |
|
| |
|
| == 2. Shell里的命令 == | | === Unix 命令 === |
|
| |
|
|
| | 在shell脚本中可以使用任意unix命令,不过实际上最为常用的一般都是那些文件和文字操作相关的命令。下面介绍一些常用命令的语法和功能: |
|
| |
|
|
| | ;echo "some text": 在屏幕上输出信息 |
|
| |
|
| === 2.1. Unix 命令 ===
| | ;ls: 文件列表 |
|
| |
|
|
| | ;wc –l file wc -w file wc -c file: 分别计算文件的行数(line)、单词数(word)和字符数(character) |
|
| |
|
| 在shell脚本中可以使用任意unix命令,不过实际上最为常用的一般都是那些文件和文字操作相关的命令。下面介绍一些常用命令的语法和功能:
| | ;cp sourcefile destfile: 文件拷贝 |
|
| |
|
| echo "some text": 在屏幕上输出信息<br><br> ls: 文件列表<br><br> wc –l file wc -w file wc -c file: 分别计算文件的行数(line)、单词数(word)和字符数(character)<br><br> cp sourcefile destfile: 文件拷贝<br><br> mv oldname newname: 重命名文件或移动文件<br><br> rm file: 删除文件<br><br> grep 'pattern' file: 在文件内搜索字符串或和正则表达式匹配的字符串<br><br> cut -b column file: 将指定范围内的文件内容输出到标准输出设备(屏幕)上。比如:输出每行第5至9个字符 cut -b5-9 file.txt,注意不要和cat命令混淆,这是两个完全不同的命令<br><br> cat file.txt: 输出文件内容到标准输出设备(屏幕)上<br><br> file somefile: 取得文件somefile的文件类型<br><br> read var: 提示用户输入,并将输入内容赋值给变量var<br><br> sort file.txt: 对file.txt文件所有行进行排序<br><br> uniq: 只输出文件中内容不一致的行,如: sort file.txt | uniq<br><br> expr: 进行数学运算,如要进行2+3的运算,命令为: expr 2 "+" 3<br><br> find: 搜索文件,如根据文件名搜索:find . -name filename -print<br><br> tee: 将数据输出到标准输出设备(屏幕) 和文件,比如:somecommand | tee outfile<br><br> basename file: 返回不包含路径的文件名,如: basename /bin/tux 会返回 tux<br><br> dirname file: 返回文件所在路径,如:dirname /bin/tux 会返回 /bin<br><br> head file: 打印文本文件开头几行<br><br> tail file : 打印文本文件末尾几行<br><br> sed: 是一个基本的查找替换程序。可以从标准输入(如命令管道)读入文本,并将结果输出到标准输出(屏幕);该命令采用正则表达式进行搜索。不要和 shell中的通配符相混淆。比如将 ubuntu 替换为 Ubuntu :cat text.file | sed 's/ubuntu/Ubuntu/' > newtext.file<br><br> awk: 用来提取文本文件中的字段。缺省的字段分割符是空格,可以使用 -F 指定其它分割符。cat file.txt | awk -F, '{print $1 "," $3 }',这里我们使用 , 作为字段分割符,同时打印第一和第三个字段。如果该文件内容为 Adam Bor, 34, IndiaKerry Miller, 22, USA,则上述命令的输出为:Adam Bor, IndiaKerry Miller, USA
| | ;mv oldname newname: 重命名文件或移动文件 |
|
| |
|
|
| | ;rm file: 删除文件 |
|
| |
|
|
| | ;grep 'pattern' file: 在文件内搜索字符串或和正则表达式匹配的字符串 |
|
| |
|
| === 2.2. 概念: 管道, 重定向和 backtick ===
| | ;cut -b column file: 将指定范围内的文件内容输出到标准输出设备(屏幕)上。比如:输出每行第5至9个字符 cut -b5-9 file.txt,注意不要和cat命令混淆,这是两个完全不同的命令 |
|
| |
|
|
| | ;cat file.txt: 输出文件内容到标准输出设备(屏幕)上 |
|
| |
|
| ----
| | ;file somefile: 取得文件somefile的文件类型 |
|
| |
|
|
| | ;read var: 提示用户输入,并将输入内容赋值给变量var |
|
| |
|
| 尽管这些都不是系统命令,不过它们扮演着相当重要的角色。
| | ;sort file.txt: 对file.txt文件所有行进行排序 |
|
| |
|
| * 管道 (|) 将一个命令的输出作为另外一个命令的输入
| | ;uniq: 只输出文件中内容不一致的行,如: sort file.txt | uniq |
|
| |
|
|
| | ;expr: 进行数学运算,如要进行2+3的运算,命令为: expr 2 "+" 3 |
| <pre>grep "hello" file.txt | wc -l<br /></pre>
| |
|
| |
|
| |
|
| 上述命令会在file.txt中搜索包含有”hello”的行并计算行数,这里grep命令的输出成了wc命令的输入。
| | ;find: 搜索文件,如根据文件名搜索:find . -name filename -print |
|
| |
|
| * 重定向:将命令的结果输出到文件,而不是标准输出(屏幕)
| | ;tee: 将数据输出到标准输出设备(屏幕) 和文件,比如:somecommand | tee outfile |
|
| |
|
|
| | ;basename file: 返回不包含路径的文件名,如: basename /bin/tux 会返回 tux |
| <pre>> 写入文件并复盖旧文件<br /> >> 加到文件的尾部,保留旧文件内容<br /></pre>
| |
|
| |
|
| |
|
| * 反短斜线
| | ;dirname file: 返回文件所在路径,如:dirname /bin/tux 会返回 /bin |
|
| |
|
| 反短斜线可以将一个命令的输出作为其它命令的命令行参数。
| | ;head file: 打印文本文件开头几行 |
| <pre>find . -mtime -1 -type f -print<br /></pre>
| |
|
| |
|
| |
|
| 上述命令可以查找过去24小时(-mtime –2则表示过去48小时)内修改过的文件。如果你想将上述命令查找到的所有文件打包,则可以使用如下脚本:
| | ;tail file : 打印文本文件末尾几行 |
| <pre>#!/bin/sh<br /><br /> # The ticks are backticks (`) not normal quotes ('):<br /> tar -zcvf lastmod.tar.gz `find . -mtime -1 -type f -print`<br /></pre>
| |
|
| |
|
| |
|
| | | ;sed: 是一个基本的查找替换程序。可以从标准输入(如命令管道)读入文本,并将结果输出到标准输出(屏幕);该命令采用正则表达式进行搜索。不要和 shell中的通配符相混淆。比如将 ubuntu 替换为 Ubuntu :cat text.file | sed 's/ubuntu/Ubuntu/' > newtext.file |
|
| |
|
| == 3. Shell里的流程控制 ==
| | ;awk: 用来提取文本文件中的字段。缺省的字段分割符是空格,可以使用 -F 指定其它分割符。cat file.txt | awk -F, '{print $1 "," $3 }',这里我们使用 , 作为字段分割符,同时打印第一和第三个字段。如果该文件内容为 Adam Bor, 34, IndiaKerry Miller, 22, USA,则上述命令的输出为:Adam Bor, IndiaKerry Miller, USA |
|
| |
|
|
| | === 概念: 管道, 重定向和 backtick === |
|
| |
|
|
| | 尽管这些都不是系统命令,不过它们扮演着相当重要的角色。 |
|
| |
|
| === 3.1. if 语句 ===
| | * 管道 (|) 将一个命令的输出作为另外一个命令的输入 |
|
| |
|
|
| | grep "hello" file.txt | wc -l |
|
| |
|
| "if"表达式如果条件为真,则执行then後的部分:
| | 上述命令会在file.txt中搜索包含有”hello”的行并计算行数,这里grep命令的输出成了wc命令的输入。 |
| <div lang="en" dir="ltr" class="codearea"><script type="text/javascript">
| |
| function isnumbered(obj) {
| |
|
| |
|
| return obj.childNodes.length && obj.firstChild.childNodes.length && obj.firstChild.firstChild.className == 'LineNumber';
| | * 重定向:将命令的结果输出到文件,而不是标准输出(屏幕) |
|
| |
|
| } function nformat(num,chrs,add) {
| | > 写入文件并复盖旧文件 |
|
| |
|
| var nlen = Math.max(0,chrs-(''+num).length), res = '';
| | >> 加到文件的尾部,保留旧文件内容 |
| while (nlen>0) { res += ' '; nlen-- }
| |
| return res+num+add;
| |
|
| |
|
| } function addnumber(did, nstart, nstep) {
| | * 反短斜线 |
|
| |
|
| var c = document.getElementById(did), l = c.firstChild, n = 1; | | 反短斜线可以将一个命令的输出作为其它命令的命令行参数。 |
| if (!isnumbered(c))
| | find . -mtime -1 -type f -print |
| if (typeof nstart == 'undefined') nstart = 1;
| |
| if (typeof nstep == 'undefined') nstep = 1;
| |
| n = nstart;
| |
| while (l != null) {
| |
| if (l.tagName == 'SPAN') {
| |
| var s = document.createElement('SPAN');
| |
| s.className = 'LineNumber'
| |
| s.appendChild(document.createTextNode(nformat(n,4,' ')));
| |
| n += nstep;
| |
| if (l.childNodes.length)
| |
| l.insertBefore(s, l.firstChild)
| |
| else
| |
| l.appendChild(s)
| |
| }
| |
| l = l.nextSibling;
| |
| }
| |
| return false;
| |
|
| |
|
| } function remnumber(did) {
| | 上述命令可以查找过去24小时(-mtime –2则表示过去48小时)内修改过的文件。如果你想将上述命令查找到的所有文件打包,则可以使用如下脚本: |
| | #!/bin/sh |
| | |
| | # The ticks are backticks (`) not normal quotes ('): |
| | tar -zcvf lastmod.tar.gz `find . -mtime -1 -type f -print` |
|
| |
|
| var c = document.getElementById(did), l = c.firstChild;
| | == Shell里的流程控制 == |
| if (isnumbered(c))
| |
| while (l != null) {
| |
| if (l.tagName == 'SPAN' && l.firstChild.className == 'LineNumber') l.removeChild(l.firstChild);
| |
| l = l.nextSibling;
| |
| }
| |
| return false;
| |
|
| |
|
| } function togglenumber(did, nstart, nstep) {
| | === if 语句 === |
|
| |
|
| var c = document.getElementById(did);
| | "if"表达式如果条件为真,则执行then后的部分: |
| if (isnumbered(c)) {
| |
| remnumber(did);
| |
| } else {
| |
| addnumber(did,nstart,nstep);
| |
| }
| |
| return false;
| |
|
| |
|
| } </script> <script type="text/javascript"> document.write('<a href="#" onclick="return togglenumber(\'CA-f5c371b7eea37b1e7bfdc12cca5acd38bf88b99c_000\', 1, 1);" \
| | if ....; then |
| | .... |
| | elif ....; then |
| | .... |
| | else |
| | .... |
| | fi |
|
| |
|
| class="codenumbers">Toggle line numbers<\/a>');
| | 大多数情况下,可以使用测试命令来对条件进行测试,比如可以比较字符串、判断文件是否存在及是否可读等等……通常用" [ ] "来表示条件测试,注意这里的空格很重要,要确保方括号前后的空格。 |
|
| |
|
| </script><span class="codenumbers">Toggle line numbers</span> <address><span class="line"><span class="LineNumber">1</span> <span class="ResWord">if</span> <span class="Operator">.</span><span class="Operator">.</span><span class="Operator">.</span><span class="Operator">.</span><span class="Operator">;</span> <span class="ID">then</span></span><br> <span class="line"><span class="LineNumber">2</span> <span class="Operator">.</span><span class="Operator">.</span><span class="Operator">.</span><span class="Operator">.</span></span><br> <span class="line"><span class="LineNumber">3</span> <span class="ResWord">elif</span> <span class="Operator">.</span><span class="Operator">.</span><span class="Operator">.</span><span class="Operator">.</span><span class="Operator">;</span> <span class="ID">then</span></span><br> <span class="line"><span class="LineNumber">4</span> <span class="Operator">.</span><span class="Operator">.</span><span class="Operator">.</span><span class="Operator">.</span></span><br> <span class="line"><span class="LineNumber">5</span> <span class="ResWord">else</span></span><br> <span class="line"><span class="LineNumber">6</span> <span class="Operator">.</span><span class="Operator">.</span><span class="Operator">.</span><span class="Operator">.</span></span><br> <span class="line"><span class="LineNumber">7</span> <span class="ID">fi</span></span></address>
| | ;[ -f "somefile" ] :判断是否是一个文件 |
| </div>
| | ;[ -x "/bin/ls" ] :判断/bin/ls是否存在并有可执行权限 |
| <address> </address>
| | ;[ -n "$var" ] :判断$var变量是否有值 |
| | | ;[ "$a" = "$b" ] :判断$a和$b是否相等 |
| 大多数情况下,可以使用测试命令来对条件进行测试,比如可以比较字符串、判断文件是否存在及是否可读等等……通常用" [ ] "来表示条件测试,注意这里的空格很重要,要确保方括号前後的空格。
| |
| <pre>[ -f "somefile" ] :判断是否是一个文件<br /> [ -x "/bin/ls" ] :判断/bin/ls是否存在并有可执行权限<br /> [ -n "$var" ] :判断$var变量是否有值<br /> [ "$a" = "$b" ] :判断$a和$b是否相等</pre>
| |
|
| |
|
| |
|
| 执行man test可以查看所有测试表达式可以比较和判断的类型。下面是一个简单的if语句: | | 执行man test可以查看所有测试表达式可以比较和判断的类型。下面是一个简单的if语句: |
| <div lang="en" dir="ltr" class="codearea"><script type="text/javascript">
| |
| document.write('<a href="#" onclick="return togglenumber(\'CA-a3fb8bf838f3565b62e0b99e3059c942a69f48d4_001\', 1, 1);" \
| |
|
| |
|
| class="codenumbers">Toggle line numbers<\/a>'); | | #!/bin/sh |
| | | |
| </script><span class="codenumbers">Toggle line numbers</span> <address><span class="line"><span class="LineNumber">1</span> <span class="Comment">#!/bin/sh</span></span><br> <span class="line"><span class="LineNumber">2</span></span><br> <span class="line"><span class="LineNumber">3</span> <span class="ResWord">if</span> <span class="Operator">[</span> <span class="String">"$SHELL"</span> <span class="Operator">=</span> <span class="String">"/bin/bash"</span> <span class="Operator">]</span><span class="Operator">;</span> <span class="ID">then</span></span><br> <span class="line"><span class="LineNumber">4</span> <span class="ID">echo</span> <span class="String">"your login shell is the bash (bourne again shell)"</span></span><br> <span class="line"><span class="LineNumber">5</span> <span class="ResWord">else</span></span><br> <span class="line"><span class="LineNumber">6</span> <span class="ID">echo</span> <span class="String">"your login shell is not bash but $SHELL"</span></span><br> <span class="line"><span class="LineNumber">7</span> <span class="ID">fi</span></span></address>
| | if [ "$SHELL" = "/bin/bash" ]; then |
| </div>
| | echo "your login shell is the bash (bourne again shell)" |
|
| | else |
| | echo "your login shell is not bash but $SHELL" |
| | fi |
|
| |
|
| 变量$SHELL包含有登录shell的名称,我们拿它和/bin/bash进行比较以判断当前使用的shell是否为bash。 | | 变量$SHELL包含有登录shell的名称,我们拿它和/bin/bash进行比较以判断当前使用的shell是否为bash。 |
| | | === && 和|| 操作符=== |
|
| |
| | |
| === 3.2. && 和|| 操作符 === | |
| | |
|
| |
|
| |
|
| 熟悉C语言的朋友可能会喜欢下面的表达式: | | 熟悉C语言的朋友可能会喜欢下面的表达式: |
| <pre>[ -f "/etc/shadow" ] && echo "This computer uses shadow passwords"<br /></pre>
| |
|
| |
|
| |
|
| 这 里的 && 就是一个快捷操作符,如果左边的表达式为真则执行右边的语句,你也可以把它看作逻辑运算里的与操作。上述脚本表示如果/etc/shadow文件存在,则 打印”This computer uses shadow passwords”。同样shell编程中还可以用或操作(||),例如:
| | [ -f "/etc/shadow" ] && echo "This computer uses shadow passwords" |
| <div lang="en" class="codearea" dir="ltr"><script type="text/javascript">
| |
| document.write('<a href="#" onclick="return togglenumber(\'CA-860ef357b644a8342b4058c577e45c6a5b440045_002\', 1, 1);" \
| |
|
| |
|
| class="codenumbers">Toggle line numbers<\/a>');
| | 这里的 && 就是一个快捷操作符,如果左边的表达式为真则执行右边的语句,你也可以把它看作逻辑运算里的与操作。上述脚本表示如果/etc/shadow文件存在,则打印”This computer uses shadow passwords”。同样shell编程中还可以用或操作(||),例如: |
|
| |
|
| </script><a class="codenumbers" onclick="return togglenumber('CA-860ef357b644a8342b4058c577e45c6a5b440045_002', 1, 1);" href="http://127.0.0.1:8000/Shell%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80#">Toggle line numbers</a>
| | #!/bin/sh |
| <pre lang="en" dir="ltr" id="CA-860ef357b644a8342b4058c577e45c6a5b440045_002"><span class="line"><span class="LineNumber"> 1 </span> <span class="Comment">#!/bin/sh</span></span><br /><span class="line"><span class="LineNumber"> 2 </span></span><br /><span class="line"><span class="LineNumber"> 3 </span> <span class="ID">mailfolder</span><span class="Operator">=</span><span class="Operator">/</span><span class="ID">var</span><span class="Operator">/</span><span class="ID">spool</span><span class="Operator">/</span><span class="ID">mail</span><span class="Operator">/</span><span class="ID">james</span></span><br /><span class="line"><span class="LineNumber"> 4 </span> <span class="Operator">[</span> <span class="Operator">-</span><span class="ID">r</span> <span class="String">"$mailfolder"</span> <span class="Operator">]</span> <span class="Operator">|</span><span class="Operator">|</span> <span class="Operator">{</span> <span class="ID">echo</span> <span class="String">"Can not read $mailfolder"</span> <span class="Operator">;</span> <span class="ID">exit</span> <span class="Number">1</span><span class="Operator">;</span> <span class="Operator">}</span></span><br /><span class="line"><span class="LineNumber"> 5 </span> <span class="ID">echo</span> <span class="String">"$mailfolder has mail from:"</span></span><br /><span class="line"><span class="LineNumber"> 6 </span> <span class="ID">grep</span> <span class="String">"^From "</span><span class="Error"> </span><span class="Error">$</span><span class="ID">mailfolder</span></span></pre></div>
| | |
|
| | mailfolder=/var/spool/mail/james |
| | [ -r "$mailfolder" ] || { echo "Can not read $mailfolder" ; exit 1; } |
| | echo "$mailfolder has mail from:" |
| | grep "^From " $mailfolder |
|
| |
|
| 该脚本首先判断mailfolder是否可读,如果可读则打印该文件中的"From" 一行。如果不可读则或操作生效,打印错误信息後脚本退出。需要注意的是,这里我们必须使用如下两个命令: | | 该脚本首先判断mailfolder是否可读,如果可读则打印该文件中的"From" 一行。如果不可读则或操作生效,打印错误信息后脚本退出。需要注意的是,这里我们必须使用如下两个命令: |
| <pre>-打印错误信息<br /><br /> -退出程序<br /></pre>
| |
|
| |
|
| |
|
| 我们使用花括号以匿名函数的形式将两个命令放到一起作为一个命令使用;普通函数稍後再作说明。即使不用与和或操作符,我们也可以用if表达式完成任何事情,但是使用与或操作符会更便利很多。
| | :-打印错误信息 |
|
| |
|
|
| | :-退出程序 |
|
| |
|
| === 3.3. case 语句 === | | 我们使用花括号以匿名函数的形式将两个命令放到一起作为一个命令使用;普通函数稍后再作说明。即使不用与和或操作符,我们也可以用if表达式完成任何事情,但是使用与或操作符会更便利很多。 |
| | == case 语句== |
|
| |
|
|
| | case表达式可以用来匹配一个给定的字符串,而不是数字(可别和C语言里的switch...case混淆)。 |
|
| |
|
| case表达式可以用来匹配一个给定的字符串,而不是数字(可别和C语言里的switch...case混淆)。
| | case ... in |
| <pre>case ... in<br /> ...) do something here ;;<br /> esac<br /></pre>
| | ...) do something here ;; |
|
| | esac |
|
| |
|
| 让我们看一个例子,file命令可以辨别出一个给定文件的文件类型,如:file lf.gz,其输出结果为: | | 让我们看一个例子,file命令可以辨别出一个给定文件的文件类型,如:file lf.gz,其输出结果为: |
| <pre>lf.gz: gzip compressed data, deflated, original filename,<br /> last modified: Mon Aug 27 23:09:18 2001, os: Unix<br /></pre>
| | |
|
| | lf.gz: gzip compressed data, deflated, original filename, |
| | last modified: Mon Aug 27 23:09:18 2001, os: Unix |
|
| |
|
| 我们利用这点写了一个名为smartzip的脚本,该脚本可以自动解压bzip2, gzip和zip 类型的压缩文件: | | 我们利用这点写了一个名为smartzip的脚本,该脚本可以自动解压bzip2, gzip和zip 类型的压缩文件: |
| <div lang="en" class="codearea" dir="ltr"><script type="text/javascript">
| |
| document.write('<a href="#" onclick="return togglenumber(\'CA-c663a0073c2d49110ab4f3f23f7f6ef77a138b02_003\', 1, 1);" \
| |
|
| |
|
| class="codenumbers">Toggle line numbers<\/a>'); | | #!/bin/sh |
| | |
| | ftype=`file "$1"` |
| | case "$ftype" in |
| | "$1: Zip archive"*) |
| | unzip "$1" ;; |
| | "$1: gzip compressed"*) |
| | gunzip "$1" ;; |
| | "$1: bzip2 compressed"*) |
| | bunzip2 "$1" ;; |
| | *) error "File $1 can not be uncompressed with smartzip";; |
| | esac |
|
| |
|
| </script><a class="codenumbers" onclick="return togglenumber('CA-c663a0073c2d49110ab4f3f23f7f6ef77a138b02_003', 1, 1);" href="http://127.0.0.1:8000/Shell%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80#">Toggle line numbers</a>
| | 你可能注意到上面使用了一个特殊变量$1,该变量包含有传递给该脚本的第一个参数值。也就是说,当我们运行: |
| <pre lang="en" dir="ltr" id="CA-c663a0073c2d49110ab4f3f23f7f6ef77a138b02_003"><span class="line"><span class="LineNumber"> 1 </span> <span class="Comment">#!/bin/sh</span></span><br /><span class="line"><span class="LineNumber"> 2 </span></span><br /><span class="line"><span class="LineNumber"> 3 </span> <span class="ID">ftype</span><span class="Operator">=</span><span class="Operator">`</span><span class="ID">file</span> <span class="String">"$1"</span><span class="Operator">`</span></span><br /><span class="line"><span class="LineNumber"> 4 </span> <span class="ID">case</span> <span class="String">"$ftype"</span> <span class="ResWord">in</span></span><br /><span class="line"><span class="LineNumber"> 5 </span> <span class="String">"$1: Zip archive"</span><span class="Operator">*</span><span class="Operator">)</span></span><br /><span class="line"><span class="LineNumber"> 6 </span> <span class="ID">unzip</span> <span class="String">"$1"</span> <span class="Operator">;</span><span class="Operator">;</span></span><br /><span class="line"><span class="LineNumber"> 7 </span> <span class="String">"$1: gzip compressed"</span><span class="Operator">*</span><span class="Operator">)</span></span><br /><span class="line"><span class="LineNumber"> 8 </span> <span class="ID">gunzip</span> <span class="String">"$1"</span> <span class="Operator">;</span><span class="Operator">;</span></span><br /><span class="line"><span class="LineNumber"> 9 </span> <span class="String">"$1: bzip2 compressed"</span><span class="Operator">*</span><span class="Operator">)</span></span><br /><span class="line"><span class="LineNumber"> 10 </span> <span class="ID">bunzip2</span> <span class="String">"$1"</span> <span class="Operator">;</span><span class="Operator">;</span></span><br /><span class="line"><span class="LineNumber"> 11 </span> <span class="Operator">*</span><span class="Operator">)</span> <span class="ID">error</span> <span class="String">"File $1 can not be uncompressed with smartzip"</span><span class="Operator">;</span><span class="Operator">;</span></span><br /><span class="line"><span class="LineNumber"> 12 </span> <span class="ID">esac</span><br /><strong>ERROR: EOF in multi-line statement</strong><br /></span></pre></div>
| |
|
| |
|
| |
|
| 你可能注意到上面使用了一个特殊变量$1,该变量包含有传递给该脚本的第一个参数值。也就是说,当我们运行:
| | smartzip articles.zip |
| <pre>smartzip articles.zip<br /></pre>
| |
|
| |
|
| |
|
| $1 就是字符串 articles.zip。 | | $1 就是字符串 articles.zip。 |
| | | === select 语句=== |
|
| |
| | |
| === 3.4. select 语句 === | |
| | |
|
| |
|
| |
|
| select表达式是bash的一种扩展应用,擅长于交互式场合。用户可以从一组不同的值中进行选择: | | select表达式是bash的一种扩展应用,擅长于交互式场合。用户可以从一组不同的值中进行选择: |
|
| |
|
|
| | select var in ... ; do |
| <div lang="en" dir="ltr" class="codearea"><script type="text/javascript">
| | break |
| document.write('<a href="#" onclick="return togglenumber(\'CA-1372e104ca0ef28128f5a5bc7daa780e167ad6f9_004\', 1, 1);" \
| | done |
| | | .... now $var can be used .... |
| class="codenumbers">Toggle line numbers<\/a>'); | |
| | |
| </script><a href="http://127.0.0.1:8000/Shell%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80#" onclick="return togglenumber('CA-1372e104ca0ef28128f5a5bc7daa780e167ad6f9_004', 1, 1);" class="codenumbers">Toggle line numbers</a> <address><span class="line"><span class="LineNumber">1</span><span class="ID">select</span> <span class="ID">var</span> <span class="ResWord">in</span> <span class="Operator">.</span><span class="Operator">.</span><span class="Operator">.</span> <span class="Operator">;</span> <span class="ID">do</span></span><br> <span class="line"><span class="LineNumber">2</span><span class="Error"> </span><span class="ResWord">break</span></span><br> <span class="line"><span class="LineNumber">3</span><span class="ID">done</span></span><br> <span class="line"><span class="LineNumber">4</span><span class="Operator">.</span><span class="Operator">.</span><span class="Operator">.</span><span class="Operator">.</span> <span class="ID">now</span><span class="Error"></span><span class="Error">$</span><span class="ID">var</span> <span class="ID">can</span> <span class="ID">be</span> <span class="ID">used</span> <span class="Operator">.</span><span class="Operator">.</span><span class="Operator">.</span><span class="Operator">.</span></span></address>
| |
| </div>
| |
|
| |
|
| |
|
| 下面是一个简单的示例: | | 下面是一个简单的示例: |
| <div lang="en" dir="ltr" class="codearea"><script type="text/javascript">
| |
| document.write('<a href="#" onclick="return togglenumber(\'CA-c92b7b6a34e56af6238cf6e11462e8411a656b79_005\', 1, 1);" \
| |
|
| |
|
| class="codenumbers">Toggle line numbers<\/a>'); | | #!/bin/sh |
| | | |
| </script><a href="http://127.0.0.1:8000/Shell%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80#" onclick="return togglenumber('CA-c92b7b6a34e56af6238cf6e11462e8411a656b79_005', 1, 1);" class="codenumbers">Toggle line numbers</a> <address><span class="line"><span class="LineNumber">1</span><span class="Comment">#!/bin/sh</span></span><br> <span class="line"><span class="LineNumber">2</span></span><br> <span class="line"><span class="LineNumber">3</span><span class="ID">echo</span> <span class="String">"What is your favourite OS?"</span></span><br> <span class="line"><span class="LineNumber">4</span><span class="ID">select</span> <span class="ID">var</span> <span class="ResWord">in</span> <span class="String">"Linux"</span> <span class="String">"Gnu Hurd"</span> <span class="String">"Free BSD"</span> <span class="String">"Other"</span><span class="Operator">;</span> <span class="ID">do</span></span><br> <span class="line"><span class="LineNumber">5</span><span class="Error"> </span><span class="Error"> </span><span class="Error"> </span><span class="Error"> </span><span class="ResWord">break</span></span><br> <span class="line"><span class="LineNumber">6</span><span class="ID">done</span></span><br> <span class="line"><span class="LineNumber">7</span><span class="ID">echo</span> <span class="String">"You have selected $var"</span></span></address>
| | echo "What is your favourite OS?" |
| </div>
| | select var in "Linux" "Gnu Hurd" "Free BSD" "Other"; do |
| <address> </address>
| | break |
| | done |
| | echo "You have selected $var" |
|
| |
|
| 该脚本的运行结果如下: | | 该脚本的运行结果如下: |
|
| |
|
| <address>What is your favourite OS?<br> 1) Linux<br> 2) Gnu Hurd<br> 3) Free BSD<br> 4) Other<br>
| | What is your favourite OS? |
| | | 1) Linux |
| # ? 1<br> | | 2) Gnu Hurd |
| | 3) Free BSD |
| | 4) Other |
| | #? 1 |
| | You have selected Linux |
|
| |
|
| You have selected Linux</address> <address> </address>
| | === while/for 循环=== |
| | |
|
| |
| | |
| === 3.5. while/for 循环 === | |
| | |
|
| |
| | |
| ----
| |
| | |
|
| |
|
| |
|
| 在shell中,可以使用如下循环: | | 在shell中,可以使用如下循环: |
| <div lang="en" class="codearea" dir="ltr"><script type="text/javascript">
| |
| document.write('<a href="#" onclick="return togglenumber(\'CA-c0248677e3766e700161c1cefa1b61f2c2c1c26f_006\', 1, 1);" \
| |
|
| |
| class="codenumbers">Toggle line numbers<\/a>');
| |
|
| |
| </script><a class="codenumbers" onclick="return togglenumber('CA-c0248677e3766e700161c1cefa1b61f2c2c1c26f_006', 1, 1);" href="http://127.0.0.1:8000/Shell%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80#">Toggle line numbers</a>
| |
| <pre lang="en" dir="ltr" id="CA-c0248677e3766e700161c1cefa1b61f2c2c1c26f_006"><span class="line"><span class="LineNumber"> 1 </span><span class="ResWord">while</span> <span class="Operator">.</span><span class="Operator">.</span><span class="Operator">.</span><span class="Operator">;</span> <span class="ID">do</span></span><br /><span class="line"><span class="LineNumber"> 2 </span> <span class="Operator">.</span><span class="Operator">.</span><span class="Operator">.</span><span class="Operator">.</span></span><br /><span class="line"><span class="LineNumber"> 3 </span><span class="ID">done</span></span></pre></div>
| |
|
| |
|
| |
|
| 只要测试表达式条件为真,则while循环将一直运行。关键字"break"用来跳出循环,而关键字”continue”则可以跳过一个循环的馀下部分,直接跳到下一次循环中。
| | while ...; do |
| | .... |
| | done |
|
| |
|
| for循环会查看一个字符串行表(字符串用空格分隔),并将其赋给一个变量:
| | 只要测试表达式条件为真,则while循环将一直运行。关键字"break"用来跳出循环,而关键字”continue”则可以跳过一个循环的余下部分,直接跳到下一次循环中。 |
| <div lang="en" class="codearea" dir="ltr"><script type="text/javascript">
| |
| document.write('<a href="#" onclick="return togglenumber(\'CA-f7ff0cc0d595ae94a0160140e3cb2fd752455c11_007\', 1, 1);" \
| |
|
| |
|
| class="codenumbers">Toggle line numbers<\/a>');
| | for循环会查看一个字符串列表(字符串用空格分隔),并将其赋给一个变量: |
|
| |
|
| </script><a class="codenumbers" onclick="return togglenumber('CA-f7ff0cc0d595ae94a0160140e3cb2fd752455c11_007', 1, 1);" href="http://127.0.0.1:8000/Shell%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80#">Toggle line numbers</a>
| | for var in ....; do |
| <pre lang="en" dir="ltr" id="CA-f7ff0cc0d595ae94a0160140e3cb2fd752455c11_007"><span class="line"><span class="LineNumber"> 1 </span><span class="ResWord">for</span> <span class="ID">var</span> <span class="ResWord">in</span> <span class="Operator">.</span><span class="Operator">.</span><span class="Operator">.</span><span class="Operator">.</span><span class="Operator">;</span> <span class="ID">do</span></span><br /><span class="line"><span class="LineNumber"> 2 </span> <span class="Operator">.</span><span class="Operator">.</span><span class="Operator">.</span><span class="Operator">.</span></span><br /><span class="line"><span class="LineNumber"> 3 </span><span class="ID">done</span></span></pre></div>
| | .... |
|
| | done |
|
| |
|
| 下面的示例会把A B C分别打印到屏幕上: | | 下面的示例会把A B C分别打印到屏幕上: |
| <div lang="en" class="codearea" dir="ltr"><script type="text/javascript">
| |
| document.write('<a href="#" onclick="return togglenumber(\'CA-1cb1f1e6097b29798c83492d0561c51dcaedc677_008\', 1, 1);" \
| |
|
| |
|
| class="codenumbers">Toggle line numbers<\/a>'); | | #!/bin/sh |
| | | |
| </script><a class="codenumbers" onclick="return togglenumber('CA-1cb1f1e6097b29798c83492d0561c51dcaedc677_008', 1, 1);" href="http://127.0.0.1:8000/Shell%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80#">Toggle line numbers</a>
| | for var in A B C ; do |
| <pre lang="en" dir="ltr" id="CA-1cb1f1e6097b29798c83492d0561c51dcaedc677_008"><span class="line"><span class="LineNumber"> 1 </span><span class="Comment">#!/bin/sh</span></span><br /><span class="line"><span class="LineNumber"> 2 </span></span><br /><span class="line"><span class="LineNumber"> 3 </span><span class="ResWord">for</span> <span class="ID">var</span> <span class="ResWord">in</span> <span class="ID">A</span> <span class="ID">B</span> <span class="ID">C</span> <span class="Operator">;</span> <span class="ID">do</span></span><br /><span class="line"><span class="LineNumber"> 4 </span> <span class="ID">echo</span> <span class="String">"var is $var"</span></span><br /><span class="line"><span class="LineNumber"> 5 </span><span class="ID">done</span></span></pre></div>
| | echo "var is $var" |
|
| | done |
|
| |
|
| 下面是一个实用的脚本showrpm,其功能是打印一些RPM包的统计信息: | | 下面是一个实用的脚本showrpm,其功能是打印一些RPM包的统计信息: |
| <div lang="en" class="codearea" dir="ltr"><script type="text/javascript">
| |
| document.write('<a href="#" onclick="return togglenumber(\'CA-3dba5c48c0c1bb55da514604393db8e315aa812f_009\', 1, 1);" \
| |
|
| |
|
| class="codenumbers">Toggle line numbers<\/a>'); | | #!/bin/sh |
| | | |
| </script><a class="codenumbers" onclick="return togglenumber('CA-3dba5c48c0c1bb55da514604393db8e315aa812f_009', 1, 1);" href="http://127.0.0.1:8000/Shell%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80#">Toggle line numbers</a>
| | # list a content summary of a number of RPM packages |
| <pre lang="en" dir="ltr" id="CA-3dba5c48c0c1bb55da514604393db8e315aa812f_009"><span class="line"><span class="LineNumber"> 1 </span><span class="Comment">#!/bin/sh</span></span><br /><span class="line"><span class="LineNumber"> 2 </span></span><br /><span class="line"><span class="LineNumber"> 3 </span><span class="Comment"># list a content summary of a number of RPM packages</span></span><br /><span class="line"><span class="LineNumber"> 4 </span><span class="Comment"># USAGE: showrpm rpmfile1 rpmfile2 ...</span></span><br /><span class="line"><span class="LineNumber"> 5 </span><span class="Comment"># EXAMPLE: showrpm /cdrom/RedHat/RPMS/*.rpm</span></span><br /><span class="line"><span class="LineNumber"> 6 </span><span class="ResWord">for</span> <span class="ID">rpmpackage</span> <span class="ResWord">in</span><span class="Error"> </span><span class="Error">$</span><span class="Operator">*</span><span class="Operator">;</span> <span class="ID">do</span></span><br /><span class="line"><span class="LineNumber"> 7 </span> <span class="ResWord">if</span> <span class="Operator">[</span> <span class="Operator">-</span><span class="ID">r</span> <span class="String">"$rpmpackage"</span> <span class="Operator">]</span><span class="Operator">;</span><span class="ID">then</span></span><br /><span class="line"><span class="LineNumber"> 8 </span> <span class="ID">echo</span> <span class="String">"=============== $rpmpackage =============="</span></span><br /><span class="line"><span class="LineNumber"> 9 </span> <span class="ID">rpm</span> <span class="Operator">-</span><span class="ID">qi</span> <span class="Operator">-</span><span class="ID">p</span><span class="Error"> </span><span class="Error">$</span><span class="ID">rpmpackage</span></span><br /><span class="line"><span class="LineNumber"> 10 </span> <span class="ResWord">else</span></span><br /><span class="line"><span class="LineNumber"> 11 </span> <span class="ID">echo</span> <span class="String">"ERROR: cannot read file $rpmpackage"</span></span><br /><span class="line"><span class="LineNumber"> 12 </span> <span class="ID">fi</span></span><br /><span class="line"><span class="LineNumber"> 13 </span><span class="ID">done</span></span></pre></div>
| | # USAGE: showrpm rpmfile1 rpmfile2 ... |
|
| | # EXAMPLE: showrpm /cdrom/RedHat/RPMS/*.rpm |
| | | for rpmpackage in $*; do |
| 这 里出现了第二个特殊变量$*,该变量包含有输入的所有命令行参数值。如果你运行showrpm openssh.rpm w3m.rpm webgrep.rpm,那幺 $* 就包含有 3 个字符串,即openssh.rpm, w3m.rpm和 webgrep.rpm。
| | if [ -r "$rpmpackage" ];then |
| | | echo "=============== $rpmpackage ==============" |
|
| | rpm -qi -p $rpmpackage |
| | | else |
| == 4. Shell里的一些特殊符号 ==
| | echo "ERROR: cannot read file $rpmpackage" |
| | | fi |
|
| | done |
| | |
| ----
| |
| | |
|
| |
|
| |
|
|
| | 这里出现了第二个特殊变量$*,该变量包含有输入的所有命令行参数值。如果你运行showrpm openssh.rpm w3m.rpm webgrep.rpm,那么 $* 就包含有 3 个字符串,即openssh.rpm, w3m.rpm和 webgrep.rpm。 |
|
| |
|
| === 4.1. 引号 === | | == Shell里的一些特殊符号== |
|
| |
|
|
| | === 引号=== |
| | |
| ----
| |
| | |
|
| |
|
| |
|
| 在向程序传递任何参数之前,程序会扩展通配符和变量。这里所谓的扩展是指程序会把通配符(比如*)替换成适当的文件名,把变量替换成变量值。我们可以使用引号来防止这种扩展,先来看一个例子,假设在当前目录下有两个jpg文件:mail.jpg和tux.jpg。 | | 在向程序传递任何参数之前,程序会扩展通配符和变量。这里所谓的扩展是指程序会把通配符(比如*)替换成适当的文件名,把变量替换成变量值。我们可以使用引号来防止这种扩展,先来看一个例子,假设在当前目录下有两个jpg文件:mail.jpg和tux.jpg。 |
| <div lang="en" class="codearea" dir="ltr"><script type="text/javascript">
| |
| document.write('<a href="#" onclick="return togglenumber(\'CA-cca50ec62fd5a61b6ff64c3060efdd8a04b56607_010\', 1, 1);" \
| |
|
| |
|
| class="codenumbers">Toggle line numbers<\/a>'); | | #!/bin/sh |
| | |
| | echo *.jpg |
|
| |
|
| </script><a class="codenumbers" onclick="return togglenumber('CA-cca50ec62fd5a61b6ff64c3060efdd8a04b56607_010', 1, 1);" href="http://127.0.0.1:8000/Shell%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80#">Toggle line numbers</a>
| | 运行结果为: |
| <pre lang="en" dir="ltr" id="CA-cca50ec62fd5a61b6ff64c3060efdd8a04b56607_010"><span class="line"><span class="LineNumber"> 1 </span><span class="Comment">#!/bin/sh</span></span><br /><span class="line"><span class="LineNumber"> 2 </span></span><br /><span class="line"><span class="LineNumber"> 3 </span><span class="ID">echo</span> <span class="Operator">*</span><span class="Operator">.</span><span class="ID">jpg</span></span></pre></div>
| |
|
| |
|
| |
|
| 运行结果为:
| | mail.jpg tux.jpg |
| <pre>mail.jpg tux.jpg<br /></pre>
| |
|
| |
|
| |
|
| 引号(单引号和双引号)可以防止通配符*的扩展: | | 引号(单引号和双引号)可以防止通配符*的扩展: |
| <div lang="en" class="codearea" dir="ltr"><script type="text/javascript">
| |
| document.write('<a href="#" onclick="return togglenumber(\'CA-861e22b4d7d455ed8c88718e1d1c88def6b92a45_011\', 1, 1);" \
| |
|
| |
|
| class="codenumbers">Toggle line numbers<\/a>'); | | #!/bin/sh |
| | |
| | echo "*.jpg" |
| | echo '*.jpg' |
|
| |
|
| </script><a class="codenumbers" onclick="return togglenumber('CA-861e22b4d7d455ed8c88718e1d1c88def6b92a45_011', 1, 1);" href="http://127.0.0.1:8000/Shell%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80#">Toggle line numbers</a>
| | 其运行结果为: |
| <pre lang="en" dir="ltr" id="CA-861e22b4d7d455ed8c88718e1d1c88def6b92a45_011"><span class="line"><span class="LineNumber"> 1 </span><span class="Comment">#!/bin/sh</span></span><br /><span class="line"><span class="LineNumber"> 2 </span></span><br /><span class="line"><span class="LineNumber"> 3 </span><span class="ID">echo</span> <span class="String">"*.jpg"</span></span><br /><span class="line"><span class="LineNumber"> 4 </span><span class="ID">echo</span> <span class="String">'*.jpg'</span></span></pre></div>
| |
|
| |
|
| |
|
| 其运行结果为:
| | *.jpg |
| <pre>*.jpg<br /> *.jpg<br /></pre>
| | *.jpg |
|
| |
|
| |
|
| 其中单引号更严格一些,它可以防止任何变量扩展;而双引号可以防止通配符扩展但允许变量扩展: | | 其中单引号更严格一些,它可以防止任何变量扩展;而双引号可以防止通配符扩展但允许变量扩展: |
| <div lang="en" class="codearea" dir="ltr"><script type="text/javascript">
| |
| document.write('<a href="#" onclick="return togglenumber(\'CA-d1585cc917e2f453edf18f3e887231b88ada9708_012\', 1, 1);" \
| |
|
| |
|
| class="codenumbers">Toggle line numbers<\/a>'); | | #!/bin/sh |
| | | |
| </script><a class="codenumbers" onclick="return togglenumber('CA-d1585cc917e2f453edf18f3e887231b88ada9708_012', 1, 1);" href="http://127.0.0.1:8000/Shell%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80#">Toggle line numbers</a>
| | echo $SHELL |
| <pre lang="en" dir="ltr" id="CA-d1585cc917e2f453edf18f3e887231b88ada9708_012"><span class="line"><span class="LineNumber"> 1 </span><span class="Comment">#!/bin/sh</span></span><br /><span class="line"><span class="LineNumber"> 2 </span></span><br /><span class="line"><span class="LineNumber"> 3 </span><span class="ID">echo</span><span class="Error"> </span><span class="Error">$</span><span class="ID">SHELL</span></span><br /><span class="line"><span class="LineNumber"> 4 </span><span class="ID">echo</span> <span class="String">"$SHELL"</span></span><br /><span class="line"><span class="LineNumber"> 5 </span><span class="ID">echo</span> <span class="String">'$SHELL'</span></span></pre></div>
| | echo "$SHELL" |
|
| | echo '$SHELL' |
|
| |
|
| 运行结果为: | | 运行结果为: |
| <div lang="en" class="codearea" dir="ltr"><script type="text/javascript">
| |
| document.write('<a href="#" onclick="return togglenumber(\'CA-45b48036e40d65c70df271f2ea697532de3a4ba6_013\', 1, 1);" \
| |
|
| |
|
| class="codenumbers">Toggle line numbers<\/a>'); | | /bin/bash |
| | /bin/bash |
| | $SHELL |
|
| |
|
| </script><a class="codenumbers" onclick="return togglenumber('CA-45b48036e40d65c70df271f2ea697532de3a4ba6_013', 1, 1);" href="http://127.0.0.1:8000/Shell%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80#">Toggle line numbers</a>
| | 此外还有一种防止这种扩展的方法,即使用转义字符——反斜杆: |
| <pre lang="en" dir="ltr" id="CA-45b48036e40d65c70df271f2ea697532de3a4ba6_013"><span class="line"><span class="LineNumber"> 1 </span><span class="Operator">/</span><span class="ID">bin</span><span class="Operator">/</span><span class="ID">bash</span></span><br /><span class="line"><span class="LineNumber"> 2 </span><span class="Operator">/</span><span class="ID">bin</span><span class="Operator">/</span><span class="ID">bash</span></span><br /><span class="line"><span class="LineNumber"> 3 </span><span class="Error">$</span><span class="ID">SHELL</span></span></pre></div>
| |
|
| |
|
| |
|
| 此外还有一种防止这种扩展的方法,即使用转义字符——反斜杆:
| | echo *.jpg |
| <pre>echo *.jpg<br /> echo $SHELL<br /></pre>
| | echo $SHELL |
|
| |
|
| |
|
| 输出结果为: | | 输出结果为: |
| <pre>*.jpg<br /> $SHELL<br /></pre>
| |
|
| |
|
| |
|
|
| | *.jpg |
| | $SHELL |
|
| |
|
| === 4.2. Here documents === | | === Here documents=== |
|
| |
|
|
| | 当要将几行文字传递给一个命令时,here documents一种不错的方法。对每个脚本写一段帮助性的文字是很有用的,此时如果使用here documents就不必用echo函数一行行输出。Here document以 << 开头,后面接上一个字符串,这个字符串还必须出现在here document的末尾。下面是一个例子,在该例子中,我们对多个文件进行重命名,并且使用here documents打印帮助: |
|
| |
|
| 当 要将几行文字传递给一个命令时,here documents一种不错的方法。对每个脚本写一段帮助性的文字是很有用的,此时如果使用here documents就不必用echo函数一行行输出。Here document以 << 开头,後面接上一个字符串,这个字符串还必须出现在here document的末尾。下面是一个例子,在该例子中,我们对多个文件进行重命名,并且使用here documents打印帮助:
| | #!/bin/sh |
| <div lang="en" class="codearea" dir="ltr"><script type="text/javascript"> | | |
| document.write('<a href="#" onclick="return togglenumber(\'CA-cb6508d380a72da28fa9a5b846a25d55eea1e838_014\', 1, 1);" \
| | # we have less than 3 arguments. Print the help text: |
| | if [ $# -lt 3 ] ; then |
| | cat < ren -- renames a number of files using sed regular expressions |
| | |
| | USAGE: ren 'regexp' 'replacement' files... |
| | |
| | EXAMPLE: rename all *.HTM files in *.html: |
| | ren 'HTM$' 'html' *.HTM |
| | |
| | HELP |
| | exit 0 |
| | fi |
| | |
| | OLD="$1" |
| | NEW="$2" |
| | # The shift command removes one argument from the list of |
| | # command line arguments. |
| | shift |
| | shift |
| | # $* contains now all the files: |
| | for file in $*; do |
| | if [ -f "$file" ] ; then |
| | newfile=`echo "$file" | sed "s/${OLD}/${NEW}/g"` |
| | if [ -f "$newfile" ]; then |
| | echo "ERROR: $newfile exists already" |
| | else |
| | echo "renaming $file to $newfile ..." |
| | mv "$file" "$newfile" |
| | fi |
| | fi |
| | done |
|
| |
|
| class="codenumbers">Toggle line numbers<\/a>');
| | 这个示例有点复杂,我们需要多花点时间来说明一番。第一个if表达式判断输入命令行参数是否小于3个 (特殊变量$# 表示包含参数的个数) 。如果输入参数小于3个,则将帮助文字传递给cat命令,然后由cat命令将其打印在屏幕上。打印帮助文字后程序退出。如果输入参数等于或大于3个,我们就将第一个参数赋值给变量OLD,第二个参数赋值给变量NEW。下一步,我们使用shift命令将第一个和第二个参数从参数列表中删除,这样原来的第三个参数就成为参数列表$*的第一个参数。然后我们开始循环,命令行参数列表被一个接一个地被赋值给变量$file。接着我们判断该文件是否存在,如果存在则通过sed命令搜索和替换来产生新的文件名。然后将反短斜线内命令结果赋值给newfile。这样我们就达到了目的:得到了旧文件名和新文件名。然后使用 mv命令进行重命名。 |
|
| |
|
| </script><a class="codenumbers" onclick="return togglenumber('CA-cb6508d380a72da28fa9a5b846a25d55eea1e838_014', 1, 1);" href="http://127.0.0.1:8000/Shell%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80#">Toggle line numbers</a>
| | == Shell里的函数== |
| <pre lang="en" dir="ltr" id="CA-cb6508d380a72da28fa9a5b846a25d55eea1e838_014"><span class="line"><span class="LineNumber"> 1 </span><span class="Comment">#!/bin/sh</span></span><br /><span class="line"><span class="LineNumber"> 2 </span></span><br /><span class="line"><span class="LineNumber"> 3 </span><span class="Comment"># we have less than 3 arguments. Print the help text:</span></span><br /><span class="line"><span class="LineNumber"> 4 </span><span class="ResWord">if</span> <span class="Operator">[</span><span class="Error"> </span><span class="Error">$</span><span class="Comment"># -lt 3 ] ; then</span></span><br /><span class="line"><span class="LineNumber"> 5 </span><span class="ID">cat</span> <span class="Operator"><</span> <span class="ID">ren</span> <span class="Operator">-</span><span class="Operator">-</span> <span class="ID">renames</span> <span class="ID">a</span> <span class="ID">number</span> <span class="ID">of</span> <span class="ID">files</span> <span class="ID">using</span> <span class="ID">sed</span> <span class="ID">regular</span> <span class="ID">expressions</span></span><br /><span class="line"><span class="LineNumber"> 6 </span></span><br /><span class="line"><span class="LineNumber"> 7 </span><span class="ID">USAGE</span><span class="Operator">:</span> <span class="ID">ren</span> <span class="String">'regexp'</span> <span class="String">'replacement'</span> <span class="ID">files</span><span class="Operator">.</span><span class="Operator">.</span><span class="Operator">.</span></span><br /><span class="line"><span class="LineNumber"> 8 </span></span><br /><span class="line"><span class="LineNumber"> 9 </span><span class="ID">EXAMPLE</span><span class="Operator">:</span> <span class="ID">rename</span> <span class="ID">all</span> <span class="Operator">*</span><span class="Operator">.</span><span class="ID">HTM</span> <span class="ID">files</span> <span class="ResWord">in</span> <span class="Operator">*</span><span class="Operator">.</span><span class="ID">html</span><span class="Operator">:</span></span><br /><span class="line"><span class="LineNumber"> 10 </span> <span class="ID">ren</span> <span class="String">'HTM$'</span> <span class="String">'html'</span> <span class="Operator">*</span><span class="Operator">.</span><span class="ID">HTM</span></span><br /><span class="line"><span class="LineNumber"> 11 </span></span><br /><span class="line"><span class="LineNumber"> 12 </span><span class="ID">HELP</span></span><br /><span class="line"><span class="LineNumber"> 13 </span> <span class="ID">exit</span> <span class="Number">0</span></span><br /><span class="line"><span class="LineNumber"> 14 </span><span class="ID">fi</span></span><br /><span class="line"><span class="LineNumber"> 15 </span></span><br /><span class="line"><span class="LineNumber"> 16 </span><span class="ID">OLD</span><span class="Operator">=</span><span class="String">"$1"</span></span><br /><span class="line"><span class="LineNumber"> 17 </span><span class="ID">NEW</span><span class="Operator">=</span><span class="String">"$2"</span></span><br /><span class="line"><span class="LineNumber"> 18 </span><span class="Comment"># The shift command removes one argument from the list of</span></span><br /><span class="line"><span class="LineNumber"> 19 </span><span class="Comment"># command line arguments.</span></span><br /><span class="line"><span class="LineNumber"> 20 </span><span class="ID">shift</span></span><br /><span class="line"><span class="LineNumber"> 21 </span><span class="ID">shift</span></span><br /><span class="line"><span class="LineNumber"> 22 </span><span class="Comment"># $* contains now all the files:</span></span><br /><span class="line"><span class="LineNumber"> 23 </span><span class="ResWord">for</span> <span class="ID">file</span> <span class="ResWord">in</span><span class="Error"> </span><span class="Error">$</span><span class="Operator">*</span><span class="Operator">;</span> <span class="ID">do</span></span><br /><span class="line"><span class="LineNumber"> 24 </span> <span class="ResWord">if</span> <span class="Operator">[</span> <span class="Operator">-</span><span class="ID">f</span> <span class="String">"$file"</span> <span class="Operator">]</span> <span class="Operator">;</span> <span class="ID">then</span></span><br /><span class="line"><span class="LineNumber"> 25 </span> <span class="ID">newfile</span><span class="Operator">=</span><span class="Operator">`</span><span class="ID">echo</span> <span class="String">"$file"</span> <span class="Operator">|</span> <span class="ID">sed</span> <span class="String">"s/${OLD}/${NEW}/g"</span><span class="Operator">`</span></span><br /><span class="line"><span class="LineNumber"> 26 </span> <span class="ResWord">if</span> <span class="Operator">[</span> <span class="Operator">-</span><span class="ID">f</span> <span class="String">"$newfile"</span> <span class="Operator">]</span><span class="Operator">;</span> <span class="ID">then</span></span><br /><span class="line"><span class="LineNumber"> 27 </span><span class="Error"> </span><span class="Error"> </span><span class="Error"> </span><span class="Error"> </span> <span class="ID">echo</span> <span class="String">"ERROR: $newfile exists already"</span></span><br /><span class="line"><span class="LineNumber"> 28 </span> <span class="ResWord">else</span></span><br /><span class="line"><span class="LineNumber"> 29 </span> <span class="ID">echo</span> <span class="String">"renaming $file to $newfile ..."</span></span><br /><span class="line"><span class="LineNumber"> 30 </span> <span class="ID">mv</span> <span class="String">"$file"</span> <span class="String">"$newfile"</span></span><br /><span class="line"><span class="LineNumber"> 31 </span> <span class="ID">fi</span></span><br /><span class="line"><span class="LineNumber"> 32 </span> <span class="ID">fi</span></span><br /><span class="line"><span class="LineNumber"> 33 </span><span class="ID">done</span><br /><strong>ERROR: EOF in multi-line statement</strong><br /></span></pre></div>
| |
|
| |
| | |
| 这 个示例有点复杂,我们需要多花点时间来说明一番。第一个if表达式判断输入命令行参数是否小于3个 (特殊变量$# 表示包含参数的个数) 。如果输入参数小于3个,则将帮助文字传递给cat命令,然後由cat命令将其打印在屏幕上。打印帮助文字後程序退出。如果输入参数等于或大于3个,我们 就将第一个参数赋值给变量OLD,第二个参数赋值给变量NEW。下一步,我们使用shift命令将第一个和第二个参数从参数列表中删除,这样原来的第三个 参数就成为参数列表$*的第一个参数。然後我们开始循环,命令行参数列表被一个接一个地被赋值给变量$file。接着我们判断该文件是否存在,如果存在则 通过sed命令搜索和替换来产生新的文件名。然後将反短斜线内命令结果赋值给newfile。这样我们就达到了目的:得到了旧文件名和新文件名。然後使用 mv命令进行重命名。
| |
| | |
|
| |
| | |
| == 5. Shell里的函数 ==
| |
| | |
|
| |
|
| |
|
| 如果你写过比较复杂的脚本,就会发现可能在几个地方使用了相同的代码,这时如果用上函数,会方便很多。函数的大致样子如下: | | 如果你写过比较复杂的脚本,就会发现可能在几个地方使用了相同的代码,这时如果用上函数,会方便很多。函数的大致样子如下: |
| <div lang="en" class="codearea" dir="ltr"><script type="text/javascript">
| |
| document.write('<a href="#" onclick="return togglenumber(\'CA-8321b263dc991021d79d7ce9ed777c5992cc3b17_015\', 1, 1);" \
| |
|
| |
|
| class="codenumbers">Toggle line numbers<\/a>'); | | functionname() |
| | | { |
| </script><a class="codenumbers" onclick="return togglenumber('CA-8321b263dc991021d79d7ce9ed777c5992cc3b17_015', 1, 1);" href="http://127.0.0.1:8000/Shell%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80#">Toggle line numbers</a>
| | # inside the body $1 is the first argument given to the function |
| <pre lang="en" dir="ltr" id="CA-8321b263dc991021d79d7ce9ed777c5992cc3b17_015"><span class="line"><span class="LineNumber"> 1 </span><span class="ID">functionname</span><span class="Operator">(</span><span class="Operator">)</span></span><br /><span class="line"><span class="LineNumber"> 2 </span><span class="Operator">{</span></span><br /><span class="line"><span class="LineNumber"> 3 </span><span class="Comment"># inside the body $1 is the first argument given to the function</span></span><br /><span class="line"><span class="LineNumber"> 4 </span><span class="Comment"># $2 the second ...</span></span><br /><span class="line"><span class="LineNumber"> 5 </span><span class="ID">body</span></span><br /><span class="line"><span class="LineNumber"> 6 </span><span class="Operator">}</span></span></pre></div>
| | # $2 the second ... |
|
| | body |
| | } |
|
| |
|
| 你需要在每个脚本的开始对函数进行声明。 | | 你需要在每个脚本的开始对函数进行声明。 |
|
| |
|
| 下面是一个名为xtitlebar的脚本,它可以改变终端窗口的名称。这里使用了一个名为help的函数,该函数在脚本中使用了两次: | | 下面是一个名为xtitlebar的脚本,它可以改变终端窗口的名称。这里使用了一个名为help的函数,该函数在脚本中使用了两次: |
| <div lang="en" class="codearea" dir="ltr"><script type="text/javascript">
| |
| document.write('<a href="#" onclick="return togglenumber(\'CA-44e64264e26782b13781561b1645e84a2a64125b_016\', 1, 1);" \
| |
|
| |
|
| class="codenumbers">Toggle line numbers<\/a>'); | | #!/bin/sh |
| | | # vim: set sw=4 ts=4 et: |
| </script><a class="codenumbers" onclick="return togglenumber('CA-44e64264e26782b13781561b1645e84a2a64125b_016', 1, 1);" href="http://127.0.0.1:8000/Shell%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80#">Toggle line numbers</a>
| | |
| <pre lang="en" dir="ltr" id="CA-44e64264e26782b13781561b1645e84a2a64125b_016"><span class="line"><span class="LineNumber"> 1 </span><span class="Comment">#!/bin/sh</span></span><br /><span class="line"><span class="LineNumber"> 2 </span><span class="Comment"># vim: set sw=4 ts=4 et:</span></span><br /><span class="line"><span class="LineNumber"> 3 </span></span><br /><span class="line"><span class="LineNumber"> 4 </span><span class="ID">help</span><span class="Operator">(</span><span class="Operator">)</span></span><br /><span class="line"><span class="LineNumber"> 5 </span><span class="Operator">{</span></span><br /><span class="line"><span class="LineNumber"> 6 </span> <span class="ID">cat</span> <span class="Operator"><</span> <span class="ID">xtitlebar</span> <span class="Operator">-</span><span class="Operator">-</span> <span class="ID">change</span> <span class="ID">the</span> <span class="ID">name</span> <span class="ID">of</span> <span class="ID">an</span> <span class="ID">xterm</span><span class="Operator">,</span> <span class="ID">gnome</span><span class="Operator">-</span><span class="ID">terminal</span> <span class="ResWord">or</span> <span class="ID">kde</span> <span class="ID">konsole</span></span><br /><span class="line"><span class="LineNumber"> 7 </span></span><br /><span class="line"><span class="LineNumber"> 8 </span><span class="ID">USAGE</span><span class="Operator">:</span> <span class="ID">xtitlebar</span> <span class="Operator">[</span><span class="Operator">-</span><span class="ID">h</span><span class="Operator">]</span> <span class="String">"string_for_titelbar"</span></span><br /><span class="line"><span class="LineNumber"> 9 </span></span><br /><span class="line"><span class="LineNumber"> 10 </span><span class="ID">OPTIONS</span><span class="Operator">:</span> <span class="Operator">-</span><span class="ID">h</span> <span class="ID">help</span> <span class="ID">text</span></span><br /><span class="line"><span class="LineNumber"> 11 </span></span><br /><span class="line"><span class="LineNumber"> 12 </span><span class="ID">EXAMPLE</span><span class="Operator">:</span> <span class="ID">xtitlebar</span> <span class="String">"cvs"</span></span><br /><span class="line"><span class="LineNumber"> 13 </span></span><br /><span class="line"><span class="LineNumber"> 14 </span><span class="ID">HELP</span></span><br /><span class="line"><span class="LineNumber"> 15 </span> <span class="ID">exit</span> <span class="Number">0</span></span><br /><span class="line"><span class="LineNumber"> 16 </span><span class="Operator">}</span></span><br /><span class="line"><span class="LineNumber"> 17 </span></span><br /><span class="line"><span class="LineNumber"> 18 </span><span class="Comment"># in case of error or if -h is given we call the function help:</span></span><br /><span class="line"><span class="LineNumber"> 19 </span><span class="Operator">[</span> <span class="Operator">-</span><span class="ID">z</span> <span class="String">"$1"</span> <span class="Operator">]</span> <span class="Operator">&</span><span class="Operator">&</span> <span class="ID">help</span></span><br /><span class="line"><span class="LineNumber"> 20 </span><span class="Operator">[</span> <span class="String">"$1"</span> <span class="Operator">=</span> <span class="String">"-h"</span> <span class="Operator">]</span> <span class="Operator">&</span><span class="Operator">&</span> <span class="ID">help</span></span><br /><span class="line"><span class="LineNumber"> 21 </span></span><br /><span class="line"><span class="LineNumber"> 22 </span><span class="Comment"># send the escape sequence to change the xterm titelbar:</span></span><br /><span class="line"><span class="LineNumber"> 23 </span><span class="ID">echo</span> <span class="Operator">-</span><span class="ID">e</span> <span class="String">"33]0;$107"</span></span><br /><span class="line"><span class="LineNumber"> 24 </span><span class="Comment">#</span></span></pre></div>
| | help() |
|
| | { |
| | cat < xtitlebar -- change the name of an xterm, gnome-terminal or kde konsole |
| | |
| | USAGE: xtitlebar [-h] "string_for_titelbar" |
| | |
| | OPTIONS: -h help text |
| | |
| | EXAMPLE: xtitlebar "cvs" |
| | |
| | HELP |
| | exit 0 |
| | } |
| | |
| | # in case of error or if -h is given we call the function help: |
| | [ -z "$1" ] && help |
| | [ "$1" = "-h" ] && help |
| | |
| | # send the escape sequence to change the xterm titelbar: |
| | echo -e "33]0;$107" |
| | # |
|
| |
|
| 在脚本中提供帮助是一种很好的编程习惯,可以方便其他用户(和自己)使用和理解脚本。 | | 在脚本中提供帮助是一种很好的编程习惯,可以方便其他用户(和自己)使用和理解脚本。 |
| | == 命令行参数== |
|
| |
|
|
| | 我们已经见过$* 和 $1, $2 ... $9 等特殊变量,这些特殊变量包含了用户从命令行输入的参数。迄今为止,我们仅仅了解了一些简单的命令行语法(比如一些强制性的参数和查看帮助的-h选项)。但是在编写更复杂的程序时,您可能会发现您需要更多的自定义的选项。通常的惯例是在所有可选的参数之前加一个减号,后面再加上参数值 (比如文件名)。 |
| | |
| == 6. 命令行参数 ==
| |
| | |
|
| |
| | |
| 我 们已经见过$* 和 $1, $2 ... $9 等特殊变量,这些特殊变量包含了用户从命令行输入的参数。迄今为止,我们仅仅了解了一些简单的命令行语法(比如一些强制性的参数和查看帮助的-h选项)。 但是在编写更复杂的程序时,您可能会发现您需要更多的自定义的选项。通常的惯例是在所有可选的参数之前加一个减号,後面再加上参数值 (比如文件名)。
| |
|
| |
|
| 有好多方法可以实现对输入参数的分析,但是下面的使用case表达式的例子无疑是一个不错的方法。 | | 有好多方法可以实现对输入参数的分析,但是下面的使用case表达式的例子无疑是一个不错的方法。 |
| <div lang="en" class="codearea" dir="ltr"><script type="text/javascript">
| |
| document.write('<a href="#" onclick="return togglenumber(\'CA-b5a643119a63f5eea1744e170bb7cbd6d65b8df8_017\', 1, 1);" \
| |
|
| |
|
| class="codenumbers">Toggle line numbers<\/a>'); | | #!/bin/sh |
| | |
| | help() |
| | { |
| | cat < This is a generic command line parser demo. |
| | USAGE EXAMPLE: cmdparser -l hello -f -- -somefile1 somefile2 |
| | HELP |
| | exit 0 |
| | } |
| | |
| | while [ -n "$1" ]; do |
| | case $1 in |
| | -h) help;shift 1;; # function help is called |
| | -f) opt_f=1;shift 1;; # variable opt_f is set |
| | -l) opt_l=$2;shift 2;; # -l takes an argument -> shift by 2 |
| | --) shift;break;; # end of options |
| | -*) echo "error: no such option $1. -h for help";exit 1;; |
| | *) break;; |
| | esac |
| | done |
| | |
| | echo "opt_f is $opt_f" |
| | echo "opt_l is $opt_l" |
| | echo "first arg is $1" |
| | echo "2nd arg is $2" |
|
| |
|
| </script><a class="codenumbers" onclick="return togglenumber('CA-b5a643119a63f5eea1744e170bb7cbd6d65b8df8_017', 1, 1);" href="http://127.0.0.1:8000/Shell%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80#">Toggle line numbers</a>
| | 你可以这样运行该脚本: |
| <pre lang="en" dir="ltr" id="CA-b5a643119a63f5eea1744e170bb7cbd6d65b8df8_017"><span class="line"><span class="LineNumber"> 1 </span><span class="Comment">#!/bin/sh</span></span><br /><span class="line"><span class="LineNumber"> 2 </span></span><br /><span class="line"><span class="LineNumber"> 3 </span><span class="ID">help</span><span class="Operator">(</span><span class="Operator">)</span></span><br /><span class="line"><span class="LineNumber"> 4 </span><span class="Operator">{</span></span><br /><span class="line"><span class="LineNumber"> 5 </span> <span class="ID">cat</span> <span class="Operator"><</span> <span class="ID">This</span> <span class="ResWord">is</span> <span class="ID">a</span> <span class="ID">generic</span> <span class="ID">command</span> <span class="ID">line</span> <span class="ID">parser</span> <span class="ID">demo</span><span class="Operator">.</span></span><br /><span class="line"><span class="LineNumber"> 6 </span> <span class="ID">USAGE</span> <span class="ID">EXAMPLE</span><span class="Operator">:</span> <span class="ID">cmdparser</span> <span class="Operator">-</span><span class="ID">l</span> <span class="ID">hello</span> <span class="Operator">-</span><span class="ID">f</span> <span class="Operator">-</span><span class="Operator">-</span> <span class="Operator">-</span><span class="ID">somefile1</span> <span class="ID">somefile2</span></span><br /><span class="line"><span class="LineNumber"> 7 </span> <span class="ID">HELP</span></span><br /><span class="line"><span class="LineNumber"> 8 </span> <span class="ID">exit</span> <span class="Number">0</span></span><br /><span class="line"><span class="LineNumber"> 9 </span><span class="Operator">}</span></span><br /><span class="line"><span class="LineNumber"> 10 </span></span><br /><span class="line"><span class="LineNumber"> 11 </span><span class="ResWord">while</span> <span class="Operator">[</span> <span class="Operator">-</span><span class="ID">n</span> <span class="String">"$1"</span> <span class="Operator">]</span><span class="Operator">;</span> <span class="ID">do</span></span><br /><span class="line"><span class="LineNumber"> 12 </span><span class="ID">case</span><span class="Error"> </span><span class="Error">$</span><span class="Number">1</span> <span class="ResWord">in</span></span><br /><span class="line"><span class="LineNumber"> 13 </span> <span class="Operator">-</span><span class="ID">h</span><span class="Operator">)</span> <span class="ID">help</span><span class="Operator">;</span><span class="ID">shift</span> <span class="Number">1</span><span class="Operator">;</span><span class="Operator">;</span> <span class="Comment"># function help is called</span></span><br /><span class="line"><span class="LineNumber"> 14 </span> <span class="Operator">-</span><span class="ID">f</span><span class="Operator">)</span> <span class="ID">opt_f</span><span class="Operator">=</span><span class="Number">1</span><span class="Operator">;</span><span class="ID">shift</span> <span class="Number">1</span><span class="Operator">;</span><span class="Operator">;</span> <span class="Comment"># variable opt_f is set</span></span><br /><span class="line"><span class="LineNumber"> 15 </span> <span class="Operator">-</span><span class="ID">l</span><span class="Operator">)</span> <span class="ID">opt_l</span><span class="Operator">=</span><span class="Error">$</span><span class="Number">2</span><span class="Operator">;</span><span class="ID">shift</span> <span class="Number">2</span><span class="Operator">;</span><span class="Operator">;</span> <span class="Comment"># -l takes an argument -> shift by 2</span></span><br /><span class="line"><span class="LineNumber"> 16 </span> <span class="Operator">-</span><span class="Operator">-</span><span class="Operator">)</span> <span class="ID">shift</span><span class="Operator">;</span><span class="ResWord">break</span><span class="Operator">;</span><span class="Operator">;</span> <span class="Comment"># end of options</span></span><br /><span class="line"><span class="LineNumber"> 17 </span> <span class="Operator">-</span><span class="Operator">*</span><span class="Operator">)</span> <span class="ID">echo</span> <span class="String">"error: no such option $1. -h for help"</span><span class="Operator">;</span><span class="ID">exit</span> <span class="Number">1</span><span class="Operator">;</span><span class="Operator">;</span></span><br /><span class="line"><span class="LineNumber"> 18 </span> <span class="Operator">*</span><span class="Operator">)</span> <span class="ResWord">break</span><span class="Operator">;</span><span class="Operator">;</span></span><br /><span class="line"><span class="LineNumber"> 19 </span><span class="ID">esac</span></span><br /><span class="line"><span class="LineNumber"> 20 </span><span class="ID">done</span></span><br /><span class="line"><span class="LineNumber"> 21 </span></span><br /><span class="line"><span class="LineNumber"> 22 </span><span class="ID">echo</span> <span class="String">"opt_f is $opt_f"</span></span><br /><span class="line"><span class="LineNumber"> 23 </span><span class="ID">echo</span> <span class="String">"opt_l is $opt_l"</span></span><br /><span class="line"><span class="LineNumber"> 24 </span><span class="ID">echo</span> <span class="String">"first arg is $1"</span></span><br /><span class="line"><span class="LineNumber"> 25 </span><span class="ID">echo</span> <span class="String">"2nd arg is $2"</span><br /><strong>ERROR: EOF in multi-line statement</strong><br /></span></pre></div>
| |
|
| |
|
| |
|
| 你可以这样运行该脚本:
| | cmdparser -l hello -f -- -somefile1 somefile2 |
| <pre>cmdparser -l hello -f -- -somefile1 somefile2<br /></pre>
| |
|
| |
|
| |
|
| 返回结果如下: | | 返回结果如下: |
| <pre>opt_f is 1<br /> opt_l is hello<br /> first arg is -somefile1<br /> 2nd arg is somefile2<br /></pre>
| | |
|
| | opt_f is 1 |
| | opt_l is hello |
| | first arg is -somefile1 |
| | 2nd arg is somefile2 |
|
| |
|
| 这个脚本是如何工作的呢?脚本首先在所有输入命令行参数中进行循环,将输入参数与case表达式进行比较,如果匹配则设置一个变量并且移除该参数。根据unix系统的惯例,首先输入的应该是包含减号的参数。 | | 这个脚本是如何工作的呢?脚本首先在所有输入命令行参数中进行循环,将输入参数与case表达式进行比较,如果匹配则设置一个变量并且移除该参数。根据unix系统的惯例,首先输入的应该是包含减号的参数。 |
| | == Shell脚本示例== |
|
| |
|
|
| | === 一般编程步骤=== |
|
| |
|
| == 7. Shell脚本示例 ==
| | 现在我们来讨论编写一个脚本的一般步骤。任何优秀的脚本都应该具有帮助和输入参数。写一个框架脚本(framework.sh),该脚本包含了大多数脚本需要的框架结构,是一个非常不错的主意。这样一来,当我们开始编写新脚本时,可以先执行如下命令: |
| | |
|
| |
| | |
| ----
| |
| | |
|
| |
|
| |
|
|
| | cp framework.sh myscript |
|
| |
|
| === 7.1. 一般编程步骤 ===
| | 然后再插入自己的函数。 |
| | |
|
| |
| | |
| 现在我们来讨论编写一个脚本的一般步骤。任何优秀的脚本都应该具有帮助和输入参数。写一个框架脚本(framework.sh),该脚本包含了大多数脚本需要的框架结构,是一个非常不错的主意。这样一来,当我们开始编写新脚本时,可以先执行如下命令:
| |
| <pre>cp framework.sh myscript</pre>
| |
|
| |
| | |
| 然後再插入自己的函数。
| |
|
| |
|
| 让我们来看看如下两个示例。 | | 让我们来看看如下两个示例。 |
| | | === 二进制到十进制的转换=== |
|
| |
| | |
| === 7.2. 二进制到十进制的转换 === | |
| | |
|
| |
| | |
| ----
| |
| | |
|
| |
|
| |
|
| 脚本 b2d 将二进制数 (比如 1101) 转换为相应的十进制数。这也是一个用expr命令进行数学运算的例子: | | 脚本 b2d 将二进制数 (比如 1101) 转换为相应的十进制数。这也是一个用expr命令进行数学运算的例子: |
| <div lang="en" class="codearea" dir="ltr"><script type="text/javascript">
| |
| document.write('<a href="#" onclick="return togglenumber(\'CA-207d191769de27203cfe00538f94e294591bbd59_018\', 1, 1);" \
| |
|
| |
|
| class="codenumbers">Toggle line numbers<\/a>'); | | #!/bin/sh |
| | | # vim: set sw=4 ts=4 et: |
| </script><a class="codenumbers" onclick="return togglenumber('CA-207d191769de27203cfe00538f94e294591bbd59_018', 1, 1);" href="http://127.0.0.1:8000/Shell%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80#">Toggle line numbers</a>
| | help() |
| <pre lang="en" dir="ltr" id="CA-207d191769de27203cfe00538f94e294591bbd59_018"><span class="line"><span class="LineNumber"> 1 </span><span class="Comment">#!/bin/sh</span></span><br /><span class="line"><span class="LineNumber"> 2 </span><span class="Comment"># vim: set sw=4 ts=4 et:</span></span><br /><span class="line"><span class="LineNumber"> 3 </span><span class="ID">help</span><span class="Operator">(</span><span class="Operator">)</span></span><br /><span class="line"><span class="LineNumber"> 4 </span><span class="Operator">{</span></span><br /><span class="line"><span class="LineNumber"> 5 </span> <span class="ID">cat</span> <span class="Operator"><</span> <span class="ID">b2h</span> <span class="Operator">-</span><span class="Operator">-</span> <span class="ID">convert</span> <span class="ID">binary</span> <span class="ID">to</span> <span class="ID">decimal</span></span><br /><span class="line"><span class="LineNumber"> 6 </span></span><br /><span class="line"><span class="LineNumber"> 7 </span><span class="ID">USAGE</span><span class="Operator">:</span> <span class="ID">b2h</span> <span class="Operator">[</span><span class="Operator">-</span><span class="ID">h</span><span class="Operator">]</span> <span class="ID">binarynum</span></span><br /><span class="line"><span class="LineNumber"> 8 </span></span><br /><span class="line"><span class="LineNumber"> 9 </span><span class="ID">OPTIONS</span><span class="Operator">:</span> <span class="Operator">-</span><span class="ID">h</span> <span class="ID">help</span> <span class="ID">text</span></span><br /><span class="line"><span class="LineNumber"> 10 </span></span><br /><span class="line"><span class="LineNumber"> 11 </span><span class="ID">EXAMPLE</span><span class="Operator">:</span> <span class="ID">b2h</span> <span class="Number">111010</span></span><br /><span class="line"><span class="LineNumber"> 12 </span><span class="ID">will</span> <span class="ResWord">return</span> <span class="Number">58</span></span><br /><span class="line"><span class="LineNumber"> 13 </span><span class="ID">HELP</span></span><br /><span class="line"><span class="LineNumber"> 14 </span> <span class="ID">exit</span> <span class="Number">0</span></span><br /><span class="line"><span class="LineNumber"> 15 </span><span class="Operator">}</span></span><br /><span class="line"><span class="LineNumber"> 16 </span></span><br /><span class="line"><span class="LineNumber"> 17 </span><span class="ID">error</span><span class="Operator">(</span><span class="Operator">)</span></span><br /><span class="line"><span class="LineNumber"> 18 </span><span class="Operator">{</span></span><br /><span class="line"><span class="LineNumber"> 19 </span> <span class="Comment"># print an error and exit</span></span><br /><span class="line"><span class="LineNumber"> 20 </span> <span class="ID">echo</span> <span class="String">"$1"</span></span><br /><span class="line"><span class="LineNumber"> 21 </span> <span class="ID">exit</span> <span class="Number">1</span></span><br /><span class="line"><span class="LineNumber"> 22 </span><span class="Operator">}</span></span><br /><span class="line"><span class="LineNumber"> 23 </span></span><br /><span class="line"><span class="LineNumber"> 24 </span><span class="ID">lastchar</span><span class="Operator">(</span><span class="Operator">)</span></span><br /><span class="line"><span class="LineNumber"> 25 </span><span class="Operator">{</span></span><br /><span class="line"><span class="LineNumber"> 26 </span> <span class="Comment"># return the last character of a string in $rval</span></span><br /><span class="line"><span class="LineNumber"> 27 </span> <span class="ResWord">if</span> <span class="Operator">[</span> <span class="Operator">-</span><span class="ID">z</span> <span class="String">"$1"</span> <span class="Operator">]</span><span class="Operator">;</span> <span class="ID">then</span></span><br /><span class="line"><span class="LineNumber"> 28 </span> <span class="Comment"># empty string</span></span><br /><span class="line"><span class="LineNumber"> 29 </span> <span class="ID">rval</span><span class="Operator">=</span><span class="String">""</span></span><br /><span class="line"><span class="LineNumber"> 30 </span> <span class="ResWord">return</span></span><br /><span class="line"><span class="LineNumber"> 31 </span> <span class="ID">fi</span></span><br /><span class="line"><span class="LineNumber"> 32 </span> <span class="Comment"># wc puts some space behind the output this is why we need sed:</span></span><br /><span class="line"><span class="LineNumber"> 33 </span> <span class="ID">numofchar</span><span class="Operator">=</span><span class="Operator">`</span><span class="ID">echo</span> <span class="Operator">-</span><span class="ID">n</span> <span class="String">"$1"</span> <span class="Operator">|</span> <span class="ID">wc</span> <span class="Operator">-</span><span class="ID">c</span> <span class="Operator">|</span> <span class="ID">sed</span> <span class="String">'s/ //g'</span> <span class="Operator">`</span></span><br /><span class="line"><span class="LineNumber"> 34 </span> <span class="Comment"># now cut out the last char</span></span><br /><span class="line"><span class="LineNumber"> 35 </span> <span class="ID">rval</span><span class="Operator">=</span><span class="Operator">`</span><span class="ID">echo</span> <span class="Operator">-</span><span class="ID">n</span> <span class="String">"$1"</span> <span class="Operator">|</span> <span class="ID">cut</span> <span class="Operator">-</span><span class="ID">b</span><span class="Error"> </span><span class="Error">$</span><span class="ID">numofchar</span><span class="Operator">`</span></span><br /><span class="line"><span class="LineNumber"> 36 </span><span class="Operator">}</span></span><br /><span class="line"><span class="LineNumber"> 37 </span></span><br /><span class="line"><span class="LineNumber"> 38 </span><span class="ID">chop</span><span class="Operator">(</span><span class="Operator">)</span></span><br /><span class="line"><span class="LineNumber"> 39 </span><span class="Operator">{</span></span><br /><span class="line"><span class="LineNumber"> 40 </span> <span class="Comment"># remove the last character in string and return it in $rval</span></span><br /><span class="line"><span class="LineNumber"> 41 </span> <span class="ResWord">if</span> <span class="Operator">[</span> <span class="Operator">-</span><span class="ID">z</span> <span class="String">"$1"</span> <span class="Operator">]</span><span class="Operator">;</span> <span class="ID">then</span></span><br /><span class="line"><span class="LineNumber"> 42 </span> <span class="Comment"># empty string</span></span><br /><span class="line"><span class="LineNumber"> 43 </span> <span class="ID">rval</span><span class="Operator">=</span><span class="String">""</span></span><br /><span class="line"><span class="LineNumber"> 44 </span> <span class="ResWord">return</span></span><br /><span class="line"><span class="LineNumber"> 45 </span> <span class="ID">fi</span></span><br /><span class="line"><span class="LineNumber"> 46 </span> <span class="Comment"># wc puts some space behind the output this is why we need sed:</span></span><br /><span class="line"><span class="LineNumber"> 47 </span> <span class="ID">numofchar</span><span class="Operator">=</span><span class="Operator">`</span><span class="ID">echo</span> <span class="Operator">-</span><span class="ID">n</span> <span class="String">"$1"</span> <span class="Operator">|</span> <span class="ID">wc</span> <span class="Operator">-</span><span class="ID">c</span> <span class="Operator">|</span> <span class="ID">sed</span> <span class="String">'s/ //g'</span> <span class="Operator">`</span></span><br /><span class="line"><span class="LineNumber"> 48 </span> <span class="ResWord">if</span> <span class="Operator">[</span> <span class="String">"$numofchar"</span> <span class="Operator">=</span> <span class="String">"1"</span> <span class="Operator">]</span><span class="Operator">;</span> <span class="ID">then</span></span><br /><span class="line"><span class="LineNumber"> 49 </span> <span class="Comment"># only one char in string</span></span><br /><span class="line"><span class="LineNumber"> 50 </span> <span class="ID">rval</span><span class="Operator">=</span><span class="String">""</span></span><br /><span class="line"><span class="LineNumber"> 51 </span> <span class="ResWord">return</span></span><br /><span class="line"><span class="LineNumber"> 52 </span> <span class="ID">fi</span></span><br /><span class="line"><span class="LineNumber"> 53 </span> <span class="ID">numofcharminus1</span><span class="Operator">=</span><span class="Operator">`</span><span class="ID">expr</span><span class="Error"> </span><span class="Error">$</span><span class="ID">numofchar</span> <span class="String">"-"</span> <span class="Number">1</span><span class="Operator">`</span></span><br /><span class="line"><span class="LineNumber"> 54 </span> <span class="Comment"># now cut all but the last char:</span></span><br /><span class="line"><span class="LineNumber"> 55 </span> <span class="ID">rval</span><span class="Operator">=</span><span class="Operator">`</span><span class="ID">echo</span> <span class="Operator">-</span><span class="ID">n</span> <span class="String">"$1"</span> <span class="Operator">|</span> <span class="ID">cut</span> <span class="Operator">-</span><span class="ID">b</span> <span class="Number">0</span><span class="Operator">-</span><span class="Error">$</span><span class="Operator">{</span><span class="ID">numofcharminus1</span><span class="Operator">}</span><span class="Operator">`</span></span><br /><span class="line"><span class="LineNumber"> 56 </span><span class="Operator">}</span></span><br /><span class="line"><span class="LineNumber"> 57 </span></span><br /><span class="line"><span class="LineNumber"> 58 </span><span class="ResWord">while</span> <span class="Operator">[</span> <span class="Operator">-</span><span class="ID">n</span> <span class="String">"$1"</span> <span class="Operator">]</span><span class="Operator">;</span> <span class="ID">do</span></span><br /><span class="line"><span class="LineNumber"> 59 </span><span class="ID">case</span><span class="Error"> </span><span class="Error">$</span><span class="Number">1</span> <span class="ResWord">in</span></span><br /><span class="line"><span class="LineNumber"> 60 </span> <span class="Operator">-</span><span class="ID">h</span><span class="Operator">)</span> <span class="ID">help</span><span class="Operator">;</span><span class="ID">shift</span> <span class="Number">1</span><span class="Operator">;</span><span class="Operator">;</span> <span class="Comment"># function help is called</span></span><br /><span class="line"><span class="LineNumber"> 61 </span> <span class="Operator">-</span><span class="Operator">-</span><span class="Operator">)</span> <span class="ID">shift</span><span class="Operator">;</span><span class="ResWord">break</span><span class="Operator">;</span><span class="Operator">;</span> <span class="Comment"># end of options</span></span><br /><span class="line"><span class="LineNumber"> 62 </span> <span class="Operator">-</span><span class="Operator">*</span><span class="Operator">)</span> <span class="ID">error</span> <span class="String">"error: no such option $1. -h for help"</span><span class="Operator">;</span><span class="Operator">;</span></span><br /><span class="line"><span class="LineNumber"> 63 </span> <span class="Operator">*</span><span class="Operator">)</span> <span class="ResWord">break</span><span class="Operator">;</span><span class="Operator">;</span></span><br /><span class="line"><span class="LineNumber"> 64 </span><span class="ID">esac</span></span><br /><span class="line"><span class="LineNumber"> 65 </span><span class="ID">done</span></span><br /><span class="line"><span class="LineNumber"> 66 </span></span><br /><span class="line"><span class="LineNumber"> 67 </span><span class="Comment"># The main program</span></span><br /><span class="line"><span class="LineNumber"> 68 </span><span class="ID">sum</span><span class="Operator">=</span><span class="Number">0</span></span><br /><span class="line"><span class="LineNumber"> 69 </span><span class="ID">weight</span><span class="Operator">=</span><span class="Number">1</span></span><br /><span class="line"><span class="LineNumber"> 70 </span><span class="Comment"># one arg must be given:</span></span><br /><span class="line"><span class="LineNumber"> 71 </span><span class="Operator">[</span> <span class="Operator">-</span><span class="ID">z</span> <span class="String">"$1"</span> <span class="Operator">]</span> <span class="Operator">&</span><span class="Operator">&</span> <span class="ID">help</span></span><br /><span class="line"><span class="LineNumber"> 72 </span><span class="ID">binnum</span><span class="Operator">=</span><span class="String">"$1"</span></span><br /><span class="line"><span class="LineNumber"> 73 </span><span class="ID">binnumorig</span><span class="Operator">=</span><span class="String">"$1"</span></span><br /><span class="line"><span class="LineNumber"> 74 </span></span><br /><span class="line"><span class="LineNumber"> 75 </span><span class="ResWord">while</span> <span class="Operator">[</span> <span class="Operator">-</span><span class="ID">n</span> <span class="String">"$binnum"</span> <span class="Operator">]</span><span class="Operator">;</span> <span class="ID">do</span></span><br /><span class="line"><span class="LineNumber"> 76 </span> <span class="ID">lastchar</span> <span class="String">"$binnum"</span></span><br /><span class="line"><span class="LineNumber"> 77 </span> <span class="ResWord">if</span> <span class="Operator">[</span> <span class="String">"$rval"</span> <span class="Operator">=</span> <span class="String">"1"</span> <span class="Operator">]</span><span class="Operator">;</span> <span class="ID">then</span></span><br /><span class="line"><span class="LineNumber"> 78 </span> <span class="ID">sum</span><span class="Operator">=</span><span class="Operator">`</span><span class="ID">expr</span> <span class="String">"$weight"</span> <span class="String">"+"</span> <span class="String">"$sum"</span><span class="Operator">`</span></span><br /><span class="line"><span class="LineNumber"> 79 </span> <span class="ID">fi</span></span><br /><span class="line"><span class="LineNumber"> 80 </span> <span class="Comment"># remove the last position in $binnum</span></span><br /><span class="line"><span class="LineNumber"> 81 </span> <span class="ID">chop</span> <span class="String">"$binnum"</span></span><br /><span class="line"><span class="LineNumber"> 82 </span> <span class="ID">binnum</span><span class="Operator">=</span><span class="String">"$rval"</span></span><br /><span class="line"><span class="LineNumber"> 83 </span> <span class="ID">weight</span><span class="Operator">=</span><span class="Operator">`</span><span class="ID">expr</span> <span class="String">"$weight"</span> <span class="String">"*"</span> <span class="Number">2</span><span class="Operator">`</span></span><br /><span class="line"><span class="LineNumber"> 84 </span><span class="ID">done</span></span><br /><span class="line"><span class="LineNumber"> 85 </span></span><br /><span class="line"><span class="LineNumber"> 86 </span><span class="ID">echo</span> <span class="String">"binary $binnumorig is decimal $sum"</span></span><br /><span class="line"><span class="LineNumber"> 87 </span><span class="Comment">#</span><br /><strong>ERROR: EOF in multi-line statement</strong><br /></span></pre></div>
| | { |
|
| | cat < b2h -- convert binary to decimal |
| | |
| | USAGE: b2h [-h] binarynum |
| | |
| | OPTIONS: -h help text |
| | |
| | EXAMPLE: b2h 111010 |
| | will return 58 |
| | HELP |
| | exit 0 |
| | } |
| | |
| | error() |
| | { |
| | # print an error and exit |
| | echo "$1" |
| | exit 1 |
| | } |
| | |
| | lastchar() |
| | { |
| | # return the last character of a string in $rval |
| | if [ -z "$1" ]; then |
| | # empty string |
| | rval="" |
| | return |
| | fi |
| | # wc puts some space behind the output this is why we need sed: |
| | numofchar=`echo -n "$1" | wc -c | sed 's/ //g' ` |
| | # now cut out the last char |
| | rval=`echo -n "$1" | cut -b $numofchar` |
| | } |
| | |
| | chop() |
| | { |
| | # remove the last character in string and return it in $rval |
| | if [ -z "$1" ]; then |
| | # empty string |
| | rval="" |
| | return |
| | fi |
| | # wc puts some space behind the output this is why we need sed: |
| | numofchar=`echo -n "$1" | wc -c | sed 's/ //g' ` |
| | if [ "$numofchar" = "1" ]; then |
| | # only one char in string |
| | rval="" |
| | return |
| | fi |
| | numofcharminus1=`expr $numofchar "-" 1` |
| | # now cut all but the last char: |
| | rval=`echo -n "$1" | cut -b 0-${numofcharminus1}` |
| | } |
| | |
| | while [ -n "$1" ]; do |
| | case $1 in |
| | -h) help;shift 1;; # function help is called |
| | --) shift;break;; # end of options |
| | -*) error "error: no such option $1. -h for help";; |
| | *) break;; |
| | esac |
| | done |
| | |
| | # The main program |
| | sum=0 |
| | weight=1 |
| | # one arg must be given: |
| | [ -z "$1" ] && help |
| | binnum="$1" |
| | binnumorig="$1" |
| | |
| | while [ -n "$binnum" ]; do |
| | lastchar "$binnum" |
| | if [ "$rval" = "1" ]; then |
| | sum=`expr "$weight" "+" "$sum"` |
| | fi |
| | # remove the last position in $binnum |
| | chop "$binnum" |
| | binnum="$rval" |
| | weight=`expr "$weight" "*" 2` |
| | done |
| | |
| | echo "binary $binnumorig is decimal $sum" |
| | # |
|
| |
|
| 该脚本使用的算法是利用十进制和二进制数权值 (1,2,4,8,16,..),比如二进制"10"可以这样转换成十进制: | | 该脚本使用的算法是利用十进制和二进制数权值 (1,2,4,8,16,..),比如二进制"10"可以这样转换成十进制: |
| <pre>0 * 1 + 1 * 2 = 2<br /></pre>
| |
|
| |
|
| |
|
| 为了得到单个的二进制数我们是用了lastchar 函数。该函数使用wc –c计算字符个数,然後使用cut命令取出末尾一个字符。Chop函数的功能则是移除最後一个字符。
| | 0 * 1 + 1 * 2 = 2 |
|
| |
|
|
| | 为了得到单个的二进制数我们是用了lastchar 函数。该函数使用wc –c计算字符个数,然后使用cut命令取出末尾一个字符。Chop函数的功能则是移除最后一个字符。 |
| | === 文件循环拷贝=== |
|
| |
|
| === 7.3. 文件循环拷贝 ===
| | 你可能有这样的需求并一直都这么做:将所有发出邮件保存到一个文件中。但是过了几个月之后,这个文件可能会变得很大以至于该文件的访问速度变慢;下面的脚本 rotatefile 可以解决这个问题。这个脚本可以重命名邮件保存文件(假设为outmail)为outmail.1,而原来的outmail.1就变成了 outmail.2 等等... |
|
| |
|
|
| | #!/bin/sh |
| | # vim: set sw=4 ts=4 et: |
| | |
| | ver="0.1" |
| | help() |
| | { |
| | cat < rotatefile -- rotate the file name |
| | USAGE: rotatefile [-h] filename |
| | OPTIONS: -h help text |
| | EXAMPLE: rotatefile out |
| | |
| | This will e.g rename out.2 to out.3, out.1 to out.2, out to out.1[BR] |
| | and create an empty out-file |
| | |
| | The max number is 10 |
| | |
| | version $ver |
| | HELP |
| | |
| | exit 0 |
| | } |
| | |
| | error() |
| | { |
| | echo "$1" |
| | exit 1 |
| | } |
| | |
| | while [ -n "$1" ]; do |
| | case $1 in |
| | -h) help;shift 1;; |
| | --) break;; |
| | -*) echo "error: no such option $1. -h for help";exit 1;; |
| | *) break;; |
| | esac |
| | done |
| | |
| | # input check: |
| | if [ -z "$1" ] ; then |
| | error "ERROR: you must specify a file, use -h for help" |
| | fi |
| | |
| | filen="$1" |
| | # rename any .1 , .2 etc file: |
| | for n in 9 8 7 6 5 4 3 2 1; do |
| | if [ -f "$filen.$n" ]; then |
| | p=`expr $n + 1` |
| | echo "mv $filen.$n $filen.$p" |
| | mv $filen.$n $filen.$p |
| | fi |
| | done |
| | |
| | # rename the original file: |
| | if [ -f "$filen" ]; then |
| | echo "mv $filen $filen.1" |
| | mv $filen $filen.1 |
| | fi |
| | |
| | echo touch $filen |
| | touch $filen |
|
| |
|
| 你 可能有这样的需求并一直都这么做:将所有发出邮件保存到一个文件中。但是过了几个月之後,这个文件可能会变得很大以至于该文件的访问速度变慢;下面的脚本 rotatefile 可以解决这个问题。这个脚本可以重命名邮件保存文件(假设为outmail)为outmail.1,而原来的outmail.1就变成了 outmail.2 等等...
| | 这个脚本是如何工作的呢?在检测到用户提供了一个文件名之后,首先进行一个9到1的循环;文件名.9重命名为文件名.10,文件名.8重命名为文件名. 9……等等。循环结束之后,把原始文件命名为文件名.1,同时创建一个和原始文件同名的空文件(touch $filen)。 |
| | | == 脚本调试== |
|
| |
| <div lang="en" class="codearea" dir="ltr"><script type="text/javascript">
| |
| document.write('<a href="#" onclick="return togglenumber(\'CA-20be6ed29fcf5783fddc7f33ca5a1734626f729f_019\', 1, 1);" \
| |
| | |
| class="codenumbers">Toggle line numbers<\/a>');
| |
| | |
| </script><a class="codenumbers" onclick="return togglenumber('CA-20be6ed29fcf5783fddc7f33ca5a1734626f729f_019', 1, 1);" href="http://127.0.0.1:8000/Shell%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80#">Toggle line numbers</a>
| |
| <pre lang="en" dir="ltr" id="CA-20be6ed29fcf5783fddc7f33ca5a1734626f729f_019"><span class="line"><span class="LineNumber"> 1 </span><span class="Comment">#!/bin/sh</span></span><br /><span class="line"><span class="LineNumber"> 2 </span><span class="Comment"># vim: set sw=4 ts=4 et:</span></span><br /><span class="line"><span class="LineNumber"> 3 </span></span><br /><span class="line"><span class="LineNumber"> 4 </span><span class="ID">ver</span><span class="Operator">=</span><span class="String">"0.1"</span></span><br /><span class="line"><span class="LineNumber"> 5 </span><span class="ID">help</span><span class="Operator">(</span><span class="Operator">)</span></span><br /><span class="line"><span class="LineNumber"> 6 </span><span class="Operator">{</span></span><br /><span class="line"><span class="LineNumber"> 7 </span> <span class="ID">cat</span> <span class="Operator"><</span> <span class="ID">rotatefile</span> <span class="Operator">-</span><span class="Operator">-</span> <span class="ID">rotate</span> <span class="ID">the</span> <span class="ID">file</span> <span class="ID">name</span></span><br /><span class="line"><span class="LineNumber"> 8 </span> <span class="ID">USAGE</span><span class="Operator">:</span> <span class="ID">rotatefile</span> <span class="Operator">[</span><span class="Operator">-</span><span class="ID">h</span><span class="Operator">]</span> <span class="ID">filename</span></span><br /><span class="line"><span class="LineNumber"> 9 </span> <span class="ID">OPTIONS</span><span class="Operator">:</span> <span class="Operator">-</span><span class="ID">h</span> <span class="ID">help</span> <span class="ID">text</span></span><br /><span class="line"><span class="LineNumber"> 10 </span> <span class="ID">EXAMPLE</span><span class="Operator">:</span> <span class="ID">rotatefile</span> <span class="ID">out</span></span><br /><span class="line"><span class="LineNumber"> 11 </span></span><br /><span class="line"><span class="LineNumber"> 12 </span> <span class="ID">This</span> <span class="ID">will</span> <span class="ID">e</span><span class="Operator">.</span><span class="ID">g</span> <span class="ID">rename</span> <span class="ID">out</span><span class="Number">.2</span> <span class="ID">to</span> <span class="ID">out</span><span class="Number">.3</span><span class="Operator">,</span> <span class="ID">out</span><span class="Number">.1</span> <span class="ID">to</span> <span class="ID">out</span><span class="Number">.2</span><span class="Operator">,</span> <span class="ID">out</span> <span class="ID">to</span> <span class="ID">out</span><span class="Number">.1</span><span class="Operator">[</span><span class="ID">BR</span><span class="Operator">]</span></span><br /><span class="line"><span class="LineNumber"> 13 </span> <span class="ResWord">and</span> <span class="ID">create</span> <span class="ID">an</span> <span class="ID">empty</span> <span class="ID">out</span><span class="Operator">-</span><span class="ID">file</span></span><br /><span class="line"><span class="LineNumber"> 14 </span></span><br /><span class="line"><span class="LineNumber"> 15 </span> <span class="ID">The</span> <span class="ID">max</span> <span class="ID">number</span> <span class="ResWord">is</span> <span class="Number">10</span></span><br /><span class="line"><span class="LineNumber"> 16 </span></span><br /><span class="line"><span class="LineNumber"> 17 </span> <span class="ID">version</span><span class="Error"> </span><span class="Error">$</span><span class="ID">ver</span></span><br /><span class="line"><span class="LineNumber"> 18 </span> <span class="ID">HELP</span></span><br /><span class="line"><span class="LineNumber"> 19 </span></span><br /><span class="line"><span class="LineNumber"> 20 </span> <span class="ID">exit</span> <span class="Number">0</span></span><br /><span class="line"><span class="LineNumber"> 21 </span><span class="Operator">}</span></span><br /><span class="line"><span class="LineNumber"> 22 </span></span><br /><span class="line"><span class="LineNumber"> 23 </span><span class="ID">error</span><span class="Operator">(</span><span class="Operator">)</span></span><br /><span class="line"><span class="LineNumber"> 24 </span><span class="Operator">{</span></span><br /><span class="line"><span class="LineNumber"> 25 </span> <span class="ID">echo</span> <span class="String">"$1"</span></span><br /><span class="line"><span class="LineNumber"> 26 </span> <span class="ID">exit</span> <span class="Number">1</span></span><br /><span class="line"><span class="LineNumber"> 27 </span><span class="Operator">}</span></span><br /><span class="line"><span class="LineNumber"> 28 </span></span><br /><span class="line"><span class="LineNumber"> 29 </span><span class="ResWord">while</span> <span class="Operator">[</span> <span class="Operator">-</span><span class="ID">n</span> <span class="String">"$1"</span> <span class="Operator">]</span><span class="Operator">;</span> <span class="ID">do</span></span><br /><span class="line"><span class="LineNumber"> 30 </span> <span class="ID">case</span><span class="Error"> </span><span class="Error">$</span><span class="Number">1</span> <span class="ResWord">in</span></span><br /><span class="line"><span class="LineNumber"> 31 </span> <span class="Operator">-</span><span class="ID">h</span><span class="Operator">)</span> <span class="ID">help</span><span class="Operator">;</span><span class="ID">shift</span> <span class="Number">1</span><span class="Operator">;</span><span class="Operator">;</span></span><br /><span class="line"><span class="LineNumber"> 32 </span> <span class="Operator">-</span><span class="Operator">-</span><span class="Operator">)</span> <span class="ResWord">break</span><span class="Operator">;</span><span class="Operator">;</span></span><br /><span class="line"><span class="LineNumber"> 33 </span> <span class="Operator">-</span><span class="Operator">*</span><span class="Operator">)</span> <span class="ID">echo</span> <span class="String">"error: no such option $1. -h for help"</span><span class="Operator">;</span><span class="ID">exit</span> <span class="Number">1</span><span class="Operator">;</span><span class="Operator">;</span></span><br /><span class="line"><span class="LineNumber"> 34 </span> <span class="Operator">*</span><span class="Operator">)</span> <span class="ResWord">break</span><span class="Operator">;</span><span class="Operator">;</span></span><br /><span class="line"><span class="LineNumber"> 35 </span> <span class="ID">esac</span></span><br /><span class="line"><span class="LineNumber"> 36 </span><span class="ID">done</span></span><br /><span class="line"><span class="LineNumber"> 37 </span></span><br /><span class="line"><span class="LineNumber"> 38 </span><span class="Comment"># input check:</span></span><br /><span class="line"><span class="LineNumber"> 39 </span><span class="ResWord">if</span> <span class="Operator">[</span> <span class="Operator">-</span><span class="ID">z</span> <span class="String">"$1"</span> <span class="Operator">]</span> <span class="Operator">;</span> <span class="ID">then</span></span><br /><span class="line"><span class="LineNumber"> 40 </span> <span class="ID">error</span> <span class="String">"ERROR: you must specify a file, use -h for help"</span></span><br /><span class="line"><span class="LineNumber"> 41 </span><span class="ID">fi</span></span><br /><span class="line"><span class="LineNumber"> 42 </span></span><br /><span class="line"><span class="LineNumber"> 43 </span><span class="ID">filen</span><span class="Operator">=</span><span class="String">"$1"</span></span><br /><span class="line"><span class="LineNumber"> 44 </span><span class="Comment"># rename any .1 , .2 etc file:</span></span><br /><span class="line"><span class="LineNumber"> 45 </span><span class="ResWord">for</span> <span class="ID">n</span> <span class="ResWord">in</span> <span class="Number">9</span> <span class="Number">8</span> <span class="Number">7</span> <span class="Number">6</span> <span class="Number">5</span> <span class="Number">4</span> <span class="Number">3</span> <span class="Number">2</span> <span class="Number">1</span><span class="Operator">;</span> <span class="ID">do</span></span><br /><span class="line"><span class="LineNumber"> 46 </span> <span class="ResWord">if</span> <span class="Operator">[</span> <span class="Operator">-</span><span class="ID">f</span> <span class="String">"$filen.$n"</span> <span class="Operator">]</span><span class="Operator">;</span> <span class="ID">then</span></span><br /><span class="line"><span class="LineNumber"> 47 </span> <span class="ID">p</span><span class="Operator">=</span><span class="Operator">`</span><span class="ID">expr</span><span class="Error"> </span><span class="Error">$</span><span class="ID">n</span> <span class="Operator">+</span> <span class="Number">1</span><span class="Operator">`</span></span><br /><span class="line"><span class="LineNumber"> 48 </span> <span class="ID">echo</span> <span class="String">"mv $filen.$n $filen.$p"</span></span><br /><span class="line"><span class="LineNumber"> 49 </span> <span class="ID">mv</span><span class="Error"> </span><span class="Error">$</span><span class="ID">filen</span><span class="Operator">.</span><span class="Error">$</span><span class="ID">n</span><span class="Error"> </span><span class="Error">$</span><span class="ID">filen</span><span class="Operator">.</span><span class="Error">$</span><span class="ID">p</span></span><br /><span class="line"><span class="LineNumber"> 50 </span> <span class="ID">fi</span></span><br /><span class="line"><span class="LineNumber"> 51 </span><span class="ID">done</span></span><br /><span class="line"><span class="LineNumber"> 52 </span></span><br /><span class="line"><span class="LineNumber"> 53 </span><span class="Comment"># rename the original file:</span></span><br /><span class="line"><span class="LineNumber"> 54 </span><span class="ResWord">if</span> <span class="Operator">[</span> <span class="Operator">-</span><span class="ID">f</span> <span class="String">"$filen"</span> <span class="Operator">]</span><span class="Operator">;</span> <span class="ID">then</span></span><br /><span class="line"><span class="LineNumber"> 55 </span> <span class="ID">echo</span> <span class="String">"mv $filen $filen.1"</span></span><br /><span class="line"><span class="LineNumber"> 56 </span> <span class="ID">mv</span><span class="Error"> </span><span class="Error">$</span><span class="ID">filen</span><span class="Error"> </span><span class="Error">$</span><span class="ID">filen</span><span class="Number">.1</span></span><br /><span class="line"><span class="LineNumber"> 57 </span><span class="ID">fi</span></span><br /><span class="line"><span class="LineNumber"> 58 </span></span><br /><span class="line"><span class="LineNumber"> 59 </span><span class="ID">echo</span> <span class="ID">touch</span><span class="Error"> </span><span class="Error">$</span><span class="ID">filen</span></span><br /><span class="line"><span class="LineNumber"> 60 </span><span class="ID">touch</span><span class="Error"> </span><span class="Error">$</span><span class="ID">filen</span><br /><strong>ERROR: EOF in multi-line statement</strong><br /></span></pre></div>
| |
|
| |
| | |
| 这 个脚本是如何工作的呢?在检测到用户提供了一个文件名之後,首先进行一个9到1的循环;文件名.9重命名为文件名.10,文件名.8重命名为文件名. 9……等等。循环结束之後,把原始文件命名为文件名.1,同时创建一个和原始文件同名的空文件(touch $filen)。
| |
| | |
|
| |
| | |
| == 8. 脚本调试 == | |
| | |
|
| |
|
| |
|
| 最简单的调试方法当然是使用echo命令。你可以在任何怀疑出错的地方用echo打印变量值,这也是大部分shell程序员花费80%的时间用于调试的原因。Shell脚本的好处在于无需重新编译,而插入一个echo命令也不需要多少时间。 | | 最简单的调试方法当然是使用echo命令。你可以在任何怀疑出错的地方用echo打印变量值,这也是大部分shell程序员花费80%的时间用于调试的原因。Shell脚本的好处在于无需重新编译,而插入一个echo命令也不需要多少时间。 |
|
| |
|
| shell也有一个真正的调试模式,如果脚本"strangescript"出错,可以使用如下命令进行调试: | | shell也有一个真正的调试模式,如果脚本"strangescript"出错,可以使用如下命令进行调试: |
| <pre>sh -x strangescript<br /></pre>
| | |
|
| | sh -x strangescript |
|
| |
|
| 上述命令会执行该脚本,同时显示所有变量的值。 | | 上述命令会执行该脚本,同时显示所有变量的值。 |
|
| |
|
| shell还有一个不执行脚本只检查语法的模式,命令如下: | | shell还有一个不执行脚本只检查语法的模式,命令如下: |
| <pre>sh -n your_script<br /></pre>
| | |
|
| | sh -n your_script |
|
| |
|
| 这个命令会返回所有语法错误。 | | 这个命令会返回所有语法错误。 |
|
| |
|
| 我们希望你现在已经可以开始编写自己的shell脚本了,尽情享受这份乐趣吧! <img width="15" height="15" title=":)" src="http://127.0.0.1:8000/wiki/ubuntu-cn/img/smile.png" alt=":)" /> | | 我们希望你现在已经可以开始编写自己的shell脚本了,尽情享受这份乐趣吧! :) |
| | |
| ----
| |
| | |
| <a href="http://127.0.0.1:8000/%E6%94%AF%E6%8C%81%E6%89%80%E6%9C%89%E7%89%88%E6%9C%AC%E7%B1%BB">支持所有版本类</a>
| |
| | |
| Shell编程基础 (2007-03-16 07:17:53由<span title="??? @ localhost[127.0.0.1]">localhost</span>编辑)
| |
本文作者:Leal
授权许可:
编辑人员:FireHare, Dbzhang800
校对人员:Dbzhang800
基本格式
我们可以使用任意一种文字编辑器,比如nedit、kedit、emacs、vi等来编写shell脚本,它必须以如下行开始(必须放在文件的第一行):
# !/bin/sh
...
符号#!用来告诉系统执行该脚本的程序,本例使用/bin/sh。编辑结束并保存後,如果要执行该脚本,必须先使其可执行:
chmod +x filename
此後在该脚本所在目录下,输入 ./filename 即可执行该脚本。
合理使用注释
shell 脚本中以# 开始的行表示注释,直到该行的结束。我们强烈建议你在脚本中进行适当/合理的注释,这样一来,即便你在相当长时间内没有使用该脚本,也能在短时间内就明白 它的作用和工作原理。此外,还有一个很重要的原因是,在注释的帮助下,别人可以快速有效的分享你的脚本,并提出自己的意见和改进。
变量赋值和引用
Shell编程中,使用变量无需事先声明,同时变量名的命名须遵循如下规则:
- 首个字符必须为字母(a-z,A-Z)
- 中间不能有空格,可以使用下划线(_)
- 不能使用标点符号
- 不能使用bash里的关键字(可用help命令查看保留关键字)
需要给变量赋值时,可以这么写:
变量名=值
要取用一个变量的值,只需在变量名前面加一个$:
#!/bin/sh
# 对变量赋值:
a="hello world"
# 打印变量a的值:
echo "A is:" $a
挑个自己喜欢的编辑器,输入上述内容,并保存为文件first,然後执行 chmod +x first 使其可执行,最後输入 ./first 执行该脚本。其输出结果如下:
A is: hello world
有时候变量名可能会和其它文字混淆,比如:
num=2
echo "this is the $numnd"
上述脚本并不会输出"this is the 2nd"而是"this is the ";这是由于shell会去搜索变量numnd的值,而实际上这个变量此时并没有值。这时,我们可以用花括号来告诉shell要打印的是num变量:
num=2
echo "this is the ${num}nd"
其输出结果为:this is the 2nd
Shell脚本中有许多变量是系统自动设定的,我们将在用到这些变量时再作说明。除了只在脚本内有效的普通shell变量外,还有环境变量,即那些由export关键字处理过的变量。本文不讨论环境变量,因为它们一般只在登录脚本中用到。
Shell里的命令
Unix 命令
在shell脚本中可以使用任意unix命令,不过实际上最为常用的一般都是那些文件和文字操作相关的命令。下面介绍一些常用命令的语法和功能:
- echo "some text"
- 在屏幕上输出信息
- ls
- 文件列表
- wc –l file wc -w file wc -c file
- 分别计算文件的行数(line)、单词数(word)和字符数(character)
- cp sourcefile destfile
- 文件拷贝
- mv oldname newname
- 重命名文件或移动文件
- rm file
- 删除文件
- grep 'pattern' file
- 在文件内搜索字符串或和正则表达式匹配的字符串
- cut -b column file
- 将指定范围内的文件内容输出到标准输出设备(屏幕)上。比如:输出每行第5至9个字符 cut -b5-9 file.txt,注意不要和cat命令混淆,这是两个完全不同的命令
- cat file.txt
- 输出文件内容到标准输出设备(屏幕)上
- file somefile
- 取得文件somefile的文件类型
- read var
- 提示用户输入,并将输入内容赋值给变量var
- sort file.txt
- 对file.txt文件所有行进行排序
- uniq
- 只输出文件中内容不一致的行,如: sort file.txt | uniq
- expr
- 进行数学运算,如要进行2+3的运算,命令为: expr 2 "+" 3
- find
- 搜索文件,如根据文件名搜索:find . -name filename -print
- tee
- 将数据输出到标准输出设备(屏幕) 和文件,比如:somecommand | tee outfile
- basename file
- 返回不包含路径的文件名,如: basename /bin/tux 会返回 tux
- dirname file
- 返回文件所在路径,如:dirname /bin/tux 会返回 /bin
- head file
- 打印文本文件开头几行
- tail file
- 打印文本文件末尾几行
- sed
- 是一个基本的查找替换程序。可以从标准输入(如命令管道)读入文本,并将结果输出到标准输出(屏幕);该命令采用正则表达式进行搜索。不要和 shell中的通配符相混淆。比如将 ubuntu 替换为 Ubuntu :cat text.file | sed 's/ubuntu/Ubuntu/' > newtext.file
- awk
- 用来提取文本文件中的字段。缺省的字段分割符是空格,可以使用 -F 指定其它分割符。cat file.txt | awk -F, '{print $1 "," $3 }',这里我们使用 , 作为字段分割符,同时打印第一和第三个字段。如果该文件内容为 Adam Bor, 34, IndiaKerry Miller, 22, USA,则上述命令的输出为:Adam Bor, IndiaKerry Miller, USA
概念: 管道, 重定向和 backtick
尽管这些都不是系统命令,不过它们扮演着相当重要的角色。
- 管道 (|) 将一个命令的输出作为另外一个命令的输入
grep "hello" file.txt | wc -l
上述命令会在file.txt中搜索包含有”hello”的行并计算行数,这里grep命令的输出成了wc命令的输入。
- 重定向:将命令的结果输出到文件,而不是标准输出(屏幕)
> 写入文件并复盖旧文件
>> 加到文件的尾部,保留旧文件内容
反短斜线可以将一个命令的输出作为其它命令的命令行参数。
find . -mtime -1 -type f -print
上述命令可以查找过去24小时(-mtime –2则表示过去48小时)内修改过的文件。如果你想将上述命令查找到的所有文件打包,则可以使用如下脚本:
#!/bin/sh
# The ticks are backticks (`) not normal quotes ('):
tar -zcvf lastmod.tar.gz `find . -mtime -1 -type f -print`
Shell里的流程控制
if 语句
"if"表达式如果条件为真,则执行then后的部分:
if ....; then
....
elif ....; then
....
else
....
fi
大多数情况下,可以使用测试命令来对条件进行测试,比如可以比较字符串、判断文件是否存在及是否可读等等……通常用" [ ] "来表示条件测试,注意这里的空格很重要,要确保方括号前后的空格。
- [ -f "somefile" ] :判断是否是一个文件
- [ -x "/bin/ls" ] :判断/bin/ls是否存在并有可执行权限
- [ -n "$var" ] :判断$var变量是否有值
- [ "$a" = "$b" ] :判断$a和$b是否相等
执行man test可以查看所有测试表达式可以比较和判断的类型。下面是一个简单的if语句:
#!/bin/sh
if [ "$SHELL" = "/bin/bash" ]; then
echo "your login shell is the bash (bourne again shell)"
else
echo "your login shell is not bash but $SHELL"
fi
变量$SHELL包含有登录shell的名称,我们拿它和/bin/bash进行比较以判断当前使用的shell是否为bash。
&& 和|| 操作符
熟悉C语言的朋友可能会喜欢下面的表达式:
[ -f "/etc/shadow" ] && echo "This computer uses shadow passwords"
这里的 && 就是一个快捷操作符,如果左边的表达式为真则执行右边的语句,你也可以把它看作逻辑运算里的与操作。上述脚本表示如果/etc/shadow文件存在,则打印”This computer uses shadow passwords”。同样shell编程中还可以用或操作(||),例如:
#!/bin/sh
mailfolder=/var/spool/mail/james
[ -r "$mailfolder" ] || { echo "Can not read $mailfolder" ; exit 1; }
echo "$mailfolder has mail from:"
grep "^From " $mailfolder
该脚本首先判断mailfolder是否可读,如果可读则打印该文件中的"From" 一行。如果不可读则或操作生效,打印错误信息后脚本退出。需要注意的是,这里我们必须使用如下两个命令:
- -打印错误信息
- -退出程序
我们使用花括号以匿名函数的形式将两个命令放到一起作为一个命令使用;普通函数稍后再作说明。即使不用与和或操作符,我们也可以用if表达式完成任何事情,但是使用与或操作符会更便利很多。
case 语句
case表达式可以用来匹配一个给定的字符串,而不是数字(可别和C语言里的switch...case混淆)。
case ... in
...) do something here ;;
esac
让我们看一个例子,file命令可以辨别出一个给定文件的文件类型,如:file lf.gz,其输出结果为:
lf.gz: gzip compressed data, deflated, original filename,
last modified: Mon Aug 27 23:09:18 2001, os: Unix
我们利用这点写了一个名为smartzip的脚本,该脚本可以自动解压bzip2, gzip和zip 类型的压缩文件:
#!/bin/sh
ftype=`file "$1"`
case "$ftype" in
"$1: Zip archive"*)
unzip "$1" ;;
"$1: gzip compressed"*)
gunzip "$1" ;;
"$1: bzip2 compressed"*)
bunzip2 "$1" ;;
*) error "File $1 can not be uncompressed with smartzip";;
esac
你可能注意到上面使用了一个特殊变量$1,该变量包含有传递给该脚本的第一个参数值。也就是说,当我们运行:
smartzip articles.zip
$1 就是字符串 articles.zip。
select 语句
select表达式是bash的一种扩展应用,擅长于交互式场合。用户可以从一组不同的值中进行选择:
select var in ... ; do
break
done
.... now $var can be used ....
下面是一个简单的示例:
#!/bin/sh
echo "What is your favourite OS?"
select var in "Linux" "Gnu Hurd" "Free BSD" "Other"; do
break
done
echo "You have selected $var"
该脚本的运行结果如下:
What is your favourite OS?
1) Linux
2) Gnu Hurd
3) Free BSD
4) Other
#? 1
You have selected Linux
while/for 循环
在shell中,可以使用如下循环:
while ...; do
....
done
只要测试表达式条件为真,则while循环将一直运行。关键字"break"用来跳出循环,而关键字”continue”则可以跳过一个循环的余下部分,直接跳到下一次循环中。
for循环会查看一个字符串列表(字符串用空格分隔),并将其赋给一个变量:
for var in ....; do
....
done
下面的示例会把A B C分别打印到屏幕上:
#!/bin/sh
for var in A B C ; do
echo "var is $var"
done
下面是一个实用的脚本showrpm,其功能是打印一些RPM包的统计信息:
#!/bin/sh
# list a content summary of a number of RPM packages
# USAGE: showrpm rpmfile1 rpmfile2 ...
# EXAMPLE: showrpm /cdrom/RedHat/RPMS/*.rpm
for rpmpackage in $*; do
if [ -r "$rpmpackage" ];then
echo "=============== $rpmpackage =============="
rpm -qi -p $rpmpackage
else
echo "ERROR: cannot read file $rpmpackage"
fi
done
这里出现了第二个特殊变量$*,该变量包含有输入的所有命令行参数值。如果你运行showrpm openssh.rpm w3m.rpm webgrep.rpm,那么 $* 就包含有 3 个字符串,即openssh.rpm, w3m.rpm和 webgrep.rpm。
Shell里的一些特殊符号
引号
在向程序传递任何参数之前,程序会扩展通配符和变量。这里所谓的扩展是指程序会把通配符(比如*)替换成适当的文件名,把变量替换成变量值。我们可以使用引号来防止这种扩展,先来看一个例子,假设在当前目录下有两个jpg文件:mail.jpg和tux.jpg。
#!/bin/sh
echo *.jpg
运行结果为:
mail.jpg tux.jpg
引号(单引号和双引号)可以防止通配符*的扩展:
#!/bin/sh
echo "*.jpg"
echo '*.jpg'
其运行结果为:
*.jpg
*.jpg
其中单引号更严格一些,它可以防止任何变量扩展;而双引号可以防止通配符扩展但允许变量扩展:
#!/bin/sh
echo $SHELL
echo "$SHELL"
echo '$SHELL'
运行结果为:
/bin/bash
/bin/bash
$SHELL
此外还有一种防止这种扩展的方法,即使用转义字符——反斜杆:
echo *.jpg
echo $SHELL
输出结果为:
*.jpg
$SHELL
Here documents
当要将几行文字传递给一个命令时,here documents一种不错的方法。对每个脚本写一段帮助性的文字是很有用的,此时如果使用here documents就不必用echo函数一行行输出。Here document以 << 开头,后面接上一个字符串,这个字符串还必须出现在here document的末尾。下面是一个例子,在该例子中,我们对多个文件进行重命名,并且使用here documents打印帮助:
#!/bin/sh
# we have less than 3 arguments. Print the help text:
if [ $# -lt 3 ] ; then
cat < ren -- renames a number of files using sed regular expressions
USAGE: ren 'regexp' 'replacement' files...
EXAMPLE: rename all *.HTM files in *.html:
ren 'HTM$' 'html' *.HTM
HELP
exit 0
fi
OLD="$1"
NEW="$2"
# The shift command removes one argument from the list of
# command line arguments.
shift
shift
# $* contains now all the files:
for file in $*; do
if [ -f "$file" ] ; then
newfile=`echo "$file" | sed "s/${OLD}/${NEW}/g"`
if [ -f "$newfile" ]; then
echo "ERROR: $newfile exists already"
else
echo "renaming $file to $newfile ..."
mv "$file" "$newfile"
fi
fi
done
这个示例有点复杂,我们需要多花点时间来说明一番。第一个if表达式判断输入命令行参数是否小于3个 (特殊变量$# 表示包含参数的个数) 。如果输入参数小于3个,则将帮助文字传递给cat命令,然后由cat命令将其打印在屏幕上。打印帮助文字后程序退出。如果输入参数等于或大于3个,我们就将第一个参数赋值给变量OLD,第二个参数赋值给变量NEW。下一步,我们使用shift命令将第一个和第二个参数从参数列表中删除,这样原来的第三个参数就成为参数列表$*的第一个参数。然后我们开始循环,命令行参数列表被一个接一个地被赋值给变量$file。接着我们判断该文件是否存在,如果存在则通过sed命令搜索和替换来产生新的文件名。然后将反短斜线内命令结果赋值给newfile。这样我们就达到了目的:得到了旧文件名和新文件名。然后使用 mv命令进行重命名。
Shell里的函数
如果你写过比较复杂的脚本,就会发现可能在几个地方使用了相同的代码,这时如果用上函数,会方便很多。函数的大致样子如下:
functionname()
{
# inside the body $1 is the first argument given to the function
# $2 the second ...
body
}
你需要在每个脚本的开始对函数进行声明。
下面是一个名为xtitlebar的脚本,它可以改变终端窗口的名称。这里使用了一个名为help的函数,该函数在脚本中使用了两次:
#!/bin/sh
# vim: set sw=4 ts=4 et:
help()
{
cat < xtitlebar -- change the name of an xterm, gnome-terminal or kde konsole
USAGE: xtitlebar [-h] "string_for_titelbar"
OPTIONS: -h help text
EXAMPLE: xtitlebar "cvs"
HELP
exit 0
}
# in case of error or if -h is given we call the function help:
[ -z "$1" ] && help
[ "$1" = "-h" ] && help
# send the escape sequence to change the xterm titelbar:
echo -e "33]0;$107"
#
在脚本中提供帮助是一种很好的编程习惯,可以方便其他用户(和自己)使用和理解脚本。
命令行参数
我们已经见过$* 和 $1, $2 ... $9 等特殊变量,这些特殊变量包含了用户从命令行输入的参数。迄今为止,我们仅仅了解了一些简单的命令行语法(比如一些强制性的参数和查看帮助的-h选项)。但是在编写更复杂的程序时,您可能会发现您需要更多的自定义的选项。通常的惯例是在所有可选的参数之前加一个减号,后面再加上参数值 (比如文件名)。
有好多方法可以实现对输入参数的分析,但是下面的使用case表达式的例子无疑是一个不错的方法。
#!/bin/sh
help()
{
cat < This is a generic command line parser demo.
USAGE EXAMPLE: cmdparser -l hello -f -- -somefile1 somefile2
HELP
exit 0
}
while [ -n "$1" ]; do
case $1 in
-h) help;shift 1;; # function help is called
-f) opt_f=1;shift 1;; # variable opt_f is set
-l) opt_l=$2;shift 2;; # -l takes an argument -> shift by 2
--) shift;break;; # end of options
-*) echo "error: no such option $1. -h for help";exit 1;;
*) break;;
esac
done
echo "opt_f is $opt_f"
echo "opt_l is $opt_l"
echo "first arg is $1"
echo "2nd arg is $2"
你可以这样运行该脚本:
cmdparser -l hello -f -- -somefile1 somefile2
返回结果如下:
opt_f is 1
opt_l is hello
first arg is -somefile1
2nd arg is somefile2
这个脚本是如何工作的呢?脚本首先在所有输入命令行参数中进行循环,将输入参数与case表达式进行比较,如果匹配则设置一个变量并且移除该参数。根据unix系统的惯例,首先输入的应该是包含减号的参数。
Shell脚本示例
一般编程步骤
现在我们来讨论编写一个脚本的一般步骤。任何优秀的脚本都应该具有帮助和输入参数。写一个框架脚本(framework.sh),该脚本包含了大多数脚本需要的框架结构,是一个非常不错的主意。这样一来,当我们开始编写新脚本时,可以先执行如下命令:
cp framework.sh myscript
然后再插入自己的函数。
让我们来看看如下两个示例。
二进制到十进制的转换
脚本 b2d 将二进制数 (比如 1101) 转换为相应的十进制数。这也是一个用expr命令进行数学运算的例子:
#!/bin/sh
# vim: set sw=4 ts=4 et:
help()
{
cat < b2h -- convert binary to decimal
USAGE: b2h [-h] binarynum
OPTIONS: -h help text
EXAMPLE: b2h 111010
will return 58
HELP
exit 0
}
error()
{
# print an error and exit
echo "$1"
exit 1
}
lastchar()
{
# return the last character of a string in $rval
if [ -z "$1" ]; then
# empty string
rval=""
return
fi
# wc puts some space behind the output this is why we need sed:
numofchar=`echo -n "$1" | wc -c | sed 's/ //g' `
# now cut out the last char
rval=`echo -n "$1" | cut -b $numofchar`
}
chop()
{
# remove the last character in string and return it in $rval
if [ -z "$1" ]; then
# empty string
rval=""
return
fi
# wc puts some space behind the output this is why we need sed:
numofchar=`echo -n "$1" | wc -c | sed 's/ //g' `
if [ "$numofchar" = "1" ]; then
# only one char in string
rval=""
return
fi
numofcharminus1=`expr $numofchar "-" 1`
# now cut all but the last char:
rval=`echo -n "$1" | cut -b 0-${numofcharminus1}`
}
while [ -n "$1" ]; do
case $1 in
-h) help;shift 1;; # function help is called
--) shift;break;; # end of options
-*) error "error: no such option $1. -h for help";;
*) break;;
esac
done
# The main program
sum=0
weight=1
# one arg must be given:
[ -z "$1" ] && help
binnum="$1"
binnumorig="$1"
while [ -n "$binnum" ]; do
lastchar "$binnum"
if [ "$rval" = "1" ]; then
sum=`expr "$weight" "+" "$sum"`
fi
# remove the last position in $binnum
chop "$binnum"
binnum="$rval"
weight=`expr "$weight" "*" 2`
done
echo "binary $binnumorig is decimal $sum"
#
该脚本使用的算法是利用十进制和二进制数权值 (1,2,4,8,16,..),比如二进制"10"可以这样转换成十进制:
0 * 1 + 1 * 2 = 2
为了得到单个的二进制数我们是用了lastchar 函数。该函数使用wc –c计算字符个数,然后使用cut命令取出末尾一个字符。Chop函数的功能则是移除最后一个字符。
文件循环拷贝
你可能有这样的需求并一直都这么做:将所有发出邮件保存到一个文件中。但是过了几个月之后,这个文件可能会变得很大以至于该文件的访问速度变慢;下面的脚本 rotatefile 可以解决这个问题。这个脚本可以重命名邮件保存文件(假设为outmail)为outmail.1,而原来的outmail.1就变成了 outmail.2 等等...
#!/bin/sh
# vim: set sw=4 ts=4 et:
ver="0.1"
help()
{
cat < rotatefile -- rotate the file name
USAGE: rotatefile [-h] filename
OPTIONS: -h help text
EXAMPLE: rotatefile out
This will e.g rename out.2 to out.3, out.1 to out.2, out to out.1[BR]
and create an empty out-file
The max number is 10
version $ver
HELP
exit 0
}
error()
{
echo "$1"
exit 1
}
while [ -n "$1" ]; do
case $1 in
-h) help;shift 1;;
--) break;;
-*) echo "error: no such option $1. -h for help";exit 1;;
*) break;;
esac
done
# input check:
if [ -z "$1" ] ; then
error "ERROR: you must specify a file, use -h for help"
fi
filen="$1"
# rename any .1 , .2 etc file:
for n in 9 8 7 6 5 4 3 2 1; do
if [ -f "$filen.$n" ]; then
p=`expr $n + 1`
echo "mv $filen.$n $filen.$p"
mv $filen.$n $filen.$p
fi
done
# rename the original file:
if [ -f "$filen" ]; then
echo "mv $filen $filen.1"
mv $filen $filen.1
fi
echo touch $filen
touch $filen
这个脚本是如何工作的呢?在检测到用户提供了一个文件名之后,首先进行一个9到1的循环;文件名.9重命名为文件名.10,文件名.8重命名为文件名. 9……等等。循环结束之后,把原始文件命名为文件名.1,同时创建一个和原始文件同名的空文件(touch $filen)。
脚本调试
最简单的调试方法当然是使用echo命令。你可以在任何怀疑出错的地方用echo打印变量值,这也是大部分shell程序员花费80%的时间用于调试的原因。Shell脚本的好处在于无需重新编译,而插入一个echo命令也不需要多少时间。
shell也有一个真正的调试模式,如果脚本"strangescript"出错,可以使用如下命令进行调试:
sh -x strangescript
上述命令会执行该脚本,同时显示所有变量的值。
shell还有一个不执行脚本只检查语法的模式,命令如下:
sh -n your_script
这个命令会返回所有语法错误。
我们希望你现在已经可以开始编写自己的shell脚本了,尽情享受这份乐趣吧! :)