首頁 > 軟體

對話 UNIX: !$#@*%

2020-06-16 17:56:02

對話 UNIX: !$#@*%
學習更多的命令列技巧和操作符
更好地理解 UNIX® 使用者輸入的這些 “奇怪的” 字元。學習如何在 UNIX 中使用管道、重定向、操作符等特性。

現在,您已經在 IBM® AIX® 上工作了一段時間了。您已經學習了幾個基本命令,能夠在目錄結構中移動、建立和修改檔案、檢視正在執行的進程以及管理使用者和系統。這很不錯,但是您希望了解 UNIX® 管理員輸入的命令是什麼意思。這些命令中包含許多奇怪的符號。在本文中,了解 |>>><<<[[]] 等符號在 UNIX 和 Linux® 中的意思,以及如何使用 &&||<<=!= 操作符。

管道

如果您熟悉 UNIX,那麼管道(或 pipe)會是每天都要接觸到的東西。管道最初是由 Malcolm McIlroy 開發的,可以使用管道把一個命令的標準輸出(stdout)定向到下一個命令的標準輸入(stdin),這樣就形成了連續執行的命令鏈。可以在一個命令列上使用多個管道。在許多時候,一個命令的 stdout 用作下一個命令的 stdin,第二個命令的 stdout 又被重定向到另一個命令的 stdin,依此類推。

例如,在排除故障或執行日常檢查時,大多數 UNIX 管理員首先做的事情之一是檢視系統上當前正在執行的進程。清單 1 演示這樣的檢查。

清單 1. 日常進程檢查範例
# ps –ef

     UID     PID    PPID   C    STIME    TTY  TIME CMD
    root       1       0   0   Jul 27      -  0:05 /etc/init
    root   53442  151674   0   Jul 27      -  0:00 /usr/sbin/syslogd
    root   57426       1   0   Jul 27      -  0:00 /usr/lib/errdemon
    root   61510       1   0   Jul 27      - 23:55 /usr/sbin/syncd 60
    root   65634       1   0   Jul 27      -  0:00 /usr/ccs/bin/shlap64
    root   82002  110652   0   Jul 27      -  0:24 /usr/lpp/X11/bin/X -x abx 
       -x dbe -x GLX -D /usr/lib/X11//rgb -T -force :0 -auth /var/dt/A:0-SfIdMa
    root   86102       1   0   Jul 27      -  0:00 /usr/lib/methods/ssa_daemon -l ssa0
    root  106538  151674   0   Jul 27      -  0:01 sendmail: accepting connections
    root  110652       1   0   Jul 27      -  0:00 /usr/dt/bin/dtlogin -daemon
    root  114754  118854   0   Jul 27      - 20:22 dtgreet
    root  118854  110652   0   Jul 27      -  0:00 dtlogin <:0>        -daemon
    root  131088       1   0   Jul 27      -  0:07 /usr/atria/etc/lockmgr 
       -a /var/adm/atria/almd -q 1024 -u 256 -f 256
    root  147584       1   0   Jul 27      -  0:01 /usr/sbin/cron
    root  155816  151674   0   Jul 27      -  0:04 /usr/sbin/portmap
    root  163968  151674   0   Jul 27      -  0:00 /usr/sbin/qdaemon
    root  168018  151674   0   Jul 27      -  0:00 /usr/sbin/inetd
    root  172116  151674   0   Jul 27      -  0:03 /usr/sbin/xntpd
    root  180314  151674   0   Jul 27      -  0:19 /usr/sbin/snmpmibd
    root  184414  151674   0   Jul 27      -  0:21 /usr/sbin/aixmibd
    root  188512  151674   0   Jul 27      -  0:20 /usr/sbin/hostmibd
    root  192608  151674   0   Jul 27      -  7:46 /usr/sbin/muxatmd
    root  196718  151674   0 11:00:27      -  0:00 /usr/sbin/rpc.mountd
    root  200818  151674   0   Jul 27      -  0:00 /usr/sbin/biod 6
    root  213108  151674   0   Jul 27      -  0:00 /usr/sbin/nfsd 3891
    root  221304  245894   0   Jul 27      -  0:05 /bin/nsrexecd
  daemon  225402  151674   0 11:00:27      -  0:00 /usr/sbin/rpc.statd
    root  229498  151674   0 11:00:27      -  0:00 /usr/sbin/rpc.lockd
    root  241794  151674   0   Jul 27      -  0:51 /usr/lib/netsvc/yp/ypbind
    root  245894       1   0   Jul 27      -  0:00 /bin/nsrexecd
    root  253960       1   0   Jul 27      -  0:00 ./mflm_manager
    root  274568  151674   0   Jul 27      -  0:00 /usr/sbin/sshd -D
    root  282766       1   0   Jul 27   lft0  0:00 /usr/sbin/getty /dev/console
    root  290958       1   0   Jul 27      -  0:00 /usr/lpp/diagnostics/bin/diagd
    root  315646  151674   0   Jul 27      -  0:00 /usr/sbin/lpd
    root  319664       1   0   Jul 27      -  0:00 /usr/atria/etc/albd_server
    root  340144  168018   0 12:34:56      -  0:00 rpc.ttdbserver 100083 1
    root  376846  168018   0   Jul 30      -  0:00 rlogind
 cormany  409708  569522   0 19:29:27  pts/1  0:00 -ksh
    root  569522  168018   0 19:29:26      -  0:00 rlogind
 cormany  733188  409708   3 19:30:34  pts/1  0:00 ps -ef
    root  749668  168018   0   Jul 30      -  0:00 rlogind

