设为首页 收藏本站
查看: 703|回复: 0

认识shell-2

[复制链接]

尚未签到

发表于 2018-8-24 12:40:41 | 显示全部楼层 |阅读模式
  我们之所以要进行测试或比对﹐主要是用来做判断的﹕假如测试或比对成立﹐那就返回一个' 真实(true) '否则返回' 虚假(false) '。也就是说﹕如果条件成立那么就会如何如何﹔如果条件不成立又会如何如何﹐从而让script有所'智慧'。基本上﹐我们的程式之所以那么聪明﹐都是从这些简单到复杂的判断开始的。
  比方说﹐上面的-a (AND) 和-o (OR) 是用来测试两个条件﹕A 和B 。如果使用test A -a B ﹐那么A 和B 都必须成立那条件才成立﹔如果使用test A -o B ﹐那么只要A 或B 成立那条件就成立。至于其它的比对和测试﹐应该更好理解吧﹖
  另外﹐还有一个特殊符号﹕“ ! ”您可不能不会运用。它是'否'的意思﹐例如﹕"! -f"是非档案﹔ "-ne"和"! -eq"都是'不等于'的意思。
  我们在命令行上面已经知道如何定义和改变一个变数﹐那在shell script 里面就更是司空见惯了。而且﹐越会利用变数﹐您的script 能力就越高。在shell script 中所定义的变数有更严格的定义﹕
  

标签
代表意思
-a
定义为阵列(array) 变数
-f
仅定义功(function) 能名称。
-i
定义为整数。
-r
定义为唯独变数。
-x
透过环境输出变数。  我们除了用“ = ”来定义变数之外﹐还可以用declare命令来明确定义变数。例如﹕

# A=3 B="-2"  
# RESULT=$A*$B
  
# echo $RESULT
  
3*-2
  
# declare -i A=3 B="-2"
  
# declare -i RESULT=$A*$B
  
# echo $RESULT
  
-6
  您这里会发现﹕如果没有使用declare 命令将变数定义为整数的话﹐那么A 和B 的变数值都只是字串而已。
  您现在已经知道什么是变数﹑如何定义变数﹑什么是字串﹑如何比对和测试字串和档案﹐这些都是script 的基本技巧。写一些简单的script 应该不成问题了﹐例如在家目录写一个test.sh ﹐其内容如下﹕

  

      1 #!/bin/bash       2 # Purpose: a simple test shell script.       3 # Author: netman        4 # Date: 2001/08/17       5 # Version: 0.01       6       7 CHK_FILE=~/tmp/test.sh       8       9 if [ ! -e $CHK_FILE ]      10 then      11 echo "$0: Error: '$CHK_FILE' is not found." ; exit 1      12      13 elif [ -d $CHK_FILE ]; then      14 echo -n "​​$CHK_FILE is a directory, and you can "      15 test -x $CHK_FILE || echo -n "​​NOT "      16 echo "search it."      17 exit 2      18      19 elif [ -f $CHK_FILE ]; then      20 echo "$CHK_FILE is a regular file."      21 test -r $CHK_FILE && echo "You can read it."      22 test -x $CHK_FILE && echo "You can execute it."      23 test -w $CHK_FILE && echo "You can write to it."      24 test -s $CHK_FILE || echo "However, it is empty."      25 exit 0      26      27 else      28 echo "$CHK_FILE is a special file."      29 exit 3      30      31 fi  

  


(注意﹕我目前用vi 编辑﹐并用:set nu 将行数显示出来﹐实际的命令行是没有行数的。)  先让我们看第一行﹕#!/bin/bash﹐就是定义出bash 是这个script 的command interpreter 。
  然后是一些注解﹐说明了这个script 的用途﹑作者﹑日期﹑版本﹐等资讯。
  在注解之后﹐第7 行才是script 的真正开始﹕首先定义出一个变数CHK_FILE ﹐目前内容是家目录中tmp 子目录的test.sh 档案。
Tips﹕事实上﹐这个定义比较有局限﹐如果您想改良这个设计﹐可以将这行(第7行)换成下面数行﹕  

