歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Unix知識 >> Unix基礎知識

Unix基礎教程(6)

第6章 B-Shell及編程

【例6-1】使用#!為腳本文件自設定解釋程序。

$ cat lsdir 

#!/bin/od -c

if [ $# = 0 ]

then

    dir=.

else

    dir=$1

fi

find $dir -type d -print

 

$ chmod u+x lsdir

$ ./lsdir

0000000    #   !   /   b   i   n   /   o   d       -   c  \n   i   f

0000020    [       $   #       =       0       ]  \n   t   h   e   n

0000040   \n           d   i   r   =   .  \n   e   l   s   e  \n

0000060    d   i   r   =   $   1  \n   f   i  \n   f   i   n   d       $

0000100    d   i   r       -   t   y   p   e       d       -   p   r   i

0000120    n   t  \n  \n

 

    腳本文件中第一行如果缺少了#!,那麼,系統就會用默認的shell程序來解釋執行腳本文件的文本。一般系統的默認shell是/bin/sh,LINUX的默認shell是/bin/bash。

    有三種方法可以執行腳本文件。

(1) sh < lsdir

(2) sh lsdir

   sh lsdir  /bin

(3)  chmod u+x lsdir 給文件lsdir可執行屬性

    ./lsdir

 

【例6-2】標准輸入重定向的使用舉例。

    ./myap < try.in

    如果你在編寫一個程序btree.c完成一個數據結構的作業,根據一棵二叉樹的先序,中序,求後序。程序運行的時候需要輸入先序序列,中序序列,然後打印出後序序列。由於程序邏輯較復雜,先序序列和後序序列分別為下列順序時,程序運行不正確。

    ABFGEHILMOPCDJKNQR

    FGBHELIOPMACJDQNRK

    這樣,就需要反復地修改程序文件btree.c,編譯後運行./btree,然後根據程序提示,從鍵盤輸入上述的兩個字符串數據。反復的調試需要反復的輸入上述數據,這種重復性的勞動效率很低,而且容易出錯。這樣,就可以將上述兩行文本編輯成文件btree.tst1, 利用shell的輸入重定向,運行./btree < btree.tst1。

 

【例6-3】簡單的Here document。

cat << TEXT

**********

* Hello! *

**********

TEXT

上述命令執行結果,在屏幕上顯示:

**********

* Hello! *

**********

這裡,<<符號後面是定界符,在shell輸入中下一個TEXT之前的這段文本,算作cat命令的標准輸入。

 

【例6-4】在Here document中進行命令替換和變量替換。

cat << TOAST

Hello! Time: `date`

My Home Directory  is  $HOME

Bye!

TOAST

上述命令執行結果為:

Hello! Time: Sat Jul 27 14:47:56 BEIJING 2004

My Home Directory is /usr/jiang

Bye!

 

【例6-5】在Here document中禁止命令替換和變量替換。

cat << \TOAST

Hello! Time: `date`

My Home Directory  is  $HOME

Bye!

TOAST

 

cat << 'TOAST'

Hello! Time: `date`

My Home Directory  is  $HOME

Bye!

TOAST

 

上述兩種情況,輸出結果都是:

Hello! Time: `date`

My Home Directory  is  $HOME

Bye!

 

【例6-6】B-shell的標准錯誤輸出重定向舉例。

 

    (1) cc  myap.c -o myap 2> myap.err

    將cc命令的stderr重定向到文件myap.err中。

 

    (2) 設try是程序員設計的某個應用程序。

    try > try.out 2>try.err

    try 1> try.out 2>try.err

    將try程序執行後的stdout或stderr分別定向到兩個不同的文件中(其中的1和2,是文件描述符,分別是stdout和stderr,如果換成其它數字也可以對try的其它文件描述符輸出改向)。

 

【例6-7】B-shell指定文件描述符的輸出重定向。

    myap >rpt 2>&1

    或者:

    myap 1>rpt 2>&1

 

【例6-8】B-shell的管道處理舉例。

 

    (1) ls  -l  |  grep ’^d’  

    前一命令的stdout作後一命令的stdin。

 

    (2) cc myap.c -o myap 2>&1 |  more

    前一命令的stdout+stderr作為下一命令的stdin。這裡管道操作的優先級高,先完成cc的標准輸出管道到下個命令的標准輸入,然後,將文件描述符重定向的和文件描述符1一樣,就完成了將標准輸出和標准錯誤輸出都管道到下個命令的目的。

 

【例6-9】shell變量的定義和引用舉例。

    定義一個名為addr的變量,存放一個IP地址字符串。

$ addr=20.1.1.254   (最左側的$為sh命令提示符)

$ echo  $addr       (引用變量addr,echo執行前,sh完成變量替換)

20.1.1.254

$ city="Beijing, China"

$ echo $city

Beijing, China

$ echo Connected to $proto Network

Connected to Network

$ proto=TCP/IP

$ echo Connected to $proto Network

Connected to TCP/IP Network

【例6-50】使用shell函數的例子。

    這個例子是一個廣域網通信適配卡驅動程序安裝腳本的一部分。

    這個通信適配卡安裝之前要求輸入硬件的中斷號,I/O基地址和通信速率。然後,列出操作員的輸入,等待確認後才執行安裝操作。

    安裝操作在41~85行之間,被省略。

    第4~16行的函數get_answer打印出一條消息,然後,強制輸入y或者n,否則繼續要求用戶輸入。函數體內使用了$1引用調用函數get_answer的命令行參數,用return使得shell函數象普通命令一樣有返回碼,供條件判斷使用。

    第20~34行的函數get_val有四個參數。第一個參數$1存放用戶輸入值的shell變量的名字,第二個參數$2是輸入之前給用戶的提示信息,第三個參數$3是用戶直接按下回車時的缺省值,最後一個參數$4是允許取值的有效值列表。函數get_val強制用戶輸入一個有效值列表中的有效值,否則,就給出有效值列表做提示,並進一步要求用戶重新輸入。函數體內使用了while循環和for循環結構。第29行的break命令含有參數2,可以跳出兩層循環。

    腳本程序執行時從第36行開始執行。由於腳本文件前面有了函數說明,shell記下了函數名字get_val和get_answer作為內部命令,在執行命令get_val和get_answer時,shell都轉去執行函數體,而不是到磁盤上尋找這樣名字的命令文件。

 $ awk '{print NR,$0}' WanCom

  1  # Shell function to read a Y/N response

  2  # Usage: get_answer <message>

  3  #

  4  get_answer()

  5  {

  6      while  true

  7      do

  8          echo "$1? (y/n) \c"

  9          read yn

 10          case $yn in

 11              [yY]) return 0;;

 12              [nN]) return 1;;

 13                  *) echo "Please answer y or n" ;;

 14          esac

 15      done

 16  }

   

 17  # Shell function to get a value

 18  # Usage: get_val <var_name> <message> <default_val> <list>

 19  #

 20  get_val()

 21  {

 22      while true

 23      do

 24          echo "$2 [$3] : \c"

 25          read val

 26          [ "$val" = "" ] && val=$3

 27          for i in $4

 28          do

 29              [ "$val" = "$i" ] && break 2 

 30          done

 31          echo "**** Invalid choice $val, must be in $4"

 32      done

 33      eval "$1=$val"

 34  }

    

 35  #  main program

  

 36  get_val INTR "Interrupt Number" 10 "2 3 4 5 7 10 11 12 14 15"

 37  get_val PORT "I/O Base Address" 320 "200 210 220 230 300 310 320 330"

 38  get_val BAUD "Baud Rate" 9600 "2400 9600 14400 33600 64000"

   

 39  echo "Interrupt $INTR, I/O base address $PORT, Baud rate is $BAUD"

 40  get_answer "Do you want to install WanCom adapter driver" && {

 41      echo "Please Wait ...\c"

          ……

 85  }