系統上當前正在執行的進程的列表可能像 清單 1 這麼簡單;但是,大多數生產系統執行的進程更多,這會使 ps 的輸出更長。為了把這個列表縮短到自己需要的範圍,可以使用管道把 ps –ef 的標準輸出重定向到 grep,從而搜尋自己真正希望看到的結果。清單 2 把 清單 1 產生的進程列表重定向到 grep,搜尋字串 “rpc” 和 “ksh”。

清單 2. 把進程列表重定向到 grep
# ps –ef | grep –E "rpc|ksh"

    root  196718  151674   0 11:00:27      -  0:00 /usr/sbin/rpc.mountd
  daemon  225402  151674   0 11:00:27      -  0:00 /usr/sbin/rpc.statd
    root  229498  151674   0 11:00:27      -  0:00 /usr/sbin/rpc.lockd
    root  340144  168018   0 12:34:56      -  0:00 rpc.ttdbserver 100083 1
 cormany  409708  569522   0 19:29:27  pts/1  0:00 -ksh
 cormany  733202  409708   0 19:52:20  pts/1  0:00 grep -E rpc|ksh

當多次把 stdout 重定向到 stdin 時,管道的使用方法可以很複雜。在下面的範例中,擴充套件了前面的 psgrep 範例,把它的 stdout 重定向到另一個 grep,其作用是排除包含 “grep” 或 “ttdbserver” 的字串。當最後的 grep 操作完成時,再次使用管道把 stdout 重定向到一個 awk 語句,其作用是輸出進程識別符號(PID)大於 200,000 的所有進程:

# ps –ef | grep –E "rpc|ksh" | grep -vE "grep|rpc.ttdbserver" | 
   awk -v _MAX_PID=200000 '{if ($2 > _MAX_PID) {print "PID for 
   process",$8,"is greater than", _MAX_PID}}'

PID for process /usr/sbin/rpc.statd is greater than 200000
PID for process /usr/sbin/rpc.lockd is greater than 200000
PID for process -ksh is greater than 200000

圖 1 通過圖形說明命令的 stdout 重定向到後續命令的 stdin 的次序。

圖 1. 管道範例


用 >、>>、< 和 << 執行資料重定向

通過命令列介面(CLI)執行命令的另一個重要方面是,能夠把各種輸出寫到一個裝置,或者把來自另一個裝置的輸入讀取到命令中。要想寫一個命令的輸出,需要在執行的命令後面加上大於號(> 或 >>)和所需的目標檔名或裝置。如果目標檔案不存在,而且您對目標目錄有寫許可權,那麼 > 和 >> 會建立這個檔案並根據您的 umask 設定許可權,然後把命令的輸出寫到剛建立的檔案中。但是,如果這個檔案存在,> 會嘗試開啟檔案並覆蓋整個內容。如果希望在這個檔案中追加內容,那麼只需使用 >>。可以認為它的作用是把左邊命令的輸出資料流移動到右邊的目標檔案中(即 <cmd> -> <output> -> <file>)。

下面的範例執行 “管道” 一節中的 ps –ef 範例,並把輸出重定向到檔案 ps_out