if [ -z $1 ]  then echo "Syntax Erro! Usage: $0 " ; exit 5  else CHK_FILE=$1  fi  

  

  第一行是开始一个if 的判断命令﹐它一定要用一个fi 命令来结束(您可以在最后一行找到它)﹔然后在if 和fi 之间必须有一个then 命令。这是典型的if-then-fi 逻辑判断﹕如果某某条件成立﹐然后如何如何﹔还有if-then-else-fi 判断﹕如果某某条件成立﹐然后如何如何﹐否则如何如何﹔另外﹐也有if-then-elif-then-else-fi 判断﹕如果某某成立﹐然后如何如何﹔否则﹐再如果某某成立﹐然后如何如何﹔如果还是不成立﹐那就如何如何。
  上面那几行﹐主要目的是将CHK_FILE这个变数值定义为$1。嗯﹖ 您或许会问$1是什么啊﹖ 那是当您执行这个script的时候所输入的第一个参数 ﹔而 $0则是script 命令行本身。所以﹐这里是先判断一下$1是否为空的( -z )﹐然则(then)﹐告诉您语法错误﹐并告诉您正确的格式﹐同时退出﹐并返回一个状态值(后面再谈)﹔否则( else)﹐就将CHK_FILE定义为$1。

  接下来第9 行﹐您可以将"if [ ! -e $CHK_FILE ]" 换成"if test ! -e $CHK_FILE " ﹐意思都是一个测试。但如果用[ ] 的话有一个地方要注意﹕"[ " 的右边必须保留一个空白﹔" ]" 的左边必须保留一个空白。
  在目前这个script 中﹐判断逻辑如下﹕


  • 先检查$CHK_FILE (也就是~/tmp/test.sh这个档)是否存在( ! -e )﹐如果( if )条件成立﹐那就参考then里面的命令﹔否则参考下面elif或else。
  • 如果上一步骤成立﹐也就是~/tmp/test.sh不存在﹐然则用echo命令告诉您不能读取这个档﹐并同时返回父程式一个返回状态 (还记得我们在前面提到过的$?变数吗﹖)﹐这里为1。在script中﹐任何时候执行exit的话﹐就会离开script﹐不管后面是否还有其它命令行或判断。因为我将这里echo和exit写在同一行﹐所以用一个" ; "符号分隔开来﹐否则﹐您可以将exit写在下一行。
  • 接下来( 13 行)是一个elif ﹐就是else if 的意思﹐也就是说﹕如果上一个if 不成立﹐然后在这里再做另外一个if 测试。这里是继续检查这个档是否为一个目录( -d )﹐然则﹐告您它是一个目录﹐并同时尝试告诉您是否能对这个目录进行搜索。  然后看看下一行( 15 行)动内容﹐请留意上一个echo 和这个echo﹐都带有一个-n 的参数﹐意思是在显示信息的时候不进行断行( newline )的动作﹐所以﹐和下面那行合在一起(共3 行script )才是真实显示的内容。这里再进行一个测试﹕看看您对这个目录是否具有-x 权限﹐否则会在"and you can" 和"search it." 之间加上一个"NOT"﹐如果有权限就不出现这个NOT 。
      这里﹐我们没有用if-then来判断﹐而是直接用“ || ” ( OR )来做判断﹕非此即彼。这在一些简单的判断中非常好用﹐尤其对懒人来说﹐因为不用打太多的字﹔但功能就比较有限﹕判断之后只能执行一个命令而已。除了​​||之外﹐您也可以用“ && ”( AND )做判断﹐套句Jack的名言﹕You jump I jump。所以﹐这句也可以换成﹕
      
    test ! -x $CHK_FILE && echo -n "NOT " (粗体字是修改部份)。
      最后﹐根据目前这个elif 条件所进行的所有命令都执行完毕﹐并退出这个script﹐同时设定返回状态为2 。

  • 再下来( 19 行)是另一个elif ﹐也就是说﹕如果连上一个elif 也不成立的话﹐那这里继续检查这个档是否是一个常规档案( -f )﹐然则﹐告诉您是一个常规档案﹐然后﹐接连进行三个测试﹐分别测试您是否具有-r﹑-x﹑-w 的权限﹐有的话﹐分别告诉您相关的可行性。最后还检查这个档案的长度是否超过0 ( -s )﹐否则告诉您它是一个空档。完成这些判断之后﹐就退出script﹐并返回一个为0 的状态。
  • 然后( 27 行)是一个else﹐意思是如果上面的所有if 和elif 都不成立﹐那就看这里的。也就是说﹕这个档案是存在的﹐但不是目录﹐也不是常规档案﹐那它就是一个特殊档。然后退出script﹐并设定返回状态为3。  在这个范例中﹐script 一共有0﹑1﹑2﹑3 这四个返回状态﹐根据这个返回值( $? )﹐我们就可以得知检查的档案究竟是一个常规档﹑还是不存在﹑还是目录﹑还是特殊档。

  • 最后﹐再没有其它动作了﹐就结束这个if 判断。
  目前这个script 仅提供一些script 概念给您而已﹐例如﹕定义和使用变数﹑if-then-else-fi 判断式﹑条件测试﹑逻辑关系﹑退出状态﹑等等。同时﹐这个范例也提供了一些基本的script 书写惯例﹕用不同的缩排来书写不同的判断或回圈。例如这里一共有两个if-then-else-fi 判断﹐第一个if﹑then﹑else﹑fi 都没有缩排﹐然后﹐紧接这些命令后面的叙述就进行缩排﹔当碰到第二层的if-then-else-fi 的时候﹐也如此类推。事实上﹐并非一定如此写法﹐但日后如果您的程式越写越长﹐您自然会这样安排的啦~~
  刚才我们认识了一个if-then-else-fi 的判断﹐事实上﹐在script 的应用上﹐还有其它的许多判断技巧﹐在我们开发更强大和复杂的script 之前﹐不妨先认识一下﹕