$ ./WanCom

Interrupt Number [10] : 22

**** Invalid choice 22, must be in 2 3 4 5 7 10 11 12 14 15

Interrupt Number [10] : 14

I/O Base Address [320] :

Baud Rate [9600] : 33.6

**** Invalid choice 33.6, must be in  2400 9600 14400 33600 64000

Baud Rate [9600] : 33600

Interrupt 14, I/O base address 320, Baud rate is 33600

Do you want to install WanCom adapter driver? (y/n) y

Please Wait ...

...

$

 

【例6-51】shell腳本程序中-x開關的作用。

    腳本程序中打開-x開關,可以觀察到程序執行的流程。

$ cat chmod1

set -x

echo "$*"

for i

do

    [ -f $i ] && {

        chmod a+r $i

        eoho "$i is readable"

    }

done

$ ./chmod1 a*

+ echo a1 aa8 abcd

a1 aa8 abcd

+ [ -f a1 ]

+ chmod a+r a1

+ echo a1 is readable

a1 is readable

+ [ -f aa8 ]

+ [ -f abcd ]

+ chmod a+r abcd

+ echo abcd is readable

abcd is readable

    本例中第一行的set -x也可以省略,使用命令sh -x chmodl a*也能達到相同的效果。或者,將腳本文件chmod1的第一行修改為!/bin/sh -x也可以。

 

