PUB:20150506 First Step Guide for Learning Shell Scripting

@GOLinux
This commit is contained in:
wxy 2015-06-08 11:38:07 +08:00
parent 7a1ebd4b15
commit 210c1637e5

View File

@ -1,4 +1,4 @@
Shell脚本学习初次操作指南 Shell脚本编程初体验
================================================================================ ================================================================================
![](http://blog.linoxide.com/wp-content/uploads/2015/04/myfirstshellscript.jpg) ![](http://blog.linoxide.com/wp-content/uploads/2015/04/myfirstshellscript.jpg)
@ -18,33 +18,33 @@ Linux世界中最为流行的shell脚本语言之一就是bash。而我认为
shell脚本语言就跟和几个人聊天类似。你只需把所有命令想象成能帮你做事的那些人只要你用正确的方式来请求他们去做。比如说你想要写文档。首先你需要纸。然后你需要把内容说给某个人听让他帮你写。最后你想要把它存放到某个地方。或者说你想要造一所房子因而你需要请合适的人来清空场地。在他们说“事情干完了”那么另外一些工程师就可以帮你来砌墙。最后当这些工程师们也告诉你“事情干完了”的时候你就可以叫油漆工来给房子粉饰了。如果你让油漆工在墙砌好前就来粉饰会发生什么呢我想他们会开始发牢骚了。几乎所有这些像人一样的命令都会说话如果它们完成了工作而没有发生什么问题那么它们就会告诉“标准输出”。如果它们不能做你叫它们做的事——它们会告诉“标准错误”。这样最后所有的命令都通过“标准输入”来听你的话。 shell脚本语言就跟和几个人聊天类似。你只需把所有命令想象成能帮你做事的那些人只要你用正确的方式来请求他们去做。比如说你想要写文档。首先你需要纸。然后你需要把内容说给某个人听让他帮你写。最后你想要把它存放到某个地方。或者说你想要造一所房子因而你需要请合适的人来清空场地。在他们说“事情干完了”那么另外一些工程师就可以帮你来砌墙。最后当这些工程师们也告诉你“事情干完了”的时候你就可以叫油漆工来给房子粉饰了。如果你让油漆工在墙砌好前就来粉饰会发生什么呢我想他们会开始发牢骚了。几乎所有这些像人一样的命令都会说话如果它们完成了工作而没有发生什么问题那么它们就会告诉“标准输出”。如果它们不能做你叫它们做的事——它们会告诉“标准错误”。这样最后所有的命令都通过“标准输入”来听你的话。
快速实例——当你打开linux终端并写一些文本时——你正通过“标准输入”和bash说话。那么让我们来问问bash shell **who am i**吧。 快速实例——当你打开linux终端并写一些文本时——你正通过“标准输入”和bash说话。那么让我们来问问bash shell **who am i(我是谁?)**吧。
root@localhost ~]# who am i <--- you speaking through the standard input to bash shell root@localhost ~]# who am i <--- 你通过标准输入对 bash shell
root pts/0 2015-04-22 20:17 (192.168.1.123) <--- bash shell answering to you through the standard output root pts/0 2015-04-22 20:17 (192.168.1.123) <--- bash shell通过标准输出回答你
现在让我们说一些bash听不懂的问题 现在让我们说一些bash听不懂的问题
[root@localhost ~]# blablabla <--- 你又在和标准输入说话了 [root@localhost ~]# blablabla <--- 你又在和标准输入说话了
-bash: blablabla: command not found <--- bash通过标准错误在发牢骚了 -bash: blablabla: command not found <--- bash通过标准错误在发牢骚了
”之前的第一个单词通常是向你发牢骚的命令。实际上,这些流中的每一个都有它们自己的索引号: :”之前的第一个单词通常是向你发牢骚的命令。实际上,这些流中的每一个都有它们自己的索引号LCTT 译注:文件句柄号)
- 标准输入(**stdin** - 0 - 标准输入(**stdin** - 0
- 标准输出(**stdout** - 1 - 标准输出(**stdout** - 1
- 标准错误(**stderr** - 2 - 标准错误(**stderr** - 2
如果你真的想要知道哪个输出命令说了些什么——你需要重定向(在命令后使用大于号“>”和流索引)那次发言到文件: 如果你真的想要知道哪个输出命令说了些什么——你需要将那次发言重定向(在命令后使用大于号“>”和流索引)文件:
[root@localhost ~]# blablabla 1> output.txt [root@localhost ~]# blablabla 1> output.txt
-bash: blablabla: command not found -bash: blablabla: command not found
在本例中我们试着重定向1**stdout**到名为output.txt的文件。让我们来看对该文件内容所做的事情吧使用cat命令可以做这事 在本例中,我们试着重定向1**stdout**到名为output.txt的文件。让我们来看对该文件内容所做的事情吧使用cat命令可以做这事
[root@localhost ~]# cat output.txt [root@localhost ~]# cat output.txt
[root@localhost ~]# [root@localhost ~]#
看起来似乎是空的。好吧现在让我们来重定向2**stderr** 看起来似乎是空的。好吧,现在让我们来重定向2**stderr**
[root@localhost ~]# blablabla 2> error.txt [root@localhost ~]# blablabla 2> error.txt
[root@localhost ~]# [root@localhost ~]#
@ -77,17 +77,17 @@ shell脚本语言就跟和几个人聊天类似。你只需把所有命令想象
rm: cannot remove `folder1': Is a directory rm: cannot remove `folder1': Is a directory
[root@localhost ~]# [root@localhost ~]#
正如我们所看到的,不同的流被分离到了不同的文件。有时候,这也不很方便,因为我们想要查看出现错误时,在某些操作前面或后面所连续发生的事情。要实现这一目的,我们可以重定向两个流到同一个文件: 正如我们所看到的,不同的流被分离到了不同的文件。有时候,这也不很方便,因为我们想要查看出现错误时,在某些操作前面或后面所连续发生的事情。要实现这一目的,我们可以重定向两个流到同一个文件:
command >>out_err.txt 2>>out_err.txt command >>out_err.txt 2>>out_err.txt
注意:请注意,我使用“>>”替代了“>”。它允许我们附加到文件,而不是覆盖文件。 注意:请注意,我使用“>>”替代了“>”。它允许我们附加到文件,而不是覆盖文件。
我们可以重定向一个流到另一个: 我们可以重定向一个流到另一个:
command >out_err.txt 2>&1 command >out_err.txt 2>&1
让我来解释一下吧。所有命令的标准输出将被重定向到out_err.txt错误输出将被重定向到1-st流(上面已经解释过了),而该流会被重定向到同一个文件。让我们看这个实例: 让我来解释一下吧。所有命令的标准输出将被重定向到out_err.txt错误输出将被重定向到1上面已经解释过了而该流会被重定向到同一个文件。让我们看这个实例
[root@localhost ~]# rm -fv folder2 file2 >out_err.txt 2>&1 [root@localhost ~]# rm -fv folder2 file2 >out_err.txt 2>&1
[root@localhost ~]# cat out_err.txt [root@localhost ~]# cat out_err.txt
@ -127,7 +127,7 @@ shell脚本语言就跟和几个人聊天类似。你只需把所有命令想象
如果你打算grep一些双引号引起来带有空格的内容呢 如果你打算grep一些双引号引起来带有空格的内容呢
注意: fdisk命令显示关于Linux操作系统磁盘驱动器的信息 注意fdisk命令显示关于Linux操作系统磁盘驱动器的信息
就像我们看到的,这种方式很不方便,因为我们不一会儿就把临时文件空间给搞乱了。要完成该任务,我们可以使用管道。它们允许我们重定向一个命令的**stdout**到另一个命令的**stdin**流: 就像我们看到的,这种方式很不方便,因为我们不一会儿就把临时文件空间给搞乱了。要完成该任务,我们可以使用管道。它们允许我们重定向一个命令的**stdout**到另一个命令的**stdin**流:
@ -147,11 +147,11 @@ shell脚本语言就跟和几个人聊天类似。你只需把所有命令想象
正如我们所知道的通常与shell的交流以及shell内的交流是以对话的方式进行的。因此让我们创建一些真正的脚本吧这些脚本也会和我们讲话。这会让你学到一些简单的命令并对脚本的概念有一个更好的理解。 正如我们所知道的通常与shell的交流以及shell内的交流是以对话的方式进行的。因此让我们创建一些真正的脚本吧这些脚本也会和我们讲话。这会让你学到一些简单的命令并对脚本的概念有一个更好的理解。
假设我们是某个公司的总服务台经理我们想要创建某个shell脚本来注册呼叫信息电话号码、用户名以及问题的简要描述。我们打算把这些信息存储到普通文本文件data.txt中以便今后统计。脚本它自己就是以对话的方式工作这会让总服务台的工作人员的小日子过得轻松点。那么首先我们需要显示问题。对于现实信息我们可以用echo和printf命令。这两个都是用来显示信息的但是printf更为强大因为我们可以通过它很好地格式化输出我们可以让它右对齐、左对齐或者为信息留出专门的空间。让我们从一个简单的例子开始吧。要创建文件请使用你喜欢的文本编辑器katenanovi……然后创建名为note.sh的文件里面写入这些命令 假设我们是某个公司的总服务台经理我们想要创建某个shell脚本来注册呼叫信息电话号码、用户名以及问题的简要描述。我们打算把这些信息存储到普通文本文件data.txt中以便今后统计。脚本它自己就是以对话的方式工作这会让总服务台的工作人员的小日子过得轻松点。那么首先我们需要显示提问。对于显示信息我们可以用echo和printf命令。这两个都是用来显示信息的但是printf更为强大因为我们可以通过它很好地格式化输出我们可以让它右对齐、左对齐或者为信息留出专门的空间。让我们从一个简单的例子开始吧。要创建文件请使用你惯用的文本编辑器katenanovi……然后创建名为note.sh的文件里面写入这些命令
echo "Phone number ?" echo "Phone number ?"
### Script执行 ### ### 如何运行/执行脚本? ###
在保存文件后我们可以使用bash命令来运行把我们的文件作为它的参数 在保存文件后我们可以使用bash命令来运行把我们的文件作为它的参数
@ -176,7 +176,7 @@ shell脚本语言就跟和几个人聊天类似。你只需把所有命令想象
[root@localhost ~]# ./note.sh [root@localhost ~]# ./note.sh
Phone number ? Phone number ?
在脚本名前,我添加了./组合。.(点在unix世界中意味着当前位置当前文件夹/斜线是文件夹分隔符。在Windows系统中我们使用\(反斜线)实现同样功能所以这整个组合的意思是说“从当前文件夹执行note.sh脚本”。我想如果我用完整路径来运行这个脚本的话你会更加清楚一些 在脚本名前,我添加了 ./ 组合。.(点在unix世界中意味着当前位置当前文件夹/斜线是文件夹分隔符。在Windows系统中我们使用反斜线 \ 表示同样功能所以这整个组合的意思是说“从当前文件夹执行note.sh脚本”。我想如果我用完整路径来运行这个脚本的话你会更加清楚一些
[root@localhost ~]# /root/note.sh [root@localhost ~]# /root/note.sh
Phone number ? Phone number ?
@ -184,7 +184,7 @@ shell脚本语言就跟和几个人聊天类似。你只需把所有命令想象
它也能工作。 它也能工作。
如果所有linux用户都有相同的默认shell那就万事OK。如果我们只是执行该脚本默认的用户shell就会用于解析脚本内容并运行命令。不同的shell有着一丁点不同的语法、内部命令等等,所以,为了保证我们的脚本会使用**bash**,我们应该添加**#!/bin/bash**到文件首行。这样默认的用户shell将调用**/bin/bash**,而只有在那时候,脚本中的命令才会被执行: 如果所有linux用户都有相同的默认shell那就万事OK。如果我们只是执行该脚本默认的用户shell就会用于解析脚本内容并运行命令。不同的shell的语法、内部命令等等有着一丁点不同,所以,为了保证我们的脚本会使用**bash**,我们应该添加**#!/bin/bash**到文件首行。这样默认的用户shell将调用**/bin/bash**,而只有在那时候,脚本中的命令才会被执行:
[root@localhost ~]# cat note.sh [root@localhost ~]# cat note.sh
#!/bin/bash #!/bin/bash
@ -194,13 +194,13 @@ shell脚本语言就跟和几个人聊天类似。你只需把所有命令想象
### 读取输入 ### ### 读取输入 ###
现实信息后,脚本会等待用户回答。那儿有个**read**命令用来接收用户的回答: 显示信息后,脚本会等待用户回答。有个**read**命令用来接收用户的回答:
#!/bin/bash #!/bin/bash
echo "Phone number ?" echo "Phone number ?"
read phone read phone
在执行后,脚本会等待用户输入,直到用户按[ENTER]键: 在执行后,脚本会等待用户输入,直到用户按[ENTER]键结束输入
[root@localhost ~]# ./note.sh [root@localhost ~]# ./note.sh
Phone number ? Phone number ?
@ -220,7 +220,7 @@ shell脚本语言就跟和几个人聊天类似。你只需把所有命令想象
You have entered 123456 as a phone number You have entered 123456 as a phone number
[root@localhost ~]# [root@localhost ~]#
在**bash** shell中我们使用**$**(美元)符号作为变量标示,除了读入到变量和其它为数不多的时候(将在今后说明)。 在**bash** shell中一般我们使用**$**(美元)符号来表明这是一个变量,除了读入到变量和其它为数不多的时候才不用这个$(将在今后说明)。
好了,现在我们准备添加剩下的问题了: 好了,现在我们准备添加剩下的问题了:
@ -244,7 +244,7 @@ shell脚本语言就跟和几个人聊天类似。你只需把所有命令想象
太完美了剩下来就是重定向所有东西到文件data.txt了。作为字段分隔符我们将使用/(斜线)符号。 太完美了剩下来就是重定向所有东西到文件data.txt了。作为字段分隔符我们将使用/(斜线)符号。
**注意** 你可以选择任何你认为是最好,但是确保文件内容不会包含这些符号在内它会导致在文本行中产生额外字段。 **注意** 你可以选择任何你认为是最好的分隔符,但是确保文件内容不会包含这些符号在内,否则它会导致在文本行中产生额外字段。
别忘了使用“>>”来代替“>”,因为我们想要将输出内容附加到文件末! 别忘了使用“>>”来代替“>”,因为我们想要将输出内容附加到文件末!
@ -262,7 +262,7 @@ shell脚本语言就跟和几个人聊天类似。你只需把所有命令想象
987/Jimmy/Keybord issue. 987/Jimmy/Keybord issue.
[root@localhost ~]# [root@localhost ~]#
**注意** **tail**命令显示了文件的最后**-n**行。 **注意** **tail**命令显示了文件的最后**n**行。
搞定。让我们再来运行一次看看: 搞定。让我们再来运行一次看看:
@ -285,7 +285,7 @@ shell脚本语言就跟和几个人聊天类似。你只需把所有命令想象
[root@localhost ~]# date "+%Y.%m.%d %H:%M:%S" [root@localhost ~]# date "+%Y.%m.%d %H:%M:%S"
2015.04.23 21:33:18 <---- 格式化后的输出 2015.04.23 21:33:18 <---- 格式化后的输出
有几种方式可以读取命令输出到变脸,在这种简单的情况下,我们将使用`(反引号): 有几种方式可以读取命令的输出到变量,在这种简单的情况下,我们将使用`反引号,不是单引号,和波浪号~在同一个键位
[root@localhost ~]# cat note.sh [root@localhost ~]# cat note.sh
#!/bin/bash #!/bin/bash
@ -320,7 +320,7 @@ shell脚本语言就跟和几个人聊天类似。你只需把所有命令想象
你可以直接从控制台查找到各个命令的大量有趣的信息,只需输入:**man read, man echo, man date, man ……** 你可以直接从控制台查找到各个命令的大量有趣的信息,只需输入:**man read, man echo, man date, man ……**
同意吗?它看上去是多了! 同意吗?它看上去是舒服多了!
[root@localhost ~]# ./note.sh [root@localhost ~]# ./note.sh
Phone number: 321 Phone number: 321
@ -331,9 +331,9 @@ shell脚本语言就跟和几个人聊天类似。你只需把所有命令想象
2015.04.23 21:43:50/321/Susane/Mouse was stolen 2015.04.23 21:43:50/321/Susane/Mouse was stolen
[root@localhost ~]# [root@localhost ~]#
光标在消息的后面(不是在新的一行中),这有点意思。 光标在消息的后面(不是在新的一行中),这有点意思。LCTT 译注:如果用 echo 命令输出显示的话,可以用 -n 参数来避免换行。)
循环 ### 循环 ###
是时候来改进我们的脚本了。如果用户一整天都在接电话,如果每次都要去运行,这岂不是很麻烦?让我们让这些活动都永无止境地循环去吧: 是时候来改进我们的脚本了。如果用户一整天都在接电话,如果每次都要去运行,这岂不是很麻烦?让我们让这些活动都永无止境地循环去吧:
@ -348,7 +348,7 @@ shell脚本语言就跟和几个人聊天类似。你只需把所有命令想象
echo "$now/$phone/$name/$issue">>data.txt echo "$now/$phone/$name/$issue">>data.txt
done done
我已经交换了**read phone**和**now=`date`**行。这是因为我想要在输入电话号码后再获得时间。如果我把它放在循环**- the**的首行变量就会在数据存储到文件中后获得时间。而这并不好因为下一次呼叫可能在20分钟后甚至更晚。 我已经交换了**read phone**和**now=`date`**行的位置。这是因为我想要在输入电话号码后再获得时间。如果我把它放在循环的首行,那么循环一次后,变量 now 就会在数据存储到文件中后马上获得时间。而这并不好因为下一次呼叫可能在20分钟后甚至更晚。
[root@localhost ~]# ./note.sh [root@localhost ~]# ./note.sh
Phone number: 123 Phone number: 123
@ -365,11 +365,11 @@ shell脚本语言就跟和几个人聊天类似。你只需把所有命令想象
2015.04.23 21:48:16/777/Daniel/I broke my monitor 2015.04.23 21:48:16/777/Daniel/I broke my monitor
[root@localhost ~]# [root@localhost ~]#
注意: 要从无限循环中退出,你可以按[Ctrl]+[C]键。Shell会显示^表示Ctrl键。 注意: 要从无限循环中退出,你可以按[Ctrl]+[C]键。Shell会显示\^表示Ctrl键。
### 使用管道重定向 ### ### 使用管道重定向 ###
让我们添加更多功能到我们的“弗兰肯斯坦”我想要脚本在每次呼叫后显示某个统计数据。比如说我想要查看各个号码呼叫了我几次。对于这个我们应该cat文件data.txt 让我们添加更多功能到我们的“弗兰肯斯坦Frankenstein我想要脚本在每次呼叫后显示某个统计数据。比如说我想要查看各个号码呼叫了我几次。对于这个我们应该cat文件data.txt
[root@localhost ~]# cat data.txt [root@localhost ~]# cat data.txt
2015.04.23 21:38:56/123/Jim/Script hanging. 2015.04.23 21:38:56/123/Jim/Script hanging.
@ -453,7 +453,7 @@ via: http://linoxide.com/linux-shell-script/guide-start-learning-shell-scripting
作者:[Petras Liumparas][a] 作者:[Petras Liumparas][a]
译者:[GOLinux](https://github.com/GOLinux) 译者:[GOLinux](https://github.com/GOLinux)
校对:[校对者ID](https://github.com/校对者ID) 校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创翻译,[Linux中国](https://linux.cn/) 荣誉推出 本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创翻译,[Linux中国](https://linux.cn/) 荣誉推出