case格式﹕  

case string in  pattern ) commands ;; esac  

  

  它能根据不同的字串来做相应的动作﹐不如用例子来说好了﹕

  

      1 #!/bin/bash       2 # Purpose: a simple test shell script.       3 # Author: netman        4 # Date: 2001/08/20       5 # Version: 0.02       6       7        8 echo Please pick a number:       9 echo " "a, To show the local time.      10 echo " "b, To list current directory.      11 echo " "c, To see who is on the machine.      12 echo -n "​​Your choice: "      13      14 read choice      15      16 case $choice in       17                  a | A) echo -n "The local time is "      18 date ;;       19                  b | B) echo "The current directory is $PWD " ;;       20                  c | C) echo "There are following users on the machine:"      21 who ;;       22                  *) echo "Your choice is an invalid option." ;;       23 esac  

  

  这个script 是先请您选择a﹑b﹑c 字母﹐再用read 命令从键盘读入choice 的变数值﹐然后将这个变数应用在case 判断中﹕


  • 如果是a 或A﹕执行date 命令﹔
  • 如果是b 或B﹕用$PWD 这个环境变数显示当前目录﹔
  • 如果是c 或C﹕则执行who 命令﹔
  • 如果是其它( * ) ﹕则告诉您invalid 。
  不知道您是否有注意到﹕每一个case 的选项﹐都用一个" ) " 作指引﹐然后﹐在这个case 最后一个命令完成以后﹐一定要用" ;; " 来结束。最后﹐还必须用case 的倒写esac 来关闭这个判断。


for格式﹕  

for item in list  do commands done  

  

  当您需要重复处理一些事物的时候﹐for 回圈就非常好用了。它通常用来重复处理一些列表( list ) 中的事物﹐比方说您有一个变数﹐里面包含着一串列表﹐那么回圈会一个接一个的进行处理﹐直到最后一个处理完毕之后才退出。不如又用一个范例来说明好了﹕

  

      1 #!/bin/bash       2 # Purpose: a simple test shell script.       3 # Author: netman        4 # Date: 2001/08/21       5 # Version: 0.03       6       7       8 if [ -z "$1" ] || [ -z "$2" ] ; then       9 echo "Syntax Error: Usage ${0##*/}  "      10 exit 1      11 fi      12 if [ ! -d $2 ]; then      13 echo "${0##*/} : Error: $2 is not a directory."      14 exit 2      15 fi      16 TWORD="$1"      17 TDIR="$2"      18 TFILE=`grep -r "$TWORD" "$TDIR" | cut -d ':' -f1 | uniq`      19      20 if [ ! -z "$TFILE" ]; then      21 echo "You can find $TWORD in following file(s):"      22          for i in $TFILE ; do      23 echo $i      24          done      25 exit 0      26 else      27 echo "Could not find $TWORD in any file under $TDIR."      28 exit 3      29 fi  

  

  这个script 是在一个目录下面搜索档案﹐如果档案里面发现有指定的文字﹐就将档案的名称列出来。它必须要抓两个变数﹕TWORD 和TDIR ﹐这两个变数分别为script 的第1 个和第2 个参数。
  一开始要检查命令行是否有两个变数﹐用-z $1 和-z $1 来测试﹐如果它们其一没有指定﹐就告诉您语法错误﹐同时退出(返回值为1 ) 。然后再检查$2 是否为目录﹐如果不是目录﹐就也提出警告﹐并退出(返回值为2 )。如果通过上面两道检查﹐然后用命令grep﹑cut﹑uniq﹐将档案抓出来。注意﹕这就是for 回圈需要检查的列表。
  然后会检查列表是否有内容﹐如果有的话﹐那就用for 回圈来重复显示列表里面的所有项目﹔一次一个﹐直到列表最后一个项目也处理完毕。这就是一个for 回圈的基本运作方式了。如果列表没有被建立起来﹐那就告诉您找不到您指定的文字﹐并退出(返回值为3 )。