【例6-52】交互式shell中-x開關的作用。

    交互式shell中打開-x開關,可以觀察shell的命令替換,變量替換,文件名生成,以及轉移符的作用。每次shell在真正執行一個命令之前都把要執行的命令顯示出來。

$ set -x

$ tty

+ tty

/dev/tty6

$ termno=`expr \`tty\` : /dev/tty\\\\\\(.\\*\\\\\\)`

+ + tty

+ expr /dev/tty6 : /dev/tty\(.*\)

termno=6

$ echo $termno

+ echo 6

6

$ find $HOME -size +100 \( -name \*.c -o -name xxxx \) -exec rm -i {} \;

+ find /usr/jiang -size +100 ( -name *.c -o -name xxxx ) -exec rm -i {} ;

 

【例6-53】shell的-u開關的使用。

    可以檢查出引用變量時的變量名拼寫錯誤。

$ name=CSPTF

$ echo Connecting to $nmae Network

Connecting to Network

$ echo Connecting to $NAME Network

Connecting to Network

$ set -u

$ echo Connecting to $nmae Network

nmae: 0402-009 Parameter is not set.

$ echo Connecting to $NAME Network

NAME: 0402-009 Parameter is not set.

$ echo Connecting to $name Network

Connecting to CSPTF Network

$

 

【例6-54】使用set命令設置shell的位置變量。

    使用set命令可以重新設置shell的位置變量,先前的位置變量全部被新的值代替。

$ echo $#

0

$ date

Sun Jul 28 11:00:40 BEIJING 2004

$ set `date`

$ echo $1 $2 $3 $4

Sun Jul 28 11:00:40

$ ls -l /etc/motd

-rw-r--r-- 1 root staff 316 Jan 5 08:42 /etc/motd

$ set `ls -l /etc/motd`

sh:-rw-r-r-: bad option(s)

$ set -- `ls -l /etc/motd`

$ echo $9:$5  $1

/etc/motd:316  -rw-r--r--

    注意--的使用,顯式地指定set命令選項的結束,否則set會把以減號開頭的命令行參數理解成set的選項。關於--,在前面的4.4.4節介紹過。

 

【例6-55】逐個打印源程序文件。

    打印多個源程序文件,每打印個文件之前列出文件名,打印文件時每行帶上行號。

$ cat prt

while  [ $# -gt 0 ]

do

    echo ===================

    echo FILE NAME: $1

    echo ===================

    awk '{printf("2d %s\n",NR,$0)}' $1

    shift

done

$ ./prt makefile *.[ch]

 

【例6-56】給出若干個程序名,終止這些程序文件啟動的所有進程。

    獲取程序啟動的進程的PID的方法,在前面的“元字符”6.5.10節中介紹過。這裡的腳本程序中使用了位置變量和shift命令。

$ cat k

while [ $# != 0 ]

do

    echo "$1: \c"

    PID=`ps -e | awk "/[0-9]:[0-9][0-9] $1\\$/{printf(\\"%d \\",\\$1)}"`

    if [ -n "$PID" ]

    then

        echo kill $PID

        kill $PID

    else

        echo No process

    fi

    shift

done

$ ./k myap findkey sortdat

myap: kill 26506 38020

findkey: kill 31542

sortdat: No process

$

 

【例6-57】軟件安裝時調整操作系統內核的部分參數。

    下面的一段腳本程序,在SCO UNIX系統中安裝某個軟件包時,調整操作系統內核參數。第一行和第二行列出了相應的參數和期望的配置值。例如:要求MSGMNB參數取值至少32768, NQUEUE參數取值至少64。

    命令configure的格式:

    configure -y 參數名

    configure 參數名=參數值 參數名=參數值 ……

    第一種格式,打印出指定名字的內核參數的當前取值,第二種格式,調整指定名字的內核參數為指定的參數值,並且可以一次調整多個參數。這個命令是SCO UNIX專用的,在其它UNIX中沒有通用性。

    腳本程序使用set命令和shift命令對位置變量的影響。內核參數當前取值已經滿足要求的參數不再調整。

 1 PARA="MSGMNB MSGTQL MSGSEG NBLK4096 NBLK2048 NBLK1024 NQUEUE"

 2 VAL=" 32768  600     16384   16        128        100       64"

 3 CHANGE=

 

 4 cd /etc/conf/cf.d

 5 set $VAL

 6 for i in $PARA; do

 7      x=`./configure -y $i`

 8      if [ $x -lt $1 ]

 9      then

10          echo "Adjusting parameter $i from $x to $1"

11          CHANGE="$i=$1 $CHANGE"

12      fi

13      shift

14 done

 

15 if [ -n "$CHANGE" ]

16 then

17      ./configure $CHANGE

18 fi

Copyright © Linux教程網 All Rights Reserved