學習 bash shell
本文資料主要針對 Fedora Core 4 的系統進行說明, Fedora Core 1 主要是由 Red Hat Linux 9 改版而來, 這個 Red Hat Linux 9 並不是當前大家聽到的 RHEL 喔!那是在 RHEL 出現之前的產品,基本上是在 2003 年以前的作品了!Fedora Core 4 則是在 2005 年 6 月份釋出,使用的核心是 2.6.11 版,當時是很紅的一個作品!只是生命週期太短,所以用這個 Fedora 系列來介紹 Server, 當時的決定確實有點莫名其妙了...
建議您前往本站查詢最新版本的 Linux distribution 文章來閱讀,比較不會浪費時間。那為何還需要編輯 Fedora Core 4 的資料呢? 鳥哥只想要做個自己曾經撰寫過的文件內容保存而已囉! ^_^!最新文章請前往鳥站首頁查閱囉!
文字模式 (command line) 這種指令下達的方式,在 Linux 裡面,其實就相當於是 bash 的工具與介面! 因為 Linux 就是以 bash 為預設的 shell 的!那麼前幾章我們都已經很快樂的進行了很多的指令下達囉~ 所以說, bash shell 根本就不難吧~是啦!只要能夠熟悉的話,那麼確實他也不是這麼不可親近的一項工具啊~ 這個章節中,鳥哥會由變數談起,先講到環境變數的功能與修改的問題, 然後會繼續提到歷史指令的運用。接下來,就會談一下『資料流重導向』這個重要概念, 最後就是管線命令的利用啦!好好清一清腦門,準備用功去囉~ ^_^ 這個章節幾乎是所有 command line 與未來主機維護與管理的重要基礎,一定要好好仔細的閱讀喔!
[root@linux ~]# cat /etc/passwd root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin .....(中間省略).....如上所示,在每一行的最後一個資料,就是您登入後,可以取得的預設的 shell 啦! 那你也會看到, root 是 /bin/bash ,不過,系統帳號 bin 與 daemon 等等,就使用那個怪怪的 /sbin/nologin 囉~關於使用者這部分的內容,我們留在 帳號管理 時提供更多的說明。
[root@linux ~]# type [-tpa] name 參數: :不加任何參數時,則 type 會顯示出那個 name 是外部指令還是 bash 內建的指令! -t :當加入 -t 參數時,type 會將 name 以底下這些字眼顯示出他的意義: file :表示為外部指令; alias :表示該指令為命令別名所設定的名稱; builtin :表示該指令為 bash 內建的指令功能; -p :如果後面接的 name 為指令時,會顯示完整檔名(外部指令)或顯示為內建指令; -a :會將由 PATH 變數定義的路徑中,將所有含有 name 的指令都列出來,包含 alias 範例: 範例一:查詢一下 ls 這個指令是否為 bash 內建? [root@linux ~]# type ls ls is aliased to `ls --color=tty' # 沒有加上任何參數,僅列出 ls 這個指令的最主要使用情況 [root@linux ~]# type -t ls alias # -t 參數則僅列出 ls 這個指令的最主要使用情況說明 [root@linux ~]# type -a ls ls is aliased to `ls --color=tty' ls is /bin/ls # 利用所有方法找出來的 ls 相關資訊都會被列出來! 範例二:那麼 cd 呢? [root@linux ~]# type cd cd is a shell builtin透過 type 這個指令的用途,我們可以知道每個指令是否為 bash 的內建指令。 此外,由於利用 type 搜尋後面的名稱時,如果後面接的名稱並不能以執行檔的狀態被找到, 那麼該名稱是不會被顯示出來的。舉例來說,您的 FC4 應該不會有 vbird 這個指令吧?! 輸入 type -p vbird 看一下,果然沒有輸出任何資料!而如果您輸入的是 type -p touch 呢? 則會出現 /bin/touch !呵呵!所以,這個 type 也可以用來作為類似 which 指令的用途啦!找指令用的!
[root@linux ~]# command [-options] parameter1 parameter2 ... 指令 選項 參數(1) 參數(2) 說明: 0. 一行指令中第一個輸入的絕對是『指令(command)』或『可執行檔案』 1. command 為指令的名稱,例如變換路徑的指令為 cd 等等; 2. 中刮號[]並不存在於實際的指令中,而加入參數設定時,通常為 - 號,例如 -h; 有時候完整參數名稱會輸入 -- 符號,例如 --help; 3. parameter1 parameter2.. 為依附在 option 後面的參數, 或者是 command 的參數; 4. command, -options, parameter1.. 這幾個咚咚中間以空格來區分, 不論空幾格 shell 都視為一格; 5. 按下 [Enter] 按鍵後,該指令就立即執行。[Enter] 按鍵為 <CR> 字符, 他代表著一行指令的開始啟動。 6. 指令太長的時候,可以使用 \ 符號來跳脫 [Enter] 符號, 使指令連續到下一行。注意! \ 後就立刻接特殊字符。 7. 在 Linux 系統中,英文大小寫字母是不一樣的。舉例來說, cd 與 CD 並不同。 範例: 範例一:列出 /root 底下的各檔案名稱 [root@linux ~]# ls -al /root [root@linux ~]# ls -al /root # 不論指令與參數中間空幾格,都是可以接受的! 範例二:如果指令太長的話,如何使用兩行來輸出? [root@linux ~]# cp /var/spool/mail/root /etc/crontab \ > /etc/fstab /root # 上面這個指令,就是將三個檔案複製到 /root 這個目錄下而已。不過,因為指令太長, # 於是鳥哥就利用 \[Enter] 來將 [Enter] 這個按鍵『跳脫!』開來,讓 # [Enter] 按鍵不再具有上述說明的第 5 點功能!好讓指令繼續在下一行輸入。 # 需要特別留意, [Enter] 按鍵是緊接著反斜線 (\) 的,兩者中間沒有其他字元。 # 因為 \ 僅跳脫『緊接著的下一個字符』而已!所以,萬一我寫成: # \ [Enter] ,亦即 [Enter] 與反斜線中間有一個空格時,則 \ 跳脫的是『空白鍵』 # 而不是 [Enter] 按鍵!這個地方請在仔細的看一遍!很重要! # 如果順利跳脫 [Enter] 後,下一行最前面就會主動出現 > 的符號, # 您可以繼續輸入指令囉!也就是說,那個 > 是系統自動出現的,你不需要輸入。總之,當我們順利的在終端機 (tty) 上面登入後, Linux 就會依據 /etc/passwd 檔案的設定給我們一個 shell ,預設就是 bash ,然後我們就可以依據上面的指令下達方式來操作 shell, 之後,我們就可以透過 man 這個線上查詢來查詢指令的使用方式與參數說明, 很不錯吧!那麼我們就趕緊更進一步來操作 bash 這個好玩的東西囉!
[root@linux ~]# echo $variable [root@linux ~]# echo $PATH /bin:/sbin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/usr/X11R6/bin [root@linux ~]# echo ${PATH}變數的取用就如同上面的範例,利用 ehco 就能夠讀出,只是需要在變數名稱前面加上 $ , 或者是以 ${variable} 的方式來取用都可以!當然啦,那個 echo 的功能可是很多的, 我們這裡單純是拿 echo 來讀出變數的內容而已,更多的 echo 使用,請自行給他 man echo 吧! ^_^
例題一:請在螢幕上面顯示出您的環境變數 HOME 與 MAIL: 答:
echo $MAIL |
[root@linux ~]# echo $myname <==這裡並沒有任何資料~因為這個變數尚未被設定!是空的! [root@linux ~]# myname=VBird [root@linux ~]# echo $myname VBird <==出現了!因為這個變數已經被設定了!瞧!如此一來,這個變數名稱 myname 的內容就帶有 VBird 這個資料囉~ 而由上面的例子當中,我們也可以知道: 當一個變數名稱尚未被設定時,預設的內容是『空』的。 另外,變數在設定時,還是需要符合某些規定的,否則會設定失敗喔! 這些規則如下所示啊!
範例一:設定一變數 name ,且內容為 VBird 。 [root@linux ~]# 12name=VBird -bash: 12name=VBird: command not found <==螢幕會顯示錯誤!因為不能以數字開頭! [root@linux ~]# name = VBird <==還是錯誤!因為有空白! [root@linux ~]# name=VBird <==OK 的啦! 範例二:承上題,若變數內容為 VBird's name 呢? [root@linux ~]# name=VBird's name # 因為單引號可以將 Enter 這個特殊字符取消,所以,您可以繼續在下一行輸入內容~ # 不過,這與我們要達到的功能不同,所以,算是失敗的啦! [root@linux ~]# name="VBird's name" <==OK 的啦! [root@linux ~]# name=VBird\'s\ name # 利用反斜線 (\) 跳脫特殊字元,例如單引號與空白鍵,這也是 OK 的啦! 範例三:我要在 PATH 這個變數當中『累加』:/home/dmtsai/bin 這個目錄 [root@linux ~]# PATH=$PATH:/home/dmtsai/bin [root@linux ~]# PATH="$PATH":/home/dmtsai/bin # 上面這兩種格式在 PATH 裡頭的設定都是 OK 的!但是底下的例子就不見得囉! 範例四:呈範例三,我要將 name 的內容多出 "yes" 呢? [root@linux ~]# name=$nameyes # 知道了吧?如果沒有雙引號,那麼變數成了啥?name 的內容是 $nameyes 這個變數! # 呵呵!我們可沒有設定過 nameyes 這個變數吶!所以,應該是底下這樣才對! [root@linux ~]# name="$name"yes [root@linux ~]# name=${name}yes 範例五:如何讓我剛剛設定的 name=VBird 可以用在下個 shell 的程序? [root@linux ~]# name=VBird [root@linux ~]# bash <==進入到所謂的子程序 [root@linux ~]# echo $name <==嘿嘿!並沒有剛剛設定的內容喔! [root@linux ~]# exit <==離開剛剛的子程序 [root@linux ~]# export name [root@linux ~]# bash <==進入到所謂的子程序 [root@linux ~]# echo $name <==出現了設定值了! [root@linux ~]# exit <==離開剛剛的子程序 # 什麼是『子程序』呢?就是說,在我目前這個 shell 的情況下, # 去啟用另一個新的 shell ,新的那個 shell 就是子程序啦!在一般的狀態下, # 父程序的自訂變數是無法在子程序內使用的。但是透過 export 將變數變成 # 環境變數後,就能夠在子程序底下應用了!很不賴吧!至於程序的相關概念, # 我們會在『程序與資源管理』章節當中提到的喔! 範例六:如何進入到您目前核心的模組目錄? [root@linux ~]# cd /lib/modules/`uname -r`/kernel # 每個作業系統核心版本都不相同,以 FC4 為例,他的預設核心版本是 # 2.6.11-1.1369_FC4 所以,他的模組目錄在 /lib/modules/2.6.11-1.1369_FC4/kernel 。 # 因為每個 distributions 的這個值都不相同,但是我們卻可以利用 uname -r 這個指令 # 先取得版本資訊,所以囉,就可以透過上面指令當中的內含指令 `uname -r` # 先取得版本輸出到 cd .. 那個指令當中,就能夠順利的進入目前核心的驅動程式所放置 # 的目錄囉!很方便吧! 範例七:取消剛剛設定的 name 這個變數內容 [root@linux ~]# unset name根據上面的案例你可以試試看!就可以瞭解變數的設定囉!這個是很重要的呦!請勤加練習!! 其中,較為重要的一些特殊符號的使用囉!例如單引號、雙引號、跳脫字元、錢字號、quote 符號等等,底下的例題想一想吧!
例題二:在變數的設定當中,單引號與雙引號的用途有何不同? 答:
[root@linux ~]# name=VBird [root@linux ~]# echo $name VBird [root@linux ~]# myname="$name its me" [root@linux ~]# echo $myname VBird its me [root@linux ~]# myname='$name its me' [root@linux ~]# echo $myname $name its me 發現了嗎?沒錯!使用了單引號的時候,那麼 $name 將失去原有的變數內容, 僅為一般字元的顯示型態而已!這裡必需要特別小心在意! |
例題三:在指令下達的過程中, quote ( ` ) 這個符號代表的意義為何? 答:
另外再舉個例子,我們也知道, locate 指令可以列出所有的相關檔案檔名,但是, 如果我想要知道各個檔案的權限呢?舉例來說,我想要知道每個 crontab 相關檔名的權限: [root@linux ~]# ls -l `locate crontab` 如此一來,先以 locate 將檔名資料都列出來,再以 ls 指令來處理的意思啦!瞭了嗎? ^_^ |
範例一:列出目前的 shell 環境下的所有環境變數與其內容。 [root@linux ~]# env HOSTNAME=linux.dmtsai.tw <== 這部主機的主機名稱 SHELL=/bin/bash <== 目前這個環境下,使用的 Shell 是哪一個程式? TERM=xterm <== 這個終端機使用的環境是什麼類型 HISTSIZE=1000 <== 這個就是『記錄指令的筆數』在 FC4 預設可記錄 1000 筆 USER=root <== 使用者的名稱啊! LS_COLORS=no=00:fi=00:di=00;34:ln=00;36:pi=40;33:so=00;35:bd=40;33;01:cd=40;33;01: or=01;05;37;41:mi=01;05;37;41:ex=00;32:*.cmd=00;32:*.exe=00;32:*.com=00;32:*.btm=0 0;32:*.bat=00;32:*.sh=00;32:*.csh=00;32:*.tar=00;31:*.tgz=00;31:*.arj=00;31:*.taz= 00;31:*.lzh=00;31:*.zip=00;31:*.z=00;31:*.Z=00;31:*.gz=00;31:*.bz2=00;31:*.bz=00;3 1:*.tz=00;31:*.rpm=00;31:*.cpio=00;31:*.jpg=00;35:*.gif=00;35:*.bmp=00;35:*.xbm=00 ;35:*.xpm=00;35:*.png=00;35:*.tif=00;35: <== 一些顏色顯示 ENV=/root/.bashrc <== 使用的個人環境設定檔 MAIL=/var/spool/mail/root <== 這個使用者所取用的 mailbox 位置 PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/X11R6/bin:/usr/local/bin:/usr/local/sbin: /root/bin <== 不再多講啊!是執行檔指令搜尋路徑 INPUTRC=/etc/inputrc <== 與鍵盤按鍵功能有關。可以設定特殊按鍵! PWD=/root <== 目前使用者所在的工作目錄 (利用 pwd 取出!) LANG=en_US.UTF-8 <== 這個與語系有關,底下會再介紹! HOME=/root <== 這個使用者的家目錄啊! _=/bin/env <== 上一次使用的指令的最後一個參數(或指令本身)env 是 environment (環境) 的簡寫啊~ 上面的例子當中,是列出來所有的環境變數。當然,如果使用 export 也會是一樣的內容~ 只不過, export 還有其他額外的功能就是了,我們等一下再提這個 export 指令。 那麼上面這些變數有些什麼功用呢?底下我們就一個一個來分析分析!
[root@linux ~]# declare -i number=$RANDOM*10/32767 ; echo $number 8 <== 此時會隨機取出 0~9 之間的數值喔!
[root@linux ~]# set BASH=/bin/bash <== bash 的主程式放置路徑 BASH_VERSINFO=([0]="3" [1]="00" [2]="16" [3]="1" [4]="release" [5]="i386-redhat-linux-gnu") <== bash 的版本啊! BASH_VERSION='3.00.16(1)-release' <== bash 的版本啊! COLORS=/etc/DIR_COLORS.xterm <== 使用的顏色紀錄檔案 COLUMNS=115 <== 在目前的終端機環境下,使用的欄位有幾個字元長度 HISTFILE=/root/.bash_history <== 歷史命令記錄的放置檔案,隱藏檔 HISTFILESIZE=1000 <== 存起來(與上個變數有關)的檔案之指令的最大紀錄筆數。 HISTSIZE=1000 <== 目前環境下,可記錄的歷史命令最大筆數。 HOSTTYPE=i386 <== 主機安裝的軟體主要類型。我們用的是 i386 相容機器軟體 IFS=$' \t\n' <== 預設的分隔符號 LINES=35 <== 目前的終端機下的最大行數 MACHTYPE=i386-redhat-linux-gnu <== 安裝的機器類型 MAILCHECK=60 <== 與郵件有關。每 60 秒去掃瞄一次信箱有無新信! OLDPWD=/home <== 上個工作目錄。我們可以用 cd - 來取用這個變數。 OSTYPE=linux-gnu <== 作業系統的類型! PPID=20046 <== 父程序的 PID (會在後續章節才介紹) PROMPT_COMMAND='echo -ne "\033]0;${USER}@${HOSTNAME%%.*}:${PWD/#$HOME/~}\007"' <== 上面這個是命令提示字元!與底下也有關。 PS1='[\u@\h \W]\$ ' <== PS1 就厲害了。這個是命令提示字元,也就是我們常見的 [root@linux ~]# 或 [dmtsai ~]$ 的設定值啦!可以更動的! RANDOM=13586 <== 亂數啊!上面已經提過囉~ SUPPORTED=zh_TW.UTF-8:zh_TW:zh:en_US.UTF-8 <== 本系統所支援的語系 name=VBird <== 剛剛設定的自訂變數也可以被列出來喔! $ <== 目前這個 shell 所使用的 PID ? <== 剛剛執行完指令的回傳值。一般來說,不論是否為環境變數,只要跟我們目前這個 shell 的操作介面有關的變數, 通常都會被設定為大寫字元,也就是說,『基本上,在 Linux 預設的情況中,使用{大寫的字母}來設定的變數一般為系統內定需要的變數』。
[root@linux home]# PS1='[\u@\h \w \A #\#]\$ ' [root@linux /home 17:02 #85]# # 看到了嗎?提示字元變了!變的很有趣吧!其中,那個 #85 比較有趣, # 如果您按下 [Enter] 後,該數字就會增加喔!為啥?上面有說明ㄇㄟ!
[root@linux ~]# echo $SHELL /bin/bash [root@linux ~]# echo $? 0 # 因為上個指令執行過程中,並沒有錯誤,為成功的執行完畢,所以回傳 0 。 [root@linux ~]# 12name=VBird -bash: 12name=VBird: command not found [root@linux ~]# echo $? 127 # 發生錯誤啦!所以 echo $? 時,就會出現錯誤的代碼! # 我們可以利用這個代碼來搜尋錯誤的原因喔! [root@linux ~]# echo $? 0 # 咦!怎麼又變成正確了?這是因為 "?" 只與『上一個執行指令』有關, # 所以,我們上一個指令是執行『 echo $? 』,當然沒有錯誤,所以是 0 沒錯!
[root@linux ~]# export declare -x ENV="/root/.bashrc" declare -x HISTSIZE="1000" declare -x HOME="/root" declare -x HOSTNAME="linux.dmtsai.tw" declare -x INPUTRC="/etc/inputrc" declare -x LANG="en_US.UTF-8" declare -x MAIL="/var/spool/mail/root" declare -x SHELL="/bin/bash" # 很多都直接省略了!不然....重複性太高,浪費版面~ ^_^
[root@linux ~]# locale -a aa_DJ aa_DJ.iso88591 en_US en_US.iso88591 en_US.iso885915 en_US.utf8 zh_TW zh_TW.big5 zh_TW.euctw zh_TW.utf8 # 其實輸出的內容有很多,鳥哥將一些資訊捨棄了~ # 從上面的輸出中,我們也不難看出,系統是有支援 big5, utf8 等中文語系資料的!中文語系至少支援了兩種以上的編碼,一種是目前還是很常見的 big5 ,另一種則是越來越熱門的 utf-8 編碼。 那麼我們如何修訂這些編碼呢?其實可以透過底下這些變數的說:
[root@linux ~]# LANG <==主語言的環境 [root@linux ~]# LC_CTYPE <==字元辨識的編碼 [root@linux ~]# LC_NUMERIC <==數字系統的顯示訊息 [root@linux ~]# LC_TIME <==時間系統的顯示資料 [root@linux ~]# LC_COLLATE <==字串的比較與排序等 [root@linux ~]# LC_MONETARY <==幣值格式的顯示等 [root@linux ~]# LC_MESSAGES <==訊息顯示的內容,如功能表、錯誤訊息等 [root@linux ~]# LC_ALL <==語言環境的整體設定。基本上,你可以逐一設定每個與語系有關的變數資料,但事實上,如果其他的語系變數都未設定, 且您有設定 LANG 或者是 LC_ALL 時,則其他的語系變數就會被這兩個變數所取代! 這也是為什麼我們在 FC4 當中,通常僅設定 LANG 這個變數而已!因為他是最主要的設定變數。 好了,那麼你應該要覺得奇怪的是,為什麼在 Linux 主機的終端機介面 (tty1 ~ tty6) 的環境下,如果 LANG=zh_TW.big5 這個設定值生效後,使用 man 或者其他訊息輸出時, 都會有一堆亂碼,尤其是使用 ls -l 這個參數時?
[root@linux ~]# vi /etc/sysconfig/i18n
LANG="en_US.UTF-8"
SYSFONT="latarcyrheb-sun16"
SUPPORTED="zh_TW.UTF-8:zh_TW:zh:en_US.UTF-8"
你可以在這個檔案當中加入 LC_TIME 或者其他語系相關變數的設定內容,
也可以直接修改 LANG 那個變數即可啊! ^_^ 但,事實上,我們還可以透過個人的環境設定檔來設定 LANG 呢!
如此一來,則不必修訂系統的語系檔案,比較安全啦![root@linux ~]# read [-pt] variable 參數: -p :後面可以接提示字元! -t :後面可以接等待的『秒數!』這個比較有趣~不會一直等待使用者啦! 範例: 範例一:讓使用者由鍵盤輸入一內容,將該內容變成 atest 變數 [root@linux ~]# read atest This is a test [root@linux ~]# echo $atest This is a test 範例二:提示使用者 30 秒內輸入自己的大名,將該輸入字串做成 named 變數 [root@linux ~]# read -p "Please keyin your name: " -t 30 named Please keyin your name: VBird Tsai [root@linux ~]# echo $named VBird Tsairead 之後不加任何參數,直接加上變數名稱,那麼底下就會主動出現一個空白行,等待您輸入。 如果加上 -t 後面接秒數之後,例如上面的範例當中,那麼 30 秒之內沒有任何動作時, 該指令就會自動略過了~如果是加上 -p ,嘿嘿!後面就會有比較多可以用的提示字元給我們參考! 在指令的下達裡面,比較美觀啦! ^_^
[root@linux ~]# declare [-aixr] variable 參數: -a :將後面的 variable 定義成為陣列 (array) -i :將後面接的 variable 定義成為整數數字 (integer) -x :用法與 export 一樣,就是將後面的 variable 變成環境變數; -r :將一個 variable 的變數設定成為 readonly ,該變數不可被更改內容,也不能 unset 範例: 範例一:讓變數 sum 進行 100+300+50 的加總結果 [root@linux ~]# sum=100+300+50 [root@linux ~]# echo $sum 100+300+50 <==咦!怎麼沒有幫我計算加總?因為這是文字型態的變數屬性啊! [root@linux ~]# declare -i sum=100+300+50 [root@linux ~]# echo $sum 450 <==瞭乎?? 範例二:將 sum 變成環境變數 [root@linux ~]# declare -x sum 範例三:讓 sum 變成唯讀屬性,不可更動! [root@linux ~]# declare -r sum [root@linux ~]# sum=tesgting -bash: sum: readonly variable <==老天爺~不能改這個變數了!declare 也是個很有用的功能~尤其是當我們需要使用到底下的陣列功能時, 他也可以幫我們宣告陣列的屬性喔!不過,老話一句,陣列也是在 shell script 比較常用的啦!
範例:設定上面提到的 var[1] ~ var[3] 的變數。 [root@linux ~]# var[1]="small min" [root@linux ~]# var[2]="big min" [root@linux ~]# var[3]="nice min" [root@linux ~]# echo "${var[1]}, ${var[2]}, ${var[3]}"比較有趣的地方在於『讀取』,一般來說,建議直接以 ${陣列} 的方式來讀取, 比較正確無誤的啦!
[root@linux ~]# ulimit [-SHacdflmnpstuv] [配額] 參數: -H :hard limit ,嚴格的設定,必定不能超過設定的值; -S :soft limit ,警告的設定,可以超過這個設定值,但是會有警告訊息, 並且,還是無法超過 hard limit 的喔!也就是說,假設我的 soft limit 為 80 , hard limit 為 100 ,那麼我的某個資源可以用到 90 , 可以超過 80 ,還是無法超過 100 ,而且在 80~90 之間,會有警告訊息的意思。 -a :列出所有的限制額度; -c :可建立的最大核心檔案容量 (core files) -d :程序資料可使用的最大容量 -f :此 shell 可以建立的最大檔案容量 (一般可能設定為 2GB)單位為 Kbytes -l :可用於鎖定 (lock) 的記憶體量 -p :可用以管線處理 (pipe) 的數量 -t :可使用的最大 CPU 時間 (單位為秒) -u :單一使用者可以使用的最大程序(process)數量。 範例: 範例一:列出所有的限制資料 [root@linux ~]# ulimit -a 範例二:限制使用者僅能建立 1MBytes 以下的容量的檔案 [root@linux ~]# ulimit -f 1024還記得我們在 Linux 磁碟檔案系統 裡面提到過,單一 filesystem 能夠支援的單一檔案大小與 block 的大小有關。例如 block size 為 1024 byte 時,單一檔案可達 16GB 的容量。但是,我們可以用 ulimit 來限制使用者可以建立的檔案大小喔! 利用 ulimit -f 就可以來設定了!例如上面的範例二,要注意單位喔!單位是 Kbytes。 若改天你一直無法建立一個大容量的檔案,記得瞧一瞧 ulimit 的資訊喔!( 不過,要注意的是,一般身份使用者如果以 ulimit 設定了 -f 的檔案大小, 那麼他『只能減小檔案大小,不能增加檔案大小喔!』)
[root@linux ~]# echo $HOME [root@linux ~]# echo ${HOME}那麼,在那個 ${variable} 的使用方法中,其實,我們還可以將變數進行一些修訂的工作喔! 只要加上一些字符標誌,後面再接著使用比對字串,就能夠修改變數的內容了! 我們取底下的例子來說明:在底下的例子中,假設我的變數名稱為 vbird ,且內容為 /home/vbird/testing/testing.x.sh。
1. 完整呈現 vbird 這個變數的內容; [root@linux ~]# vbird="/home/vbird/testing/testing.x.sh" [root@linux ~]# echo ${vbird} /home/vbird/testing/testing.x.sh 2. 在 vbird 變數中,從最前面開始比對,若開頭為 / ,則刪除兩個 / 之間的所有資料,亦即 /*/ [root@linux ~]# echo ${vbird##/*/} testing.x.sh <==刪除了 /home/vbird/testing/ [root@linux ~]# echo ${vbird#/*/} vbird/testing/testing.x.sh <==僅刪除 /home/ 而已 # 這兩個小例子有趣了~變數名稱後面如果接了兩個 ## ,表示在 ## # 後面的字串取『最長的』那一段;如果僅有一個 # ,表示取『最小的那一段』喔! 3. 承上題,如果是從後面開始,刪除 /* 呢? [root@linux ~]# echo ${vbird%%/*/} /home/vbird/testing/testing.x.sh <==都沒被刪除 [root@linux ~]# echo ${vbird%%/*} <==被刪除光了! [root@linux ~]# echo ${vbird%/*} /home/vbird/testing <==只刪除 /testing.x.sh 部分 # 這個例子當中需要特別注意,那個 % 比對的是『最後面那個字元』的意思, # 所以囉,第一個方式當然不對~因為 vbird 這個變數的內容最後面是 h 而不是 / 啊! # 至於 %%/* 則是刪除『最長的那個 /* 』,當然就是全部喔!而 %/* 則是最短的那個! 4. 將 vbird 變數中的 testing 取代為 TEST [root@linux ~]# echo ${vbird/testing/TEST} /home/vbird/TEST/testing.x.sh [root@linux ~]# echo ${vbird//testing/TEST} /home/vbird/TEST/TEST.x.sh # 如果變數後面接的是 / 時,那麼表示後面是進行『取代』的工作~而且僅取代『第一個』 # 但如果是 // ,則表示全部的字串都取代啊!這裡您稍微留意一下就好了~反正就是變數後面可以接 #, ##, %, %%, /, // , 而他們存在的意義並不相同的啦~
變數設定方式 | str 沒有設定 | str 為空字串 | str 已設定非為空字串 |
var=${str-expr} | var=expr | var= | var=$str |
var=${str:-expr} | var=expr | var=expr | var=$str |
var=${str+expr} | var= | var=expr | var=expr |
var=${str:+expr} | var= | var= | var=expr |
var=${str=expr} | str=expr var=expr |
str 不變 var= | str 不變 var=$str |
var=${str:=expr} | str=expr var=expr |
str=expr var=expr | str 不變 var=$str |
var=${str?expr} | expr 輸出至 stderr | var= | var=str |
var=${str:?expr} | expr 輸出至 stderr | expr 輸出至 stderr | var=str |
範例一:若 str 這個變數內容存在,則 var 設定為 str ,否則 var 設定為 "newvar" [root@linux ~]# unset str; var=${str-newvar} [root@linux ~]# echo var="$var", str="$str" var=newvar, str= <==因為 str 不存在,所以 var 為 newvar [root@linux ~]# str="oldvar"; var=${str-newvar} [root@linux ~]# echo var="$var", str="$str" var=oldvar, str=oldvar <==因為 str 存在,所以 var 等於 str 的內容 範例二:若 str 不存在,則 var 與 str 均設定為 newvar,否則 var 與 str 相同 [root@linux ~]# unset str; var=${str=newvar} [root@linux ~]# echo var="$var", str="$str" var=newvar, str=newvar <==因為 str 不存在,所以 var/str 均為 newvar [root@linux ~]# str="oldvar"; var=${str=newvar} [root@linux ~]# echo var="$var", str="$str" var=oldvar, str=oldvar <==因為 str 存在,所以 var 等於 str 的內容 範例三:若 str 這個變數存在,則 var 等於 str ,否則輸出 "novar" [root@linux ~]# unset str; var=${str?novar} -bash: str: novar <==因為 str 不存在,所以輸出錯誤訊息 [root@linux ~]# str="oldvar"; var=${str?novar} [root@linux ~]# echo var="$var", str="$str" var=oldvar, str=oldvar <==因為 str 存在,所以 var 等於 str 的內容 # 上面這三個案例都沒有提到當 str 有設定,且為空字串的情況喔! # 您可以自行測試一下哩!
[root@linux ~]# alias lm='ls -l | more'
嘿嘿!我立刻多出了一個可以執行的指令喔!這個指令名稱為 lm ,且其實他是執行
ls -al | more 啊!真是方便。不過,
要注意的是:『alias 的定義規則與變數定義規則幾乎相同』,
所以你只要在 alias 後面加上你的 {『別名』='指令 參數' },
以後你只要輸入 lm 就相當於輸入了 ls -al|more 這一串指令!很方便吧!
[root@linux ~]# alias rm='rm -i'
嘿嘿!那麼以後使用 rm 的時候,就不用太擔心會有錯誤刪除的情況了!這也是命令別名的優點囉!
那麼如何知道目前有哪些的命令別名呢?就使用 alias 呀!
[root@linux ~]# alias
alias l.='ls -d .* --color=tty'
alias ll='ls -l --color=tty'
alias lm='ls -al | more'
alias ls='ls --color=tty'
alias vi='vim'
alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'
由上面的資料當中,您也會發現一件事情啊,我們在 vi 文書編輯器 裡面提到
vi 與 vim 是不太一樣的, vi 是比較老,而 vim 可以用來取代 vi 喔。我們的 FC4 明明就同時有 vi/vim ,
為何我執行 vi 會是進入 vim 呢?呵呵!那就是因為上面的表格當中的『 alias vi='vim' 』這個設定啦!
至於如果要取消命令別名的話,那麼就使用 unalias 吧!例如要將剛剛的 lm 命令別名拿掉,就使用:
[root@linux ~]# unalias lm
那麼命令別名與變數有什麼不同呢?基本上,他們的意義就不太一樣了! alias
這種命令別名,你可以將他想成是建立一個新的指令名稱,
至於變數則僅是將一個數值或者字串存在某個代表意義當中!舉個例子好了,我們知道以前的
DOS 年代,列出目錄與檔案就是 dir ,而清除螢幕就是 cls ,那麼如果我想要在
linux 裡面也使用相同的指令呢?那就以 alias 來進行指令的別名設定:
[root@linux ~]# history [n] [root@linux ~]# history [-c] [root@linux ~]# history [-raw] histfiles 參數: n :數字,意思是『要列出最近的 n 筆命令列表』的意思! -c :將目前的 shell 中的所有 history 內容全部消除 -a :將目前新增的 history 指令新增入 histfiles 中,若沒有加 histfiles , 則預設寫入 ~/.bash_history -r :將 histfiles 的內容讀到目前這個 shell 的 history 記憶中; -w :將目前的 history 記憶內容寫入 histfiles 中! 範例: 範例一:列出目前記憶體內的所有 history 記憶 [root@linux ~]# history # 前面省略 1017 man bash 1018 ll 1019 history 1020 history # 列出的資訊當中,共分兩欄,第一欄為該指令在這個 shell 當中的代碼, # 另一個則是指令本身的內容喔!至於會秀出幾筆指令記錄,則與 HISTSIZE 有關! 範例二:列出目前最近的 3 筆資料 [root@linux ~]# history 3 1019 history 1020 history 1021 history 3 範例三:立刻將目前的資料寫入 histfile 當中 [root@linux ~]# history -w # 在預設的情況下,會將歷史紀錄寫入 ~/.bash_history 當中! [root@linux ~]# echo $HISTSIZE 1000在正常的情況下,當我們以 bash 登入 Linux 主機之後,系統會主動的由家目錄的 ~/.bash_history 讀取以前曾經下過的指令,那麼 ~/.bash_history 會記錄幾筆資料呢?這就與你 bash 的 HISTSIZE 這個變數設定值有關了!在預設的 FC4 底下,是會記錄 1000 筆資料的! 那麼假設我這次登入主機後,共下達過 100 次指令,『等我登出時, 系統就會將 101~1100 這總共 1000 筆歷史命令更新到 ~/.bash_history 當中。』 也就是說,歷史命令在我登出時,會將最近的 HISTSIZE 筆記錄到我的紀錄檔當中啦! 當然,也可以用 history -w 強制立刻寫入的!那為何用『更新』兩個字呢? 因為 ~/.bash_history 記錄的筆數永遠都是 HISTSIZE 那麼多,舊的訊息會被主動的拿掉! 僅保留最新的!
[root@linux ~]# !number [root@linux ~]# !command [root@linux ~]# !! 參數: number :執行第幾筆指令的意思; command :由最近的指令向前搜尋『指令串開頭為 command』的那個指令,並執行; !! :就是執行上一個指令(相當於按↑按鍵後,按 Enter) 範例: [root@linux ~]# history 66 man rm 67 alias 68 man history 69 history [root@linux ~]# !66 <==執行第 66 筆指令 [root@linux ~]# !! <==執行上一個指令,本例中亦即 !66 [root@linux ~]# !al <==執行最近以 al 為開頭的指令(上頭列出的第 67 個)經過上面的介紹,瞭乎?歷史命令用法可多了!如果我想要執行上一個指令, 除了使用上下鍵之外,我可以直接以『 !! 』 來下達上個指令的內容,此外, 我也可以直接選擇下達第 n 個指令,『 !n 』來執行,也可以使用指令標頭,例如 『 !vi 』來執行最近指令開頭是 vi 的指令列!相當的方便而好用!基本上 history 的用途很大的!但是需要小心安全的問題!尤其是 root 的歷史紀錄檔案,這是 Cracker 的最愛!因為不小心的 root 會將很多的重要資料在執行的過程中會被紀錄在 ~/.bash_history 當中,如果這個檔案被解析的話,後果不堪吶!無論如何,使用 history 配合『 ! 』曾經使用過的指令下達是很有效率的一個指令方法!
[root@linux ~]# /bin/more .bashrc
我在的目錄為 /home/test !這是絕對路徑寫法! 而如果你還記得我們在
Linux 檔案與目錄管理 那一篇文章中提到的觀念的話,那麼應該記得使用
ls -al 時會出現兩個一定存在的目錄,分別是『.』與『..』,分別代表是『這個路徑』,與『上一層路徑』!
[root@linux ~]# ls -al
drwxrwxr-x 2 root root 4096 Aug 15 11:05 .
drwxrwxr-x 2 root root 4096 Aug 14 23:26 ..
所以說,要執行上一層目錄中的命令,可以下達『../command 』那個 command
指的是存在的可執行檔!那麼我因為在 /home/test 裡面,距離 /bin 有兩層上層目錄,所以我要使用
/bin/more 這個執行檔,並且使用相對路徑的方法,就必須使用:
[root@linux ~]# ../../bin/more .bashrc
這種相對路徑的方法相當廣泛的被運用於 script 當中,這是因為如前面提到的,
每個人的安裝預設的目錄都不相同,則使用相對路徑的話,
很容易就可以找到套件之間相依軟體或者是設定檔案的相關性!
例題:關於路徑搜尋的問題!為何不執行目前所在目錄下的檔案? 答:
那麼為何不要設定這個路徑呢?這是因為『 安全』的考量。由於系統預設是允許任何人在 /tmp 底下寫入任何檔案的,那麼萬一有居心不良的使用者或者是 Cracker 入侵你的電腦,並在你的 /tmp 裡頭埋了一個小木馬,並取名為 ls ,好了,改天你以 root 身份登入後,到 /tmp 底下,並執行 ls ,你看會有什麼結果?!這個 /tmp/ls 由其他身份的人來執行或許沒有問題,但是由 root 來執行卻可能會導致 Cracker 所樂意見到的結果!那曉得為何了吧?! 當然囉!您還是可以選擇在 ~/.bashrc 當中設定你的 . 在你的 PATH 當中,不過並不這麼建議就是了! |
[root@linux ~]# ./squid
請特別留意這方面的問題!『新手特別容易犯這個錯誤呢!』
[root@linux ~]# cat /etc/issue
Fedora Core release 4 (Stentz)
Kernel \r on an \m
在 FC4 裡面預設有三行,這個在我們本機登入時就會顯示在 title 的地方呢~
咦!那麼那個 \r 及 \m 是啥?您可以使用 man issue 配合 man mingetty 就能夠知道:issue 內的各代碼意義 |
\d 本地端時間的日期; \l 顯示第幾個終端機介面; \m 顯示硬體的等級 (i386/i486/i586/i686...); \n 顯示主機的網路名稱; \o 顯示 domain name; \r 作業系統的版本 (相當於 uname -r) \t 顯示本地端時間的時間; \s 作業系統的名稱; \v 作業系統的版本。 |
[root@linux ~]# vi /etc/motd Hello everyone, Our server will be maintained at 2005/10/10 0:00 ~ 24:00. Please don't login at that time. ^_^那麼當你的使用者登入主機後,就會顯示這樣的訊息出來:
Last login: Mon Aug 15 10:17:10 2005 from 127.0.0.1 Hello everyone, Our server will be maintained at 2005/10/10 0:00 ~ 24:00. Please don't login at that time. ^_^是否很方便啊!? ^_^
[root@linux ~]# cat /etc/sysconfig/i18n
LANG="zh_TW.UTF-8"
SYSFONT="latarcyrheb-sun16"
SUPPORTED="zh_TW.UTF-8:zh_TW:zh:en_US.UTF-8"
我預設使用 zh_TW.UTF-8 來作為我的整體語系,當然,我可以在這裡修改 LANG 以及其他相關的語系變數,
例如 LC_CTYPE 或者是 LC_TIME 等等的。不過,一般來說,使用者自己個人的設定不建議在這裡做更動啦!
他們可以自行設定他們自己的設定檔啊!
[root@linux ~]# vi ~/.bashrc
# .bashrc
# Source global definitions
if [ -f /etc/bashrc ]; then
. /etc/bashrc
fi
# User specific aliases and functions
PATH="/bin:/sbin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin"
PATH="$PATH":/usr/X11R6/bin:/home/dmtsai/bin
LANG=zh_TW.big5
LC_TIME=C
export PATH LC_TIME LANG
umask 022
alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'
alias ll='ls -l'
alias lm='ls -al|more'
alias h='history'
仔細看到上頭這個檔案,會不會覺得奇怪啊!為什麼會有第五行的『 . /etc/bashrc 』呢?
那個小數點 (.) 代表什麼意思啊??其實 if [ ... ]; then .... fi 是 shell script 當中的程式寫法,
這個我們會在下一章當中介紹。不過,那個 . 則需要好好的談一談喔!一般來說,如果修改完了設定檔,
通常就是 logout 後再重新 login 到 bash 內,就能夠將環境設定檔重讀了!不過,
我們可以使用底下的方式來讓該設定檔立即生效:[root@linux ~]# source file 範例: [root@linux ~]# source ~/.bashrc [root@linux ~]# . ~/.bashrc利用 source 或小數點 (.) 都可以將設定檔的內容讀進來目前的 shell 環境中! 舉例來說,我修改了 ~/.bashrc ,那麼不需要登出,立即以 source ~/.bashrc 就可以將剛剛最新設定的內容讀進來目前的環境中!很不錯吧!此外,什麼時候會使用到不同的設定檔呢? 最常發生在一個人的工作環境分為多重的時候了!舉個例子來說,在我的大型主機中, 我常常需要負責兩到三個不同的案子,每個案子所需要處理的環境變數訂定並不相同, 那麼我就將這兩三個案子分別編寫屬於該案子的環境變數設定檔案,當我需要該環境時,就直接『 source 變數檔 』,如此一來,環境變數的設定就變的更簡便而靈活了!
[root@linux ~]# stty [-a] 參數: -a :將目前所有的 stty 參數列出來; 範例: 範例一:列出所有的按鍵與按鍵內容 [root@linux ~]# stty -a speed 38400 baud; rows 40; columns 80; line = 0; intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol =我們可以利用 stty -a 來列出目前環境中所有的按鍵列表,在上頭的列表當中,需要注意的是特殊字體那幾個, 此外,如果出現 ^ 表示 [Ctrl] 那個按鍵的意思。舉例來說, intr = ^C 表示利用 [ctrl] + c 來達成的。 幾個重要的代表意義是:; eol2 = ; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0; -parenb -parodd cs8 -hupcl -cstopb cread -clocal -crtscts -ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany -imaxbel opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0 isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke
[root@linux ~]# stty erase ^h
那麼從此之後,你的刪除字元就得要使用 [ctrl]+h 囉,按下 [backspace] 則會出現 ^? 字樣呢!
如果想要回復利用 [backspace] ,就下達 stty erase ^? 即可啊!
至於更多的 stty 說明,記得參考一下 man stty 的內容喔![root@linux ~]# set [-uvCHhmBx] 參數: -u :預設不啟用。若啟用後,當使用未設定變數時,會顯示錯誤訊息; -v :預設不啟用。若啟用後,在訊息被輸出前,會先顯示訊息的原始內容; -x :預設不啟用。若啟用後,在指令被執行前,會顯示指令內容(前面有 ++ 符號) -h :預設啟用。與歷史命令有關(下節介紹); -H :預設啟用。與歷史命令有關(下節介紹); -m :預設啟用。與工作管理有關(未來介紹); -B :預設啟用。與刮號 [] 的作用有關; -C :預設不啟用。若使用 > 等,則若檔案存在時,該檔案不會被覆蓋。 範例: 範例一:顯示目前所有的 set 設定值 [root@linux ~]# echo $- himBH # 那個 $- 變數內容就是 set 的所有設定啦! bash 預設是 himBH 喔! 範例二:設定 "若使用未定義變數時,則顯示錯誤訊息" [root@linux ~]# set -u [root@linux ~]# echo $vbirding -bash: vbirding: unbound variable # 預設情況下,未設定/未宣告 的變數都會是『空的』,不過,若設定 -u 參數, # 那麼當使用未設定的變數時,就會有問題啦!很多的 shell 都預設啟用 -u 參數。 # 若要取消這個參數,輸入 set +u 即可! 範例三:執行前,顯示該指令內容。 [root@linux ~]# set -x [root@linux ~]# echo $HOME + echo /root /root ++ echo -ne '\033]0;root@linux:~\007' # 看見否?要輸出的指令都會先被列印到螢幕上喔!前面會多出 + 的符號!另外,其實我們還有其他的按鍵設定功能呢!就是在 /etc/inputrc 這個檔案裡面設定。
[root@linux ~]# cat /etc/inputrc # do not bell on tab-completion #set bell-style none set meta-flag on set input-meta on set convert-meta off set output-meta on .....以下省略.....還有例如 /etc/DIR_COLORS* 與 /etc/termcap 等,也都是與終端機有關的環境設定檔案呢! 不過,事實上,鳥哥並不建議您修改 tty 的環境呢,這是因為 bash 的環境已經設定的很親和了, 我們不需要額外的設定或者修改,否則反而會產生一些困擾。不過,寫在這裡的資料, 只是希望大家能夠清楚的知道我們的終端機是如何進行設定的喔! ^_^
符號 | 內容 |
* | 萬用字元,代表 0 個或多個字元(或數字) |
? | 萬用字元,代表『一定有』一個字母 |
# | 註解,這個最常被使用在 script 當中,視為說明! |
\ | 跳脫符號,將『特殊字元或萬用字元』還原成一般字元 |
| | 分隔兩個管線命令的界定; |
; | 連續性命令的界定(注意!與管線命令並不相同) |
~ | 使用者的家目錄 |
$ | 亦即是變數之前需要加的變數取代值 |
& | 將指令變成背景下工作 |
! | 邏輯運算意義上的『非』 not 的意思! |
/ | 路徑分隔的符號 |
>, >> | 輸出導向,分別是『取代』與『累加』 |
' | 單引號,不具有變數置換的功能 |
" | 具有變數置換的功能! |
` ` | 兩個『 ` 』中間為可以先執行的指令! |
( ) | 在中間為子 shell 的起始與結束 |
[ ] | 在中間為字元的組合 |
{ } | 在中間為命令區塊的組合! |
組合按鍵 | 執行結果 |
Ctrl + C | 終止目前的命令 |
Ctrl + D | 輸入結束(EOF),例如郵件結束的時候; |
Ctrl + M | 就是 Enter 啦! |
Ctrl + S | 暫停螢幕的輸出 |
Ctrl + Q | 恢復螢幕的輸出 |
Ctrl + U | 在提示字元下,將整列命令刪除 |
Ctrl + Z | 『暫停』目前的命令 |
[root@linux ~]# ls test* <==那個 * 代表後面不論接幾個字元都予以接受 [root@linux ~]# ls test? <==那個 ? 代表後面『一定』要接『一個』字元 [root@linux ~]# ls test??? <==那個 ??? 代表『一定要接三個』字元! [root@linux ~]# cp test[1-5] /tmp # 將 test1, test2, test3, test4, test5 若存在的話,就拷貝到 /tmp [root@linux ~]# cp test[!1-5] /tmp # 只要不是 test1, test2, test3, test4, test5 之外的其他 test? , # 若存在的話,就拷貝到 /tmp [root@linux ~]# cd /lib/modules/`uname -r`/kernel/drivers # 被 ` ` 括起來的內容『會先執行』上面幾個例子相當的有趣!尤其是最後面兩個!需要注意的是, [1-5] 裡面『代表只有一個字元』但是範圍可以由 1-5 ,這樣來說的話,那麼我們如果允許『只要檔名裡面含有至少一個大寫字元』時,就可以將檔案 copy 出來的話,可以這樣做:
[root@linux ~]# ls -l / > ~/rootfile # 本來 ls -l / 會將根目錄的資料列出到螢幕上; # 現在我使用了 > ~/rootfile 後,則本來應該在螢幕上出現的資料 # 就會被『重新導向』到 ~/rootfile 檔案內了!就可以將該資料儲存!此時,原本應該在螢幕上面出現的資料通通不見去~因為那些資料都被寫入到 ~/rootfile 去了! 當然,那個檔案的檔名隨便你取啦~如果你下達:『 cat ~/rootfile 』就可以看到原本應該在螢幕上面的資料囉。 那麼如果我再次下達:『 ls -l /home > ~/rootfile 』後,那麼那個 ~/rootfile 檔案的內容變成什麼? 呵呵!變成『僅有 ls -l /home 的資料』而已!咦!原本的 ls -l / 資料就不見了嗎?是的! 因為該檔案的建立方式是:
command | > 1> 2> 2>> < | 裝置或檔案 |
範例一:將目前目錄下的檔案資訊全部儲存到 list.txt 檔案中 [root@linux ~]# ls -al > list.txt 範例二:將根目錄下的資料也儲存到 list.txt 檔案中 [root@linux ~]# ls -al / >> list.txt好了,對於『 > , >> 』這兩個東西有一定的概念之後,我們來深入的談一談『資料流重導向』的觀念吧! 如前所述,基本上, Linux 執行的結果中,可以約略的分成『正確輸出』與『錯誤輸出』兩種資料。 例如,當你以一般身份執行 find 這個指令時,例如執行『 find / -name testing 』時,由於你是一般身份,又有些資料夾是不允許一般身份者進入的, 所以囉,當你使用 find 時,就會有錯誤訊息發生了!但同時如果有 testing 這個檔案在你可以進入的資料夾當中,那麼螢幕也會輸出到給你看!因此, 就具有正確的與錯誤的輸出兩種囉!(分別稱為 Stdout 與 Stderror)例如下面為執行結果: 裡面的『 find: /home/root: Permission denied 』就告訴你該資料夾你沒有權限進入, 這就是錯誤的輸出了,那麼『 /home/dmtsai/tseting 』就是正確的輸出了!
[dmtsai@linux ~]$ find /home -name testing find: /home/test1: Permission denied <== Starndard error find: /home/root: Permission denied <== Starndard error find: /home/masda: Permission denied <== Starndard error /home/dmtsai/testing <== Starndard output好了,那麼假如我們想要將資料輸出到 list 這個檔案中呢?執行『 find / -name testing > list 』 會有什麼結果?呵呵,你會發現 list 裡面存了剛剛那個『正確』的輸出資料, 至於螢幕上還是會有錯誤的訊息出現呢!傷腦筋!如果想要將正確的與錯誤的資料分別存入不同的檔案中需要怎麼做?! 呵呵!其實在資料的重導向方面,正確的寫法應該是『 1> 』與『 2> 』才對!但是如果只有 > 則預設是以 1> 來進行資料的!那個 1> 是輸出正確資料, 2> 則是錯誤資料輸出項目。也就是說:
[dmtsai@linux ~]$ find /home -name testing > list_right 2> list_error
這樣一來,剛剛執行的結果中,有 Permission 的那幾行錯誤資訊都會跑到 list_error
這個檔案中,至於正確的輸出資料則會存到 list_right 這個檔案中囉!這樣可以瞭解了嗎?
如果有點混亂的話,去休息一下再來看看吧!!
[dmtsai@linux ~]$ find /home -name testing > list_right 2> /dev/null
很神奇呦! error message 就會『不見了!』呵呵!真高興!另外,
如果我要將資料都寫到同一個檔案中呢?這個時候寫法需要用到特殊寫法,請注意底下的寫法呦![dmtsai@linux ~]$ find /home -name testing > list 2> list <==錯誤寫法 [dmtsai@linux ~]$ find /home -name testing > list 2>&1 <==正確寫法請特別留意這一點呢!同時寫入同一個檔案需要使用 2>&1 才對呦!
[root@linux ~]# cat > catfile testing cat file test <==這裡按下 [ctrl]+d 結束輸入來離開!此時就會有 catfile 這個檔案產生,而且該檔案的內容就是剛剛輸入的內容喔。 那麼,我是否可以使用其他檔案來取代鍵盤輸入呢?可以啊!這樣做!
[root@linux ~]# cat > catfile < somefile
我可以先編輯 somefile ,然後再以上述的指令來將資料輸出到 catfile 去呢!這樣可以理解了嗎?
能夠理解 < 之後,再來則是怪可怕一把的 << 這個連續兩個小於的符號了~
他代表的是『結束的輸入字元』的意思!舉例來講:『我要用 cat 直接將輸入的訊息輸出到 catfile 中,
且當輸入 eof 時,該次輸入就結束』,那我可以這樣做:[root@linux ~]# cat > catfile <<eof > This is a test testing > OK now stop > eof <==輸入這個玩意兒,嘿!立刻就結束了!看到了嗎?利用 << 右側的控制字元,我們可以終止一次輸入, 而不必輸入 [crtl]+d 來結束哩!這對程式寫作很有幫助喔!好了,那麼為何要使用命令輸出重導向呢? 這個問題一定會困擾你一下下的,如果你從來都沒有寫過 script 的話!好了,我們來說一說吧!
[root@linux ~]# sync; sync; shutdown -h now
在指令與指令中間利用分號 (;) 來隔開,這樣一來,分號前的指令執行完後,
就會立刻接著執行後面的指令了。這真是方便啊~再來,換個角度來想,
萬一我想要在某個目錄底下建立一個檔案,也就是說,如果該目錄存在的話,
那我才建立這個檔案,如果不存在,那就算了~目錄是否存在可以使用一些 bash 提供的判斷式功能,
但這裡假設我不曉得那個指令,但我知道我可以使用 ls 來判斷是否有該目錄的存在,
也就是說,我可以利用 ls directoryname 判斷是否存在,然後以 touch 建立一個檔案,
這兩個指令有相關性,那該如何寫呢?呵呵!可以利用 && 來作喔!
[root@linux ~]# ls /tmp && touch /tmp/testingagin
是否記得我們在變數的章節裡面談過這個奇怪的變數『 $? 』呢?
如果指令執行結果沒有錯誤訊息,那就會回傳 $?=0 ,如果有錯誤,
那回傳值就不會是 0 啊!經由這樣的判斷,我們也可以利用 && 來決定,
當前面的指令執行結果為正確 (例如:僅有 standard output 時),就可以接著執行後續的指令,
否則就予以略過!因此,當 ls /tmp 沒有問題,那麼就會接著執行 touch /tmp/testingagin 了!
萬一是這樣:
[root@linux ~]# ls /vbird && touch /vbird/test
因為我的系統裡面根本就不可能存在 /vbird 這個目錄呢!所以,執行 ls /vbird 就會回傳錯誤,
那麼後續的 touch /vbird/test 自然就不會動作囉!瞭解嗎?
[root@linux ~]# ls /tmp/vbirding || touch /tmp/vbirding
那個 || 剛好完全跟 && 相反,當前一個指令有錯誤時,在 || 後面的指令才會被執行!
(要注意,那個 | 是兩個 | ,而 | 按鍵則是反斜線 \ 同一個按鍵,
因此,按下 [Shift] 加上 [\] 就會出現那個 | 囉!)
因此,簡單的來說,當 ls /tmp/vbirding 發生錯誤時,才會使用 touch /tmp/vbirding 去建立這個檔案的意思。
是否很有趣啊?這個 || 及 && 對於系統管理員在管理某些檔案權限、存在等問題時,
可是很有用的東西喔!好了,現在我們來玩比較難一點的,看看底下的例題:
例題:以 ls 測試 /tmp/vbirding 是否存在,若存在則顯示 "exist" ,若不存在,則顯示 "not exist"! 答:
ls /tmp/vbirding && echo "exist" || echo "not exist" 意思是說,當 ls /tmp/vbirding 執行後,若正確,就執行 echo "exist" ,若有問題,就執行 echo "not exist" ! 那如果我寫成: ls /tmp/vbirding || echo "not exist" && echo "exist" 對不對啊?這其實是有問題的,為什麼呢?因為指令是一個一個往下執行,因此,在上面的例子當中,如果 /tmp/vbirding 不存在時,他會: 所以啊,嘿嘿!第二個例子裡面竟然會同時出現 not exist 與 exist 呢!真神奇~ |
[root@linux ~]# ls -al /etc | less
嘿嘿!如此一來,使用 ls 指令輸出後的內容,就能夠被 less 讀取,
並且利用 less 的功能,我們就能夠前後翻動相關的資訊了!很方便是吧?呵呵!
我們就來瞭解一下這個管線命令『 | 』的用途吧![root@linux ~]# cut -d'分隔字元' -f fields [root@linux ~]# cut -c 字元區間 參數: -d :後面接分隔字元。與 -f 一起使用; -f :依據 -d 的分隔字元將一段訊息分割成為數段,用 -f 取出第幾段的意思; -c :以字元 (characters) 的單位取出固定字元區間; 範例: 範例一:將 PATH 變數取出,我要找出第五個路徑。 [root@linux ~]# echo $PATH /bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/X11R6/bin:/usr/games: [root@linux ~]# echo $PATH | cut -d ':' -f 5 # 嘿嘿!如此一來,就會出現 /usr/local/bin 這個目錄名稱! # 因為我們是以 : 作為分隔符號,第五個就是 /usr/local/bin 啊! # 那麼如果想要列出第 3 與第 5 呢?,就是這樣: [root@linux ~]# echo $PATH | cut -d ':' -f 3,5 範例二:將 export 輸出的訊息,取得第 12 字元以後的所有字串 [root@linux ~]# export declare -x HISTSIZE="1000" declare -x INPUTRC="/etc/inputrc" declare -x KDEDIR="/usr" declare -x LANG="zh_TW.big5" ......其他省略...... [root@linux ~]# export | cut -c 12- HISTSIZE="1000" INPUTRC="/etc/inputrc" KDEDIR="/usr" LANG="zh_TW.big5" ......其他省略...... # 知道怎麼回事了吧?用 -c 可以處理比較具有格式的輸出資料! # 我們還可以指定某個範圍的值,例如第 12-20 的字元,就是 cut -c 12-20 等等! 範例三:用 last 將這個月登入者的資訊中,僅留下使用者大名 [root@linux ~]# last vbird tty1 192.168.1.28 Mon Aug 15 11:55 - 17:48 (05:53) vbird tty1 192.168.1.28 Mon Aug 15 10:17 - 11:54 (01:37) [root@linux ~]# last | cut -d ' ' -f 1 # 用 last 可以取得最近一個月登入主機的使用者資訊, # 而我們可以利用空白字元的間隔,取出第一個資訊,就是使用者帳號囉! # 但是因為 vbird tty1 之間空格有好幾個,並非僅有一個,所以,如果要找出 # tty1 其實不能以 cut -d ' ' -f 1,2 喔!輸出的結果會不是我們想要的。這個 cut 實在很好用!不過,說真的,除非你常常在分析 log 檔案,否則使用到 cut 的機會並不多!好了! cut 主要的用途在於將『同一行裡面的資料進行分解!』, 最常使用在分析一些數據或文字資料的時候!這是因為有時候我們會以某些字元當作分割的參數, 然後來將資料加以切割,以取得我們所需要的資料。我也很常使用這個功能呢!尤其是在分析 log 檔案的時候!不過, cut 在處理多空格相連的資料時,可能會比較吃力一點~
[root@linux ~]# grep [-acinv] '搜尋字串' filename 參數: -a :將 binary 檔案以 text 檔案的方式搜尋資料 -c :計算找到 '搜尋字串' 的次數 -i :忽略大小寫的不同,所以大小寫視為相同 -n :順便輸出行號 -v :反向選擇,亦即顯示出沒有 '搜尋字串' 內容的那一行! 範例: 範例一:將 last 當中,有出現 root 的那一行就取出來; [root@linux ~]# last | grep 'root' 範例二:與範例一相反,只要沒有 root 的就取出! [root@linux ~]# last | grep -v 'root' 範例三:在 last 的輸出訊息中,只要有 root 就取出,並且僅取第一欄 [root@linux ~]# last | grep 'root' |cut -d ' ' -f1 # 在取出 root 之後,利用上個指令 cut 的處理,就能夠僅取得第一欄囉!grep 是個很棒的指令喔!他支援的語法實在是太多了~用在正規表示法裡頭, 能夠處理的資料實在是多的很~不過,我們這裡先不談正規表示法~下一章再來說明~ 您先瞭解一下, grep 可以解析一行文字,取得關鍵字,若該行有存在關鍵字, 就會整行列出來!
[root@linux ~]# sort [-fbMnrtuk] [file or stdin] 參數: -f :忽略大小寫的差異,例如 A 與 a 視為編碼相同; -b :忽略最前面的空白字元部分; -M :以月份的名字來排序,例如 JAN, DEC 等等的排序方法; -n :使用『純數字』進行排序(預設是以文字型態來排序的); -r :反向排序; -u :就是 uniq ,相同的資料中,僅出現一行代表; -t :分隔符號,預設是 tab 鍵; -k :以那個區間 (field) 來進行排序的意思, 範例: 範例一:個人帳號都記錄在 /etc/passwd 下,請將帳號進行排序。 [root@linux ~]# cat /etc/passwd | sort adm:x:3:4:adm:/var/adm:/sbin/nologin apache:x:48:48:Apache:/var/www:/sbin/nologin bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin # 我省略很多的輸出~由上面的資料看起來, sort 是預設『以第一個』資料來排序, # 而且預設是以『文字』型態來排序的喔!所以由 a 開始排到最後囉! 範例二:/etc/passwd 內容是以 : 來分隔的,我想以第三欄來排序,該如何? [root@linux ~]# cat /etc/passwd | sort -t ':' -k 3 root:x:0:0:root:/root:/bin/bash iiimd:x:100:101:IIIMF server:/usr/lib/iiim:/sbin/nologin uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin operator:x:11:0:operator:/root:/sbin/nologin bin:x:1:1:bin:/bin:/sbin/nologin games:x:12:100:games:/usr/games:/sbin/nologin # 看到特殊字體的輸出部分了吧?怎麼會這樣排列啊?呵呵!沒錯啦~ # 如果是以文字型態來排序的話,原本就會是這樣,想要使用數字排序: # cat /etc/passwd | sort -t ':' -k 3 -n # 這樣才行啊!用那個 -n 來告知 sort 以數字來排序啊! 範例三:利用 last ,將輸出的資料僅取帳號,並加以排序 [root@linux ~]# last | cut -d ' ' -f1 | sortsort 同樣是很常用的指令呢!因為我們常常需要比較一些資訊啦! 舉個上面的第二個例子來說好了!今天假設你有很多的帳號,而且你想要知道最大的使用者 ID 目前到哪一號了!呵呵!使用 sort 一下子就可以知道答案咯!當然其使用還不止此啦! 有空的話不妨玩一玩!
[root@linux ~]# uniq [-ic] 參數: -i :忽略大小寫字元的不同; -c :進行計數 範例: 範例一:使用 last 將帳號列出,僅取出帳號欄,進行排序後僅取出一位; [root@linux ~]# last | cut -d ' ' -f1 | sort | uniq 範例二:承上題,如果我還想要知道每個人的登入總次數呢? [root@linux ~]# last | cut -d ' ' -f1 | sort | uniq -c這個指令用來將『重複的行刪除掉只顯示一個』,舉個例子來說, 你要知道這個月份登入你主機的使用者有誰,而不在乎他的登入次數,那麼就使用上面的範例, (1)先將所有的資料列出;(2)再將人名獨立出來;(3)經過排序;(4)只顯示一個! 由於這個指令是在將重複的東西減少,所以當然需要『配合排序過的檔案』來處理囉!
[root@linux ~]# wc [-lwm] 參數: -l :僅列出行; -w :僅列出多少字(英文單字); -m :多少字元; 範例: 範例一:那個 /etc/man.config 裡面到底有多少相關字、行、字元數? [root@linux ~]# cat /etc/man.config | wc 138 709 4506 # 輸出的三個數字中,分別代表: 『行、字數、字元數』 範例二:我知道使用 last 可以輸出登入者,但是 last 最後兩行並非帳號內容, 那麼請問,我該如何以一行指令串取得這個月份登入系統的總人次? [root@linux ~]# last | grep [a-zA-Z] | grep -v 'wtmp' | wc -l # 由於 last 會輸出空白行與 wtmp 字樣在最底下兩行,因此,我利用 # grep 取出非空白行,以及去除 wtmp 那一行,在計算行數,就能夠瞭解囉!wc 也可以當作指令?呵呵!這可不是上洗手間的 WC 呢! 這是相當有用的計算檔案內容的一個工具組喔!舉個例子來說, 當你要知道目前你的帳號檔案中有多少個帳號時,就使用這個方法:『 cat /etc/passwd | wc -l 』啦!因為 /etc/passwd 裡頭一行代表一個使用者呀! 所以知道行數就曉得有多少的帳號在裡頭了!而如果要計算一個檔案裡頭有多少個字元時,呵呵!就使用 wc -c 這個參數吧!
[root@linux ~]# tee [-a] file 參數: -a :以累加 (append) 的方式,將資料加入 file 當中! 範例: [root@linux ~]# last | tee last.list | cut -d " " -f1 # 這個範例可以讓我們將 last 的輸出存一份到 last.list 檔案中; [root@linux ~]# ls -l /home | tee ~/homefile | more # 這個範例則是將 ls 的資料存一份到 ~/homefile ,同時螢幕也有輸出訊息! [root@linux ~]# ls -l / | tee -a ~/homefile | more # 要注意: tee 後接的檔案會被覆蓋,所以,我們要加上 -a # 這個參數才能將訊息累加。有沒有發現在命令重導向的時候,如果我們要將資料送出到檔案的時候, 螢幕上就不會出現任何的資料!那麼如果我們需要將資料同時顯示在螢幕上跟檔案中呢?呵呵!這個時候就需要 tee 這個指令囉!使用 last 可以查看到這個月份的登入資料,而使用了 tee 之後,會將資料同時傳給下一個命令去執行,也會將資料寫入 last.list 這個檔案中!也是個好幫手!
[root@linux ~]# tr [-ds] SET1 ... 參數: -d :刪除訊息當中的 SET1 這個字串; -s :取代掉重複的字元! 範例: 範例一:將 last 輸出的訊息中,所有的小寫變成大寫字元: [root@linux ~]# last | tr '[a-z]' '[A-Z]' 範例二:將 /etc/passwd 輸出的訊息中,將冒號 (:) 刪除 [root@linux ~]# cat /etc/passwd | tr -d ':' 範例三:將 DOS 檔案的斷行字元 ^M 符號刪除: [root@linux ~]# cat /home/test/dostxt | tr -d '\r' > dostxt-noM # 那個 \r 指的是 DOS 的斷行字元,關於更多的字符,請參考 man tr其實這個指令也可以寫在『正規表示法』裡頭!因為他也是由正規表示法的方式來取代資料的! 以上面的例子來說,使用 [] 可以設定一串字呢! 也常常用來取代檔案中的怪異符號! 例如上面第三個例子當中,可以去除 DOS 檔案留下來的 ^M 這個斷行的符號!這東西相當的有用!相信處理 Linux & Windows 系統中的人們最麻煩的一件事就是這個事情啦!亦即是 DOS 底下會自動的在每行行尾加入 ^M 這個斷行符號!這個時候我們可以使用這個 tr 來將 ^M 去除! ^M 可以使用 \r 來代替之!
[root@linux ~]# col [-x] 參數: -x :將 tab 鍵轉換成對等的空白鍵 範例: [root@linux ~]# cat -A /etc/man.config <==此時會看到很多 ^I 的符號,那就是 tab [root@linux ~]# cat /etc/man.config | col -x | cat -A | more # 嘿嘿!如此一來, [tab] 按鍵會被取代成為空白鍵,輸出就美觀多了!雖然 col 有他特殊的用途,不過,很多時候,他可以用來簡單的處理將 [tab] 按鍵取代成為空白鍵! 例如上面的例子當中,如果使用 cat -A 則 [tab] 會以 ^I 來表示。 但經過 col -x 的處理,則會將 [tab] 取代成為對等的空白鍵!
[root@linux ~]# join [-ti12] file1 file2 參數: -t :join 預設以空白字元分隔資料,並且比對『第一個欄位』的資料, 如果兩個檔案相同,則將兩筆資料聯成一行,且第一個欄位放在第一個! -i :忽略大小寫的差異; -1 :這個是數字的 1 ,代表『第一個檔案要用那個欄位來分析』的意思; -2 :代表『第二個檔案要用那個欄位來分析』的意思。 範例: 範例一:用 root 的身份,將 /etc/passwd 與 /etc/shadow 相關資料整合成一欄 [root@linux ~]# join -t ':' /etc/passwd /etc/shadow bin:x:1:1:bin:/bin:/sbin/nologin:*:12959:0:99999:7::: daemon:x:2:2:daemon:/sbin:/sbin/nologin:*:12959:0:99999:7::: adm:x:3:4:adm:/var/adm:/sbin/nologin:*:12959:0:99999:7::: # 因為 /etc/shadow 的權限問題,所以這裡必須是 root 才能動作!而 /etc/passwd # 與 /etc/shadow 都是以 : 來分隔欄位,所以必須要使用 -t ':' 規範欄位分隔字元。 # 且,因為 /etc/shadow 與 /etc/passwd 剛好都是以第一個欄位為帳號名稱,所以, # 就可以將同一行的資料給他貼在一起了! # 另外,再仔細看一下 /etc/shadow 的內容與 /etc/passwd 的內容,您會發現, # 兩者都以帳號為開始,而上面的輸出資料中您會發現特殊字體部分,那代表 # 第二個檔案的內容。在第二個檔案的內容部分,由於帳號(第一個欄位)與 # 第一的檔案是相同的,所以當然就省略掉,因此就成為上面的輸出。 範例二:我們知道 /etc/passwd 第四個欄位是 GID ,那個 GID 記錄在 /etc/group 當中的第三個欄位,請問如何將兩個檔案整合? [root@linux ~]# join -t ':' -1 4 /etc/passwd -2 3 /etc/group 0:root:x:0:root:/root:/bin/bash:root:x: 1:bin:x:1:bin:/bin:/sbin/nologin:bin:x:root,bin,daemon 2:daemon:x:2:daemon:/sbin:/sbin/nologin:daemon:x:root,bin,daemon 4:adm:x:3:adm:/var/adm:/sbin/nologin:adm:x:root,adm,daemon # 這個例子就更明顯了!原本的 /etc/passwd 的第一行內容應該是: # root:x:0:0:root:/root:/bin/bash # 至於 /etc/group 第一行內容應該是: # root:x:0: # 我將第一個檔案的第四欄與第二個檔案的第三欄取出,放置到輸出的最前方, # 然後將剩下的資料給他加在一起!就成了上面的輸出啦!這個 join 在處理兩個相關的資料檔案時,就真的是很有幫助的啦! 例如上面的案例當中,我的 /etc/passwd, /etc/shadow, /etc/group 都是有相關性的, 其中 /etc/passwd, /etc/shadow 以帳號為相關性,至於 /etc/passwd, /etc/group 則以所謂的 GID (帳號的數字定義) 來作為他的相關性。根據這個相關性, 我們可以將有關係的資料放置在一起!這在處理資料可是相當有幫助的! 但是上面的例子有點難,希望您可以靜下心好好的看一看原因喔!
[root@linux ~]# paste [-d] file1 file2 參數: -d :後面可以接分隔字元。預設是以 [tab] 來分隔的! - :如果 file 部分寫成 - ,表示來自 standard input 的資料的意思。 範例: 範例一:將 /etc/passwd 與 /etc/shadow 同一行貼在一起 [root@linux ~]# paste /etc/passwd /etc/shadow bin:x:1:1:bin:/bin:/sbin/nologin bin:*:12959:0:99999:7::: daemon:x:2:2:daemon:/sbin:/sbin/nologin daemon:*:12959:0:99999:7::: adm:x:3:4:adm:/var/adm:/sbin/nologin adm:*:12959:0:99999:7::: # 注意喔!同一行中間是以 [tab] 按鍵隔開的! 範例二:先將 /etc/group 讀出(用 cat),然後與範例一貼上一起!且僅取出前三行 [root@linux ~]# cat /etc/group|paste /etc/passwd /etc/shadow -|head -n 3 # 這個例子的重點在那個 - 的使用!那玩意兒常常代表 stdin 喔!
[root@linux ~]# expand [-t] file 參數: -t :後面可以接數字。一般來說,一個 tab 按鍵可以用 8 個空白鍵取代。 我們也可以自行定義一個 [tab] 按鍵代表多少個字元呢! 範例: 範例一:將 /etc/man.config 內行首為 MANPATH 的字樣就取出;僅取前三行; [root@linux ~]# grep '^MANPATH' /etc/man.config | head -n 3 MANPATH /usr/man MANPATH /usr/share/man MANPATH /usr/local/man # 行首的代表標誌為 ^ ,這個我們留待下節介紹!先有概念即可! 範例二:承上,如果我想要將所有的符號都列出來?(用 cat) [root@linux ~]# grep '^MANPATH' /etc/man.config | head -n 3 |cat -A MANPATH^I/usr/man$ MANPATH^I/usr/share/man$ MANPATH^I/usr/local/man$ # 發現差別了嗎?沒錯~ [tab] 按鍵可以被 cat -A 顯示成為 ^I 範例三:承上,我將 [tab] 按鍵設定成 6 個字元的話? [root@linux ~]# grep '^MANPATH' /etc/man.config | head -n 3 | \ > expand -t 6 - | cat -A MANPATH /usr/man$ MANPATH /usr/share/man$ MANPATH /usr/local/man$ 123456123456123456..... # 仔細看一下上面的數字說明,因為我是以 6 個字元來代表一個 [tab] 的長度,所以, # MAN... 到 /usr 之間會隔 12 (兩個 [tab]) 個字元喔!如果 tab 改成 9 的話, # 情況就又不同了!這裡也不好理解~您可以多設定幾個數字來查閱就曉得!expand 也是挺好玩的~他會自動將 [tab] 轉成空白鍵~所以,以上面的例子來說, 使用 cat -A 就會查不到 ^I 的字符囉~此外,因為 [tab] 最大的功能就是格式排列整齊! 我們轉成空白鍵後,這個空白鍵也會依據我們自己的定義來增加大小~ 所以,並不是一個 ^I 就會換成 8 個空白喔!這個地方要特別注意的哩! 此外,您也可以參考一下 unexpand 這個將空白轉成 [tab] 的指令功能啊! ^_^
[root@linux ~]# split [-bl] file PREFIX 參數: -b :後面可接欲分割成的檔案大小,可加單位,例如 b, k, m 等; -l :以行數來進行分割。 範例: 範例一:我的 /etc/termcap 有七百多K,若想要分成 300K 一個檔案時? [root@linux ~]# cd /tmp; split -b 300k /etc/termcap termcap [root@linux tmp]# ls -l termcap* -rw-rw-r-- 1 root root 307200 8月 17 00:25 termcapaa -rw-rw-r-- 1 root root 307200 8月 17 00:25 termcapab -rw-rw-r-- 1 root root 184848 8月 17 00:25 termcapac # 那個檔名可以隨意取的啦!我們只要寫上前導文字,小檔案就會以 # xxxaa, xxxab, xxxac 等方式來建立小檔案的! 範例二:如何將上面的三個小檔案合成一個檔案,檔名為 termcapback [root@linux tmp]# cat termcap* >> termcapback # 很簡單吧?就用資料流重導向就好啦!簡單! 範例三:使用 ls -al / 輸出的資訊中,每十行記錄成一個檔案 [root@linux tmp]# ls -al / | split -l 10 - lsroot # 重點在那個 - 啦!一般來說,如果需要 stdout/stdin 時,但偏偏又沒有檔案, # 有的只是 - 時,那麼那個 - 就會被當成 stdin 或 stdout ~在 Windows 的情況下,你要將檔案分割需要如何作?!傷腦筋吧!呵呵!在 Linux 底下就簡單的多了!你要將檔案分割的話,那麼就使用 -b size 來將一個分割的檔案限制其大小,如果是行數的話,那麼就使用 -l line 來分割!好用的很!如此一來,你就可以輕易的將你的檔案分割成 floppy 的大小,方便你 copy 囉!
[root@linux ~]# xargs [-0epn] command 參數: -0 :如果輸入的 stdin 含有特殊字元,例如 `, \, 空白鍵等等字元時,這個 -0 參數 可以將他還原成一般字元。這個參數可以用於特殊狀態喔! -e :這個是 EOF (end of file) 的意思。後面可以接一個字串,當 xargs 分析到 這個字串時,就會停止繼續工作! -p :在執行每個指令的 argument 時,都會詢問使用者的意思; -n :後面接次數,每次 command 指令執行時,要使用幾個參數的意思。看範例三。 當 xargs 後面沒有接任何的指令時,預設是以 echo 來進行輸出喔! 範例: 範例一:將 /etc/passwd 內的第一欄取出,僅取三行,使用 finger 這個指令將每個 帳號內容秀出來 [root@linux ~]# cut -d':' -f1 < /etc/passwd |head -n 3| xargs finger Login: root Name: root Directory: /root Shell: /bin/bash Never logged in. No mail. No Plan. ......底下省略..... # 由 finger account 可以取得該帳號的相關說明內容,例如上面的輸出就是 finger root # 後的結果。在這個例子當中,我們利用 cut 取出帳號名稱,用 head 取出三個帳號, # 最後則是由 xargs 將三個帳號的名稱變成 finger 後面需要的參數! 範例二:同上,但是每次執行 finger 時,都要詢問使用者是否動作? [root@linux ~]# cut -d':' -f1 < /etc/passwd |head -n 3| xargs -p finger finger root bin daemon ?...y ......底下省略..... # 呵呵!這個 -p 的參數有趣了吧?!他可以讓使用者的使用過程中,被詢問到每個 # 指令是否執行! 範例三:將所有的 /etc/passwd 內的帳號都以 finger 查閱,但一次僅查閱五個帳號 [root@linux ~]# cut -d':' -f1 < /etc/passwd | xargs -p -n 5 finger finger root bin daemon adm lp ?...y ......底下省略..... # 在這裡鳥哥使用了 -p 這個參數來讓您對於 -n 更有概念。一般來說,某些指令後面 # 可以接的 arguments 是有限制的,不能無限制的累加,此時,我們可以利用 -n # 來幫助我們將參數分成數個部分,每個部分分別再以指令來執行!這樣就 OK 啦!^_^ [root@linux ~]# 範例四:同上,但是當分析到 lp 就結束這串指令? [root@linux ~]# cut -d':' -f1 < /etc/passwd | xargs -p -e'lp' finger finger root bin daemon adm ?... # 仔細與上面的案例做比較。也同時注意,那個 -e'lp' 是連在一起的,中間沒有空白鍵。 # 上個例子當中,第五個參數是 lp 啊,那麼我們下達 -e'lp' 後,則分析到 lp # 這個字串時,後面的其他 stdin 的內容就會被 xargs 捨棄掉了!其實,在 man xargs 裡面就有三四個小範例,您可以自行參考一下內容。 此外, xargs 真的是很好用的一個玩意兒!您真的需要好好的參詳參詳!
[root@linux ~]# tar -cvf - /home | tar -xvf -
上面這個例子是說:『我將 /home 裡面的檔案給他打包,但打包的資料不是紀錄到檔案,而是傳送到 stdout;
經過管線後,將 tar -cvf - /home 傳送給後面的 tar -xvf - 』。後面的這個 - 則是取用前一個指令的 stdout,
因此,我們就不需要使用 file 了!這是很常見的例子喔!注意注意!