while格式﹕  

while condition do commands done  

  

  这个回圈应该蛮容易理解的﹕当条件成立的时候﹐就一直重复﹐直到条件消失为止。我们不妨改良前面的case 那个script 看看﹕

  

      1 #!/bin/bash       2 # Purpose: a simple test shell script.       3 # Author: netman        4 # Date: 2001/08/21       5 # Version: 0.02.1       6       7        8 while [ "$choice" != "x" ]; do       9 echo      10 echo Please pick a number:      11 echo " "a, To show the local time.      12 echo " "b, To list current directory.      13 echo " "c, To see who is on the machine.      14 echo " "x, To exit.      15 echo -n "​​Your choice: "      16      17 read choice      18 echo      19      20 case $choice in      21 a) echo -n "​​The local time is "      22 date ;;      23 b) echo "The current directory is $PWD ";;      24 c) echo "There are following users on the machine:"      25 who ;;      26 x) echo "Bye bye..."; exit 0 ;;      27 *) echo "Your choice is an invalid option." ;;      28 esac      29 done  

  

  首先﹐我们用whil​​e 进行应该条件判断﹕如果$choice 的变数值不等于x 的话﹐那就重复回圈﹐直到遇到x (条件消失)为止。那么这个script 会一直提示您键入选项﹐然后进行处理﹐直到您按x 键才会结束。


until格式﹕  

until condition do commands done  

  

  这个until 刚好和while 相反﹕如果条件不成立就一直重复回圈﹐直到条件成立为止。如果继续引用上例﹐只需将while 的条件设为相反就可以了﹕

  

修改前﹕       8 while [ "$choice" != "x" ]; do  
修改后﹕       8 until [ "$choice" = "x" ]; do
  

  

  没错﹕就是这么简单﹗


sub function格式﹕  

function function_name { commands }  
或﹕
  
