tcsh 是最流行的 UNIX® shell 之一。學習如何用 tcsh shell 變數簡化自己的工作以及如何利用 tcsh 的高級安全特性。
tcsh 是原來的 Berkeley UNIX C shell 的改進版本,它是最流行的 UNIX shell 之一。本文討論 tcsh 提供的一些功能:它提供的 shell 變數可以減少幾個常規任務花費的時間,還提供了一些高級的安全特性,比如監視用戶及其命令歷史。本文描述的所有命令和腳本都用 tcsh 6.15 測試過(參見 參考資料)。
如何設置 shell 變數
tcsh 提供幾個內置的 shell 變數。其中一部分(比如 rmstar 和 noclobber)是布爾值,所以建議用 set <variablename> 打開它們。對於 prompt 等其他內置變數,需要使用 set <variablename>=<value> 提供一個值。使用 unset <variablename> 取消變數。清單 1 給出一些基本示例。
tcsh# set prompt="arpan@tintin# " arpan@tintin# set autologout=1 arpan@tintin# unset prompt echo $autologout 1 <prompt has disappeared due to unset operation> |
下面幾節討論 tcsh 通過 shell 內置變數提供的一些最有用的特性。
用 rmstar 預防災難
在 UNIX 中,造成混亂的最常見原因可能是意外地執行了 rm *。大多數用戶在使用 rm 命令時不使用 -i 選項,因此會立即刪除文件。tcsh 定義了一個 shell 變數 rmstar;如果打開這個變數,在用戶執行操作時會顯示提示,要求用戶確認操作。但是,如果用戶在命令提示下運行 rm –f *,就不會出現確認提示。清單 2 演示 rmstar 的用法。
arpan@tintin# pwd /home/arpan/scratchpad arpan@tintin# ls file1 file2 arpan@tintin# set rmstar arpan@tintin# rm * Do you really want to delete all files? [n/y] n arpan@tintin# ls file1 file2 arpan@tintin# unset rmstar arpan@tintin# rm * arpan@tintin# ls arpan@tintin# |
防止意外覆蓋現有的文件
造成混亂的另一個典型場景是意外地覆蓋現有的文件。為了防止發生這種情況,應該一直打開 shell 變數 noclobber。(這個變數在 csh shell 中也可用)。注意,這隻能防止把輸出重定向到現有文件;如果使用 cp 或 mv 覆蓋文件,這個變數沒有任何幫助。見清單 3。
arpan@tintin# ls file1 file2 arpan@tintin# set noclobber arpan@tintin# echo testing > file1 file1: File exists. arpan@tintin# unset noclobber arpan@tintin# echo testing > file1 arpan@tintin# cat file1 testing |
還要注意,shell 操作符 >> 和 >! 不考慮 noclobber 的設置。前一個操作符在現有文件中追加內容(所以仍然可以恢複數據),後者覆蓋現有內容。
自動 Tab 補齊
當在 shell 提示上輸入命令時,可以只輸入命令字元串的一部分,然後按 Tab,shell 會自動補齊命令字元串或者給出可用的選擇,這會顯著加快輸入速度。這個功能對於長文件名尤其有意義;可以只輸入前幾個字母並讓 shell 補齊文件名。為了啟用這個特性,需要設置 shell 變數 autolist。清單 4 給出一個示例。
arpan@tintin# ls this_is_a_big_file test.c threads.h arpan@tintin# set autolist arpan@tintin# vi t[TAB] this_is_a_big_file test.c term.h arpan@tintin# vi th[TAB] this_is_a_big_file threads.h |
在這個示例中,[TAB] 表示按 Tab 鍵。在 shell 提示上輸入 vi thi[TAB],shell 會把 thi[TAB] 擴展為 this_is_a_big_file。
使用 addsuffix 在 Tab 補齊期間區分目錄
如果同時設置 addsuffix shell 變數和自動 Tab 補齊,那麼在找到匹配時 tcsh 會在文件夾後面加上一個 / 字元,這樣就更容易區分出文件夾。它在一般文件後面加一個空格。在清單 5 所示的情況中,有一個名為 documents 的文件夾,這個文件夾中有一個名為 deliverables 的文件;用戶輸入 do[TAB],shell 就會顯示 documents/。如果取消 addsuffix 變數,tcsh 就只顯示 documents,這對於判斷 documents 是一般文件還是文件夾很不方便。
arpan@tintin# ls documents deliverables arpan@tintin# set autolist arpan@tintin# ls do[TAB] arpan@tintin# ls documents arpan@tintin# set addsuffix arpan@tintin# ls do[TAB] arpan@tintin# ls documents/ arpan@tintin# unset autosuffix arpan@tintin# ls do[TAB] arpan@tintin# ls documents |
使用 fignore shell 變數避免意外刪除
在某些情況下,限制自動 Tab 補齊特性是有意義的。例如,如果 vi 是一個會話中最常用的命令,那麼把 Tab 補齊提供的命令字元串限制在文本文件範圍內可以節省時間。同樣,如果 .c 和 .cpp 文件還未備份,希望避免意外刪除它們,那麼在 Tab 補齊期間最好不要出現具有 .c/.cpp 擴展名的文件,這樣在 rm 命令後面使用 Tab 補齊特性時就不會刪除它們。為了避免在 Tab 補齊期間顯示 C/C++ 文件,使用 set fignore=(.c .cpp .h)。見清單 6。
arpan@tintin# set autolist arpan@tintin# ls memory.h memory.cpp kernel.c memory.o kernel.o arpan@tintin# rm m[TAB] memory.h memory.cpp memory.o arpan@tintin# set fignore=(.c .cpp .h) arpan@tintin# rm m[TAB] memory.o |
注意,如果在 rm 後面按 Tab 鍵(而不是在 m 後面按 Tab 鍵),那麼所有 C/C++ 源代碼文件都會出現。
在沒有用戶活動時自動註銷
數據安全是所有組織都很關心的問題。如果意外地讓一個 shell 終端一直打開著,就可能提供訪問重要文件的機會,這種情況隨時都會發生。可以用 tcsh autologout 變數解決這個問題。如果在指定的時間(以分鐘為單位)內沒有用戶活動,用戶就從系統中註銷,返回到 tcsh(如果 tcsh 是登錄 shell)。如果 tcsh 不是登錄 shell,用戶就退出到以前的 shell(這對安全幫助不大)。因此,在安全環境中選擇 tcsh 作為登錄 shell 是有意義的。清單 7 給出一個由於沒有用戶活動導致自動註銷的示例。
arpan@tintin# rsh herge arpan@herge# set autologout=1 arpan@herge# date Sat Jun 28 18:13:07 IST 2008 <After 1 min of inactivity> arpan@herge# auto-logout Connection to herge closed. arpan@tintin# date Sat Jun 28 18:14:10 IST 2008 |
改進 tcsh 的安全性:監視正在使用系統的每個用戶
必須一直監視用戶對受保護系統的訪問。tcsh 提供了內置 shell 變數 watch,可以通過它查看正在使用系統的用戶。語法是 set watch=(username1 ttyname1 username2 ttyname2 …)。這會監視用戶 username1 是否在終端 ttyname1 上登錄了。可以用特殊語法 set watch=(any any) 監視所有系統終端上的所有用戶。
在默認情況下,watch 每 10 分鐘檢查一次系統中的登錄/註銷活動。可以通過 watch 語法中的第一個參數指定活動檢查之間的時間間隔,例如:set watch=(5 any any)。見清單 8。
arpan@tintin# set watch=(5 any any) <checks for login/logout activity across system every 5 minutes) arpan@tintin# set watch=(b* any) <check the login/logout activities of all users whose name starts with b across any terminal in the network> |
tcsh 還提供內置命令 log,這個命令列出受 watch 變數影響的終端以及正在使用它們的用戶(見清單 9)。注意,如果在沒有設置 watch 的情況下使用 log,就會導致一個錯誤。
arpan@tintin# log arpan has logged on pts/0 from 132.132.6.73 root has logged on console zanies has logged pts/5 from 132.132.2.1 |
使用 prompt 變數跟蹤當前的工作目錄
tcsh 定義了 prompt 內置 shell 變數,可以通過這個變數定製 shell 提示。最常見的 UNIX 任務之一是跟蹤當前所在的文件夾和機器。不需要一直使用 pwd 和 hostname,只需通過設置 prompt 變數讓 shell 提示反映當前的工作目錄和主機名,即可實現相同的效果。見清單 10。
tcsh-6.15$ pwd /home/arpan/ibm1 tcsh-6.15$ hostname tintin tcsh-6.15$ echo $user arpan tcsh-6.15$ set prompt="$user@`hostname`[$cwd] " arpan@tintin[/home/arpan/ibm1] |
但是,這種方式有一個問題:如果切換到另一個文件夾,提示並不會反映這一變化。為了隨著切換文件夾連續改變提示,應該使用特殊別名 cmdcwd。如果已設置這個別名,那麼在切換到新文件夾之後 tcsh 會執行 cmdcwd 映射到的命令。為了在提示中反映修改後的文件夾,cmdcwd 必須映射到 set prompt 命令(見清單 11)。
tcsh-6.15$ alias cmdcwd 'set prompt="$user@`hostname`[$cwd] " ' tcsh-6.15$ cd arpan@tintin[/home/arpan/ibm1] cd net arpan@tintin[/home/arpan/ibm1/net] |
注意,這個方案不但能夠反映 cd 命令所做的文件夾切換,對於 pushd 和 popd 命令也是有效的。如果使用 X-Windows,另一個跟蹤當前文件夾的好方法是,在跨多個文件夾工作時,在 xterm 標題欄上顯示文件夾名。
例如,可以使用 echo 命令在 xterm 標題欄上顯示一些基本信息。在 shell 提示上輸入 echo "[Ctrl-v][Esc]]2; Hello [Ctrl-v][Ctrl-g]"。注意,[Ctrl-v] 表示按組合鍵 Ctrl-V。輸入這個命令序列,就會在 shell 提示上顯示以下內容:echo "^[]2; Hello ^G"。執行這個命令之後,xterm 標題欄顯示 Hello。清單 12 演示如何在 xterm 標題欄和提示中同時顯示當前文件夾名。
arpan@tintin[/home/arpan1/ibm1]# alias cwdcmd 'set prompt="$user@`hostname`[$cwd]# "; echo "^[]2;$cwd^G" ' |
自動糾正無效的命令用法
tcsh 提供內置變數 correct,這有助於糾正無效的命令用法。例如,如果希望調用 perl,但是輸入的是 prl,tcsh 會提示您糾正它。清單 13 給出一個示例。
arpan@tintin# set correct=cmd arpan@tintin# prl CORRECT>perl (y|n|e|a)? y .. arpan@tintin# figner CORRECT>finger (y|n|e|a)? y .. |
定期執行特定的命令
系統管理員最常見的任務之一是監視磁碟使用量,並在磁碟使用量接近 100% 時採取措施。tcsh 的一個出色特性使我們能夠輕鬆地定期執行特定的命令。把 periodic 映射到要定期執行的任務,並把 shell 內置變數 tperiod 設置為執行任務的時間間隔(以分鐘為單位)。清單 14 演示如何使用 tperiod 和 periodic。注意,periodic 映射到腳本 checkdiskusage,這個腳本檢查磁碟使用量,tcsh 每 10 分鐘運行它一次。
arpan@tintin# set tperiod=10 arpan@tintin# alias periodic checkdiskusage arpan@tintin# cat checkdiskusage df -k | awk -F" " '{print $5}' | grep "9[0-9]*" if ($status <> 0) then mail –s "disk quota exceeded 90%" root@officemail.com endif exit $status |
針對每個終端分別設置歷史文件
同一位 UNIX 系統用戶常常從多個終端登錄。為了針對每個終端分別維護命令執行歷史,可以使用 histfile 和 savehist 環境變數。histfile 變數用來指定存儲命令執行歷史的文件;默認設置是 $HOME/.history。savehist 變數讓 tcsh 存儲用戶在 shell 提示上輸入的最後 N 個命令。清單 15 中定義的 histfile 變數指定多個歷史文件,這樣就可以監視多個終端。
arpan@tintin# tty /dev/pts/0 arpan@tintin# set savehist=25 arpan@tintin# set histfile=~/.history_`tty | sed –e 's/\//_/g' ` arpan@tintin# echo $histfile ~/.history_dev_pts_0 |
監視運行一個命令花費的時間
為了監視執行一個 UNIX 進程花費的時間,可以設置 time 變數。輸出顯示用戶時間、內核時間和實際流逝時間。清單 16 給出一個示例。
注意,可以用 tcsh 的內置命令 time 產生相同的輸出,但是要對腳本做大量修改 —— 每個命令必須加上前綴 time(例如,time du –sm /opt)。如果使用 time 變數,那麼只需在腳本的開頭加上一行 set time,就可以顯示各個命令的執行時間。
arpan@tintin# cat script set time du –sm /opt df –k /lib arpan@tintin# tcsh –f ./script 198 /opt 0.628u 0.008s 0:02.00 0.0% 0+0k 0+0io 0pf+0w Filesystem 1K-blocks Used Available Use% Mounted on /dev/sda1 15773312 1125772 13846300 8% / 0.000u 0.004s 0:00.02 0.0% 0+0k 0+0io 0pf+0w |
調試 shell 腳本:在發生錯誤時自動輸出退出值
shell 變數 printexitvalue 是一個很有用的 tcsh 特性,它對腳本調試非常有幫助。在通常情況下,shell 腳本和 UNIX 程序在成功完成時返回零。如果設置這個變數,那麼當腳本或程序返回非零值時 tcsh 會顯示退出狀態,這會指出潛在的錯誤。見清單 17。
arpan@tintin# set printexitvalue arpan@tintin# ls /tmp/opt ls: /tmp/opt: No such file or directory Exit 2 arpan@tintin# cat error_script ls –l; return 2 arpan@tintin# ./error_script ./error_script: line 1: return: can only `return' from a function or sourced script Exit 1 arpan@tintin# unset printexitvalue; ls /tmp/opt ls: /tmp/opt: No such file or directory |
注意,在這個變數與一個 shell 腳本結合使用時,顯示的是腳本的非零返回值,而不是腳本內部使用的命令或用戶程序的返回值。
結束語
除了支持 csh 提供的 shell 變數之外,tcsh 還提供了大量 shell 變數和別名。本文主要介紹 tcsh 特有的變數。這裡只討論了一部分變數;更詳細的信息參見 參考資料。 (責任編輯:A6)
[火星人 ] tcsh shell 變數已經有883次圍觀