# ps –ef | grep –E "rpc|ksh" > ps_out

下面的程式碼執行前面擴充套件的管道範例並把輸出重定向到同一個檔案(ps_out),但是追加到當前資料後面:

# ps –ef | grep –E "rpc|ksh" | grep -vE "grep|rpc.ttdbserver" | 
   awk -v _MAX_PID=200000 '{if ($2 > _MAX_PID) {print "PID for 
   process",$8,"is greater than", _MAX_PID}}' >> ps_out

清單 3 給出前兩個重定向的輸出。

清單 3. 重定向的輸出
# cat ps_out

    root  196718  151674   0 11:00:27      -  0:00 /usr/sbin/rpc.mountd
  daemon  225402  151674   0 11:00:27      -  0:00 /usr/sbin/rpc.statd
    root  229498  151674   0 11:00:27      -  0:00 /usr/sbin/rpc.lockd
    root  340144  168018   0 12:34:56      -  0:00 rpc.ttdbserver 100083 1
 cormany  409708  569522   0 19:29:27  pts/1  0:00 -ksh
 cormany  733202  409708   0 19:52:20  pts/1  0:00 grep -E rpc|ksh
PID for process /usr/sbin/rpc.statd is greater than 200000
PID for process /usr/sbin/rpc.lockd is greater than 200000
PID for process -ksh is greater than 200000

當只使用 > 重定向輸出時,只重定向命令的 stdout。但是,除了 stdout,還有 stderr 輸出:前者表示為 1,後者表示為 2。在 UNIX 中輸出重定向沒有區別。只需在 > 前面加上所需的輸出型別(例如,1>2>),告訴 shell 要把輸出路由到哪裡。

清單 4 嘗試列出 fileA.tar.bz2 和 fileC.tar.bz2。但是,如第一個命令(ls)所示,fileC.tar.bz2 不存在。好在可以把 stdout 和 stderr 分別重定向到 ls.out 和 ls.err,這樣就能夠看到錯誤訊息。

清單 4. 列出檔案 fileA.tar.bz2 和 fileC.tar.bz2
# ls
fileA.tar.bz2   fileAA.tar.bz2  fileB.tar.bz2   fileBB.tar.bz2

# ls fileA.tar.bz2 fileC.tar.bz2 1> ls.out 2> ls.err

# cat ls.out
fileA.tar.bz2

# cat ls.err
ls: 0653-341 The file fileC.tar.bz2 does not exist.

在 AIX 中,對 stdout 和 stderr 使用 >>> 時應用相同的規則。例如,以後的測試可以使用相同的輸出檔案,見 清單 5。

清單 5. 使用輸出檔案進行以後的測試
# ls fileB.tar.bz2 fileD.tar.bz2 1>> ls.out 2>> ls.err

# cat ls.out
fileA.tar.bz2
fileB.tar.bz2

# cat ls.err
ls: 0653-341 The file fileC.tar.bz2 does not exist.
ls: 0653-341 The file fileD.tar.bz2 does not exist.

有時候,可能需要把 stdout 和 stderr 寫到同一個檔案或裝置。這有兩種方法。第一種方法是把 1>2> 重定向到同一個檔案:

# ls fileA.tar.bz2 fileC.tar.bz2 1> ls.out 2> ls.out

# cat ls.out
fileA.tar.bz2
ls: 0653-341 The file fileC.tar.bz2 does not exist.

第二個方法更簡單更快速,有經驗的 UNIX 使用者更喜歡採用這種方法:

# ls fileA.tar.bz2 fileC.tar.bz2 > ls.out 2>&1

# cat ls.out
fileA.tar.bz2
ls: 0653-341 The file fileC.tar.bz2 does not exist.

我們分解這個語句。首先,執行 ls fileA.tar.bz2 fileC.tar.bz2。然後使用 > ls.out 把 stdout 重定向到 ls.out,使用 2>&1 把 stderr 重定向到前面重定向的 stdout(ls.out)。

請記住,可以把輸出重定向到檔案和其他裝置。可以把資料重定向到印表機、軟碟、終端型別(TTY)以及各種其他裝置。例如,如果希望把一個訊息傳送給所有對談(或 TTY)上的某個使用者,那麼只需迴圈處理 who 並把一個訊息重定向到 TTY(如果您有足夠的許可權的話),見 清單 6。