function_name () { commands }
  

  

  当您在一个script 中﹐写好了段可以用来处理特定条件的程式之后﹐或许后面会重复用到。当然﹐您可以重复写这些句子﹐但更便利的办法是﹕将这些重复性的句子做成sub function。如果您有模组的概念﹐那就是将一些能够共享的程式做成模组﹐然后提供给需要用到此功能的其它程式使用。说实在﹐看一个程式撰写人的模组化程度﹐也就能看得出这个人的程式功力。
  我们不妨写一个script 来显示机器目前所使用的网路卡界面资讯﹐看看里面的sub function 是怎么运用的﹕

  

      1 #!/bin/bash       2 # Purpose: a simple test shell script.       3 # Author: netman        4 # Date: 2001/08/21       5 # Version: 0.04       6       7        8 # function 1: to get interface.       9 getif () {      10 until [ "$CHKIFOK" = "1" ] || [ "$GETNONE" = "1" ]; do      11 echo -n "​​The interface (ethX) for $CHKNET network [Enter for none]: "      12 read CHKIF      13 if [ -z "$CHKIF" ]; then      14 echo      15 echo "There is no interface for $CHKNET network."      16 echo      17 GETNONE=1      18 else      19              chkif  # invoke the second function      20 fi      21 done      22 }      23      24 # function 2: to check interface.      25 chkif () {      26 TESTIF=`/sbin/ifconfig $CHKIF | grep "inet add"`      27 if [ -z "$TESTIF" ]; then      28 echo ""      29 echo "ERROR: Could not find interface '$CHKIF' on your machine!"      30 echo " Please make sure $CHKIF has been set up properly."      31 echo ""      32 return 1      33 else      34 CHKIFOK=1      35          getip # invoke the third function      36 return 0      37 fi      38 }      39      40 # function 3: to get ip.      41 getip () {      42 CHKIP=`ifconfig $CHKIF | grep "inet addr" | tr -s ' ' ' ' \      43 | cut -d ' ' -f3 | cut -d ':' -f2`      44 CHKMASK=`ifconfig $CHKIF | grep "inet addr" | tr -s ' ' ' ' \      45 | cut -d ' ' -f5 | cut -d ':' -f2`      46 echo      47 echo "The interface of $CHKNET network is $CHKIF using $CHKIP/$CHKMASK."      48 echo      49 return 0      50 }      51      52 # start of main body      53 for CHKNET in EXTERNAL INTERNAL DMZ ; do      54      getif # invoke the first function      55 unset GETNONE      56 unset CHKIFOK      57 done  

  

  在这个script 中﹐目前有三个sub function﹕


  • getif ()﹕这里用until回圈从键盘那里读入指定的网路卡。如果直接按Enter表示没有界面﹐然则﹐回报一个信息﹐并将GETNONE变数设定为1 ﹐同时退出这个function﹔否则﹐执行下一个function 。
  • chkif ()﹕当上一个function顺利读入网路卡名称之后﹐会检查这个界面是否存在。这里是用/sbin/ifconfig和grep来检查﹐如果命令结果抓不到IP位址﹐表示这张卡还没设定好﹐然则﹐回报一个错误信息﹐并退出function﹐返回状态为1 ﹔否则﹐执行下一个function﹐然后退出function﹐返回状态为0。  (注意﹕这里的function 有使用return 退出以及设定返回状态﹔但上一个function 没有使用retuen﹐是因为getif () 有使用until 回圈﹐如果那里用return 的话﹐就会打断until 回圈。)

  • getip ()﹕当上一个function通过界面检测之后﹐就将界面的IP和netmask抓出来﹐同时告诉您相关的网路资讯﹐最后退出function﹐返回状态为0。
  当所有sub function 都定义完毕之后﹐接下来就是main body 的开始。这里用一个for 回圈﹐分别对EXTERNAL﹑INTERNAL﹑和DMZ 网路进行检查﹐执行第一function 就开始一连串的动作了。因为sub function 里面的变数会重复使用﹐所以﹐在每次使用过其中的功能之后﹐要将某些影响下一个判断的变数清空﹐用unset 命令即可。

  事实上﹐用在script 上面的回圈有非常多的变化﹐恐怕我也没此功力为大家一一介绍。还是留待您自己去慢慢摸索了。
  Regular Expression
  常规表示式(RE -- Regular Expression) 应该是所有学习程式的人员必须具备的基本功夫。虽然﹐我的程式能力很差﹐而且这里的文章也不是以程式为主﹐不过﹐在日后的管理生涯当中﹐如果会运用RE 的话﹐将令许多事情都时半功倍﹐同时也让您在管理过程中如虎添翼。下面﹐我们只接触最基本的RE 常识﹐至于进阶的技巧﹐将留给有兴趣的朋友自己发挥。
  首先﹐不妨让我们认识最基本的RE 符号﹕
  

符号
代表意思
范例
^
句子前端
"^dear" ﹕句子必须以dear 开头。
$
句子末端
"dear$"﹕句子必须以dear 结尾﹔"^$" ﹕空白行。
\
跳脱字符
"\\" ﹕\ 符号本身﹔"\." ﹕小数点﹔"\ " ﹕空白键。
.
任何单元字符
".ear" : 可以是dear, bear, tear﹐但不能是ear 。
?
前一个RE 出现0 次或1 次  "^[0-9]?$" ﹕ 空白行或只含1 个数字的字行。

*
前一个RE 可出现0 次或多次  "^.*" ﹕所有字行﹔
  "^[0-9][0-9]*$" ﹕ 含一或多个数字的字行。

+
前一个RE 可出现1 次或多次  "^[0-9][0-9]+$" ﹕ 含两个或多个数字的字行。

