cd /etc
ls -l
看看有沒有一個 passwd 檔?
- 用 less 檢視一下 passwd 的內容,
找到關於你自己的資訊。
grep $USER passwd
咦,
只印出關於自己的資訊! 為什麼?
ls -l $USER
錯誤訊息說什麼?
ls -l $HOME
咦,
印出自己家裡的檔案?
set -x
再重複先前三個指令。
- 我們輸入的命令列, shell
會先對它做各種處理與代換 (substitution/ expansion)
用
set -x
這個 內建指令 (builtin
command) 可以令 shell 在執行命令之前,
印出它最終代換的結果, 也就是 外部指令
(external command) 真正看到的命令列。
如果要取消, 可以這樣: set +x
-
ll -d $HOME/.[a-z]*
這句話裡面發生了三個代換: alias、 environment
variable、 file name glob。
使用者下的命令: ll $HOME/.[a-z]*
||
|| (經過 shell 處理)
\ /
\/
最後把 ls ls -l --color=auto /home/ckhung/.bash_history
叫起來之前變成: /home/ckhung/.bashrc ...
- File name glob 的範例: 先
cd /usr/bin
,
然後:
echo z* 所有 z 開? ?的檔案
echo l*s 所有以 l 開? ?, 以 s 結尾的檔案
echo *zip* 所有名稱中間有 zip 的檔案
echo ??zip 所有名稱長度為 5, 且以 zip 結尾的檔案
echo [A-Z]* 所有以大寫字母開? ?的檔案
echo *[0-9]* 所有名稱當中至少有一個數字的檔案
請注意: 這些代換都是 shell 在做的。 echo
這個命令在被呼叫起來之前,
這些特殊符號早就已經被 shell 展開成檔名了。
藉由 file name glob 的功能, 可以在沒有 ls
可以用的情況下以 echo 達到簡單的 ls 功能。
又, 這裡用到的符號, 跟 regular
expressions 的意義不一樣。 (dos/windows 使用者:
dos 的 command.com 也是一個 shell, 但它並不支援 file
name glob, 所以一個應用程式想要認得命令列上的
* 與 ? 要靠它自己處理。)
- 以
echo $HOME
印出 環境變數
(environment variable) HOME 的值。
這是你的家目錄。 其他與目錄有關的環境變數:
PATH
命令的搜尋路徑; MANPATH
手冊的搜尋路徑。 LANG
則是系統顯示訊息時要採用哪種 (自然) 語言 --
中文或英文或日文之類的。
- 許多程式共同使用的環境變數:
$EDITOR
或 $VISUAL
你要用那個文字檔編輯器;
$PAGER
你要用那個 "分頁器"
(文字檔閱覽器) 來看輸出.
- 例: 在 tcsh 下
setenv PAGER head
或在 bash
下 export PAGER=head
之後再 man 1
echo
Q: 如果把 PAGER 設定成 cat, 從此以後使用
man 會怎麼樣? 有沒有辦法在不把 PAGER
改回來的情況下仍舊可以讀手冊?
- 改變 shell 的提示符號: (bash 適用)
export
PS1='\t \[\033[4;35m\]\h:\w\$\[\033[0m\] '
或更簡短的 export PS1='\t \e[4;35m\h:\w\$\e[m '
詳見 bash(1) 裡面的 PROMPTING 以及
這篇。
可以把這句話放在 ~/.bashrc 裡面,
這樣每次開一個新的 bash, 都會執行這句。
- 看看有那些環境變數:
env
- Q: 你的環境下有幾個環境變數? Q:
有一個環境變數記載著這部機器的名稱 (例如
penguin, 或 mail, 或 digital), 是那一個?
- 用
alias ll
或 type ll
可以看到 ll 其實是 "ls -l" 的 別名 alias。
(其實概念比較像是 「簡寫」)
- 命令別名範例: 先看看危險的命令 mv 的手冊,
那一個選項可以讓系統在面臨有覆蓋舊檔危險時警告你?
現在用
alias
看看目前有那些命令別名.
然後加入兩個別名 (bash 版):
alias mv='echo use mov instead'
alias mov='/bin/mv -i'
(如果是 tcsh, 則把 = 改成空格.) 再用
alias
檢查成果. 最後試著用 mv 與 mov
更改檔名. 又, 此時下 which mv
與
which mov
得到什麼?
- alias 的應用實例:
alias pgrep='/bin/grep -P
--color=auto'
從此以後, pgrep 指令裡面可以用
PCRE 而不必另學一套 grep 自己的 regular
expression。
- 如果你的 /etc/mailcap 設定正確的話, 文字瀏覽器
lynx 也可以用來選擇性地看圖形. 但必須把 lynx 的
-image_links 打開, 才看得到圖形的超連結;
而這只能在命令列上打開, 無法在 .lynxrc
當中設定. 所以只好在 .bashrc 當中加入
alias
lynx='/usr/bin/lynx -image_links'
- Q:
dir
命令作什麼用的?
如果不用任何代換而想造成相同的效果,
要如何下命令?
- 消除命令別名範例:
unalias mov
- 題外話:
-
看看一個二進位檔案裡面有沒有一些可以印出來看的字串:
strings /usr/bin/man
- 看看 ckhung 這個使用者發呆發了多久:
finger ckhung
修改自己的資料, 讓別人
finger 你時看到你的姓名電話: chfn
-
命令結果代換
command substitution (舊稱 Back quote)
的範例
- 下
grep $(whoami) /etc/passwd
與先前的
grep $USER /etc/passwd
有相同效果.
- 主機名稱到底是在哪裡設定的?
grep
$HOSTNAME $(find /etc -type f)
- 看看 man 這個命令的可執行檔中,
有那些可以印出來看的字串:
strings $(which
man)
- 找出 man 命令的可執行檔中,
看起來像是環境變數的字串:
strings $(which
man) | grep '^[A-Z]\+$'
- 用 finger 查看目前在線上的每個使用者:
finger $(who -q | grep -v '^#' )
如果覺得太複雜, 可以分成兩步來做: who -q
| grep -v '^#' > a; finger $(cat a)
- 也請參考 「組合的力量」
當中更多的例子。
- xargs
命令可以把本來從 stdin 輸入的資料,
轉成後面那個命令的命令列參數. 這可以在不支援
back quote substitution 的 shell 下做到 back quote
substitution 的功能. 上述兩例可以改成:
which man
| xargs strings | grep '^[A-Z]\+$'
以及 who -q |
grep -v '^#' | xargs finger
- 注:
strings $(which man)
古代的寫法是
strings `which man`
不過這種寫法無法層層相疊,
所以建議還是用前一種寫法。
- 我個人認為 pipe 與 back quote substitution
是所有命令列觀念當中, 最重要的兩項.
學會靈活使用這兩項來組合其他指令,
就可以用有限的指令產生出許多神奇的效果.
如果再配合上 regular expression, 就可以算是半個 unix
高手了.
- 歷史代換: 先用
history
看一下你先前曾經下過那些命令.
!! 前一個命令再執行一次
!-5 倒數第五個命令再執行一次
!58 把第 58 個命令再執行一次
!wh 把最近一次下過, 以 wh 開頭的命令再執行一次
- 歷史代換也可以嵌在其他命令或代換裡面:
finger $(!wh)
例: 從 who -q
開始,
逐次使用 !!
於下一命令中,
終至將上面命令結果代換的例子寫出.
- 避免代換的字元: ' ... '
避免掉幾乎所有的代換; " .... " 避免掉多數代換,
但是裡面變數代換照常進行; \
避免掉它後面那個字元的特殊意義。 請看看這幾個指令的差別:
echo $HOME
echo "$HOME"
echo '$HOME'
echo \$HOME
- 作業: 運用 file name glob
與避免代換的字元等等功能,
把自己家裡亂七八糟的檔案清除乾淨.
- 作業: 自己查手冊,
看看下面這兩個命令有什麼用處:
find ~ -name '*.[ch]' | zip -@ ~/backup.zip
zip ~/backup.zip $(find ~ -name '*.[ch]' )
如何把上述命令設定成 alias, 讓你將來 login
到你的帳號以後, 隨時都可以下 "savework" 命令,
而達到備份重要資料的效果? (提示:
可能需要用到 " ... " 避免 shell 在你下 alias
命令時就急著想要代換.)
- 要取消「印出 shell expansion
處理完的命令列字串」這個效果, 可以在 bash
視窗內下
set +x
在 tcsh 視窗內下
unset echo
- bash 提供一些 快捷鍵
- 如果你發現 shell 變得很難用 -- 例如沒有快捷鍵、
檔案名稱快打、 ... 等等功能, 有可能是因為你用的是 /bin/sh
而不是 /bin/bash 。 用
ps
指令檢查看看目前正在使用哪個 shell, 也用
grep $USER /etc/passwd
檢查看看系統指定什麼 shell 給你用。
- 要改變你所使用的 shell 可以用
chsh
但是並不是系統內有安裝的 shells 都可以用,
只有記載在 /etc/shells 內的才可以用.
如果你喜愛的 shell (例如是 pdmenu) 並未在允許的
shells 之中, 可以在 .login 或 .profile 當中寫 exec
/usr/bin/pdmenu
- 簡單的迴圈:
for i in guava pineapple cherry orange
; do echo $i ; done
- 例如要將一片 12 軌的音樂 cd
上所有的歌曲全部變成 mp3, 可以這樣下:
for i
in 1 2 3 4 5 6 7 8 9 10 11 12 ; do cdda2wav -D /dev/cdrom -x -q
-t $i+$i - | lame -h -S - $i.mp3 ; done
至於它到底有幾軌, 如何得知呢? cdda2wav -D
/dev/cdrom -J -v all
- 一口氣把家目錄底下 (含子目錄, 孫目錄, ...)
所有 .doc 檔轉換成 .html 檔:
for f in $(find ~
-iname '*.doc' | sed 's/\.doc//' ) ; do echo "converting $f.doc
..."; wvHtml $f.doc $(echo $f | sed 's#.*/##g').htm ;
done
- 如何一次產生很多帳號?
例如要從這樣一個學生名單檔案 grade.txt 一口氣建立很多 unix 帳號,
可以這樣下:
for user in $(perl -ne 'print "$1\n" if
/^(\w+):/' grade.txt) do ; useradd -g users $user ;
done