清單 6. 把訊息重定向到一個 TTY
# for _TTY in 'who | grep "cormany" | awk '{print $2}''
> do
>   _TTY="/dev/${_TTY}"
>   echo "Sending message to cormany on ${_TTY}"
>   echo "Test Message to cormany@${_TTY}" > ${_TTY}
> done

Sending message to cormany on /dev/pts/13
Test Message to cormany@/dev/pts/13
Sending message to cormany on /dev/pts/14

stdin 而不是 stdout

儘管使用 > 和 >> 對於大多數人是一個相當容易掌握的概念,但是有的人在使用小於號(< 和 <<)時常常有困難。在考慮 > 和 >> 時,認為它們把左邊命令的輸出資料流移動到右邊的目標檔案中,這樣最容易理解。同樣的方法也適用於 < 和 <<。在使用 < 時,本質上是用一個已經提供的 stdin 執行一個命令。也就是說,把已經提供的資料提供給左邊的命令作為 stdin(即 <cmd> <- <data>)。

例如,假設希望把一個包含 ASCII 文字檔案的電子郵件傳送給另一個使用者。可以使用管道把 cat 的 stdout 重定向到 mail 的 stdin(即 cat mail_file.out | mail –s "Here's your E-mail!" acormany@yahoo.com),也可以把檔案的內容重定向到 mail 命令的 stdin:

# mail –s "Here's your E-mail!" acormany@yahoo.com < mail_file.out

使用 <<(也稱為 here-document)可以節省格式化時間,並且使命令執行的處理更容易。通過使用 <<,文字字串被重定向到執行的命令作為 stdin,但是可以繼續輸入資訊,直到到達終止識別符號。只需輸入命令,輸入 << 和終止識別符號,然後輸入需要的任何內容,最後在一個新行上輸入終止識別符號。通過使用 here-document,可以保留空格、換行等。

例如,UNIX 必須單獨處理下面五個 echo 語句:

# echo "Line 1"
Line 1

# echo "Line 2"
Line 2

# echo "Line 3"
Line 3

# echo "Line 4"
Line 4

# echo "Line 5"
Line 5

可以用以下程式碼替換多個 echo 語句,UNIX 只需處理一次執行:

# cat << EOF
> Line 1
> Line 2
> Line 3
> Line 4
> Line 5
> EOF

Line 1
Line 2
Line 3
Line 4
Line 5

還可以使用製表符讓 shell 指令碼中的內容更整潔一點,這只需要在 << 和終止識別符號之間放上一個連字元(-):

# cat <<- ATC
>	Line 1
>	Line 2
>	Line 3
>	Line 4
>	Line 5
> ATC

Line 1
Line 2
Line 3
Line 4
Line 5

清單 7 給出的範例演示如何結合使用本文到目前為止討論的東西。

清單 7. 組合 CLI
# cat redirect_example

#!/usr/bin/ksh

cat <<- ATC | sed "s/^/Redirect Example => /g" >> atc.out
This is an example of how to redirect
stdout to a file as well as pipe stdout into stdin
of another command (i.e. sed), all done inside
a here-document.

Cool eh?
ATC

現在,看看關於重定向和管道的指令碼。

# ./redirect_example

# cat atc.out
Redirect Example => This is an example of how to redirect
Redirect Example => stdout to a file as well as pipe stdout into stdin
Redirect Example => of another command (i.e. sed), all done inside
Redirect Example => a here-document.
Redirect Example =>
Redirect Example => Cool eh?

子 shell

有時候,需要一起執行幾個命令。例如,如果希望在另一個目錄中執行某一操作,可以使用 清單 8 中的程式碼。

清單 8. 同時執行幾個命令
# pwd
/home/cormany

# cd testdir

# tar –cf ls_output.tar ls.out?

# pwd
/home/cormany/testdir

這是有效的,但是要注意,在執行這些步驟之後,您就不再位於原來的目錄中了。通過把這些命令放在它們自己的子 shell 中,它們會作為子 shell 的範例執行。清單 9 演示如何使用子 shell 執行相同的程式碼。

清單 9. 使用子 shell 同時執行幾個命令
# pwd
/home/cormany

# (cd testdir ; tar -cf ls_output.tar ls.out?)

# pwd
/home/cormany 

更多詳情見請繼續閱讀下一頁的精彩內容http://www.linuxidc.com/Linux/2015-08/121214p2.htm


IT145.com E-mail:sddin#qq.com