\{n\}
接在前一字符的n 个相同范围字符
"^[0-9]\{3\}[^0-9]" ﹕句子开头连续3 个数字﹐然后是一个非数字。
\{n,\}
接在前一字符的最少n 个相同范围的字符
"^[0-9]\{3,\}" ﹕句子开头最少要有连续3 个数字。
\{n,m\}
接在前一字符的n 到m 个相同范围的字符
"^[0-9]\{3,5\}" ﹕句子开头连续3 或5 个数字。

    列表中任何单元字符
    "t[ear]." ﹕可以是tea, tar, try ﹐但不能是tim 。
    [range]
    范围中任何单元字符
    "t[er]." ﹕可以是tea, tim, try ﹐但不能是tar 。
    [^range]
    任何不在范围中的单一字符
    "t[^er]." ﹕可以是tar﹐但不能是tea, tim, try。  通常﹐我们用来处理RE的程式有grep﹑egrep﹑sed﹑awk﹑vi﹑等等﹐各程式的语法和功能都相差很多﹐需要详细研究过才能摸熟。在某些程式中﹐例如egrep和awk﹐还可以处理某些延伸字符﹐例如﹕" | "是两个RE的或一关系﹔" ( )"可用来组合多个RE ﹔等等。有兴趣的话﹐网路上都有许多资料可以找得到﹐例如网站龙门少尉的窝的「正规表示式的入门与应用」等系列文章。
      sed & awk
      许多人提到RE的时候﹐都少不了介绍一下sedawk这对宝贝﹐它们都可以用来处理字串﹐但处理手法上却有所不同。有人说用sed对'字行'为单位的处理比较方便﹔而awk则在列表处理上面有独到的神通。是否如此﹐大家不妨自己玩玩看啰。
      让我们先看看sed 这个程式﹐它的命令语法有点类型vi 里面的编辑功能﹕


    • 以单一字母来做命令名称﹔
    • 命令所需的参数置于命令之后﹔
    • 您可以将行数或RE 置于命令之前﹐以特指命令要处理的对象。
      关于sed 的常用命令﹐请参考下表﹕
      

    命令
    语法
    说明
    a
    a\ string
    在字行后面增加特定字串(新行)。
    c
    c\ string
    将字行换成特定字串。
    d
    d
    删除字行。
    i
    i\ string
    在字行前面插入特定字串(新行)。
    p
    p
    显示字行。除非用-n 指明﹐预设会在处理完毕之后显示子行。
    s
    s/oldstring/newstring/flag  用新的字串替换旧的字串。其中可用的旗标有﹕
      g﹕替换行中的所有旧字串(预设只换第一个)﹔
      p﹕显示﹔
      w file ﹕写入特定档案。
      例如﹐您要输入﹕

    sed 1,3d src.file  所显示的结果﹐就会将src.file 的前面三行砍掉。如果您输入﹕

    sed '3,$d' src.file  这样﹐所显示的结果﹐就会从第3 行到最后一行都砍掉﹐只剩下第1 和第2 行而已。上面的命令别忘了加引号﹐否则要\$ 来跳脱。不过﹐我强​​烈建议您用单引号将sed 的命令括起来。如果您要将空白行拿掉﹐用RE 来做非常简单﹕

    sed '/^$/d' src.file  在sed 里面引用RE 的时候﹐ 通常都会用两个/ / 符号将RE 括起来﹐然后才是命令。如果您想要更换字串﹐那就要用s 命令了﹕

    sed 's/red/blue/g' src.file  这样﹐所有的red 字串都会被换成blue ﹔如果没有加上g 旗标﹐那么只有每一行的第一个red 被替换而已。
      除了d 和s 命令之外﹐我们还可以用a 命令在句子后面新增一行﹐内容为字串部份﹔或用i 命令在句子前面插入一行﹐内容为字串部份﹔也可以用c 命令将整行换成字串部份。不过﹐您在执行这几个命令的时候﹐必须要用' ' 将命令和参数括起来﹐然后用\ 符号在命令后面跳脱Enter 键﹐然后才能完成。嗯﹐说起来蛮难理解的﹐不如实作一下吧﹕

    sed ' $a \  
    New line appened at the end. ' src.file
      这样﹐就会在档案最后面增加一行句子了。再比方说﹐您要将第3 行换成另外的文字﹐可以这样玩﹕

    sed ' 3c \  
    The third line is replace with this line. ' src.file
      再比方说﹐您想将您存储邮件的档案~/mbox 用虚线分开每一封邮件﹐可以这样试试﹕

    sed ' /^From /i \   
    \
      
    ------------------------- \
      
    \
      
    ' ~/mbox
      我想﹐您应该不会忘记我们在前面的文章中﹐用ifconfig | grep | tr | cut 这些命令管线来抓出网路卡的界面吧。事实上﹐我们用sed 命令也一样可以得到同样的结果﹕

    ifconfig eth0 | grep "inet addr" | sed -e 's/^.*addr://' | sed 's/ *Bcast.*$//'  第一个sed 是将addr: 到句子前面的字串用s 命令替换为无字串(也就是在最后的// 中间没任何字符)﹔然后第二个sed 将Bcast 连同前面的空白﹐到句子末端也用s 替换为无字串(注意﹕/ *Bcast 的/ 和* 之间是空白键)﹔这样﹐剩下来的就是IP 位址了。
      目前﹐我们所进行的命令输出﹐都是在荧幕上﹐既然您已经学会命令的重导向了﹐要将结果保存到其它档案去﹐应是易如反掌了吧。^_^
      至于sed 的应用技巧﹐您可以到如下网站好好研究一下﹕
    http://www.ptug.org/sed/sedfaq.htm  学习过sed 之后﹐让我们再看看awk 这个命令究竟有什么神通。就拿刚才所举的抓IP 的例子来说好了﹐换成awk 也行哦﹕

    ifconfig eth0 | grep "inet addr" | awk -F ' ' '{print $2}' | awk -F ':' '{print $2}'  这里的awk 和cut 命令很相似﹕首先﹐用-F 定义出分隔符号(注意﹕第一个命令用空白做分隔符﹐所以-F 后面的两个' ' 之间是空白键)﹐然后再用print 命令将相应的列抓出来。对awk 而言﹐变数$0 代表每一行被处理的句子﹐然后第一个栏位是$1﹑第二个栏位是$2﹑.... ﹐如此类推。
      如果您以为awk 只能做这些事情﹐就实在是太小看它了﹗ 例如您有这样一个文字档(dog.txt)﹐里面只有这么一行文字﹕

      

    The brown fox jumped on the lazy dog​​ quickly.   

      然后我们用awk 来进行处理﹕

    # awk '{ $2="black"; $3="dog"; $8="fox"; print}' dog.txt  
    The black dog jumped on the lazy fox quickly.
      从上面的例子中﹐我们发现awk 具有处理变数的能力﹐事实上﹐它也有自己内建的变数﹕
      

    变数名称
    代表意思
    FS
    栏位分隔符号(预设是空白键)。
    NF
    当前句子中的栏位数目。
    NR
    当前句子的行数。
    FILENAME
    当前处理的档案名称。  甚至﹐awk 还能进行数值上的比对﹕
      

    变数名称
    代表意思
    >
    大于。
    <
    小于。
    >=
    大于或等于。
    1 ﹐也就是从第二行开始)﹐然则﹐再用printf 命令﹐按%s\t%3.2f\ n 的格式来显示。其中的%s﹑\t﹑\n 相信您都知道了﹐只有%3.2f 没见过而已。它定义出浮点数字( floating point )的显示格式是﹕小数点左边3 位数和小数点右边两位数。所以这行的格式是﹕先用字串显示整行﹑然后一个tab 键﹑然后以3.2 小数点格式显示前面定义好的average 变数﹑最后是一个断行符号﹕
      

                  %s \t %3.2f \n | | | |  Kenny Chen 80 80 50 70.00 | | | |               $0 average  

      


  • 然后是'{ }' 这些括号及引号的&#8203;&#8203;关闭﹐最后是要处理的档案名称。
  而每一行的输出结果﹐就会在字行后面按指定的格式加上tab 键和平均值了。是否很神奇呢﹖ ﹗ 呵呵﹐这只是awk 的牛刀少试而已﹐若要完全发挥awk 的强大火力﹐恐怕已经不是我所能介绍的了。



运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-555981-1-1.html 上篇帖子: shell脚本简单实例 下篇帖子: shell--eval
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表