第一章 背景知識
軟體工具的原則
- 一次做好一件事
這個原則的結果自然就是會不斷產生出更小、更專用於特定功能的程式。
- 處理文字行,不要處理二進位制
文字行可以用任何文字編輯器來編輯,也可以在網路與各種機器架構之間傳輸。
二進位制是平臺相關的。
- 使用正規表示式
使用正規表示式能簡化命令指令碼的工作。
POSIX標準提供兩種正規表示式:BRE(與grep一致的正規表示式)和ERE(與egrep一致的)。
- 預設使用標準輸入/輸出
在未明確指定檔名時,程式預設從標準輸入讀取資料,將資料寫到標準輸出。
這樣可以輕鬆地讓它們成為資料過濾器,組成複雜的管道或指令碼。
- 避免喋喋不休
不要將“開始處理”,“即將完成”,“處理完成”這類資訊放程式序的標準輸出。
將這樣的資訊送往管道,別指望執行結果會像預期的一樣。在工具程式的世界裡,
沒有訊息就是好訊息。
- 讓工具去做困難的部分
雖然Unix程式並非完全符合你的需求,但是現有的工具或許可以為你完成90%的工作。
接下來可以編寫一個功能特定的小型程式來完成剩下的工作。
第二章 入門
- 指令碼中的引用命令使用絕對路徑
- 每一個空格都能影響結果
- #!/bin/sh可以避免某種程式的欺騙攻擊
- ";"分號,可以分隔同一行裡的多條命令
- "&"代表後臺執行,並且此後的命令不用等待它完成。
- 父 Shell將等待子Shell 的所有相關程式完成後,才繼續執行
- 變數賦值的時候"="前後沒有空格,引用的時候在變數前面加 $ 當賦值
m衧空格的時候請加上引號 - echo -n 會忽略結尾的換行符,但是echo版本上存在差異不建議過多使用。
- printf "Hello $s !/n" World,幾乎複製了c中printf的所有功能
- ctrl+D,也就是符號 "^D", 代表檔案結尾
- < 改變標準輸入,只限於兩個程式之間
- > 改變標準輸出,只限於兩個程式之間
- >> 追加到檔案
- pro1 | pro2 將 pro1 的標準輸出重定位到pro2 的標準輸入。管道符可以多個程式相連
- tr足極其簡化的sed,他所能完成的任務sed都能,反之則不行。
- /dev/null即是位桶檔案(bit bucket),類似垃圾桶,讀取返回檔案結束符
- /dev/tty 會重定向到終端,讀取人工輸入時有用
printf "Enter password:"
stty -echo #關閉冋顯
read pass
printf "Enter password again:"
read pass
stty echo #打幵回顯
- $PATH中加入 "." 可以包含當前目錄,不過不安全
- $1 代表第一個引數,大於9就要用括號.,比如$(10)
cat >finduser
#!/bin/sh
who | grep $1
^D
finduser aaron
- Shell將忽略#開頭的一行,註釋 。
- Shell腳木裡set +x 會開啟執行跟蹤,set -x 關閉跟蹤。
- Shell裡特殊字元稱作元字元(metacharacter)
第三章 查詢與替換
- [] 內的 "^" 表示取反
- [0-9a-zA-F】,範圍表示不建議在新程式裡運用。
- "a/{5/}"表示重複5個a,"q/{10,42/}"表示10到42個q
- 正規表示式中"^"表示開頭,"$" 表示結尾 "^$" 表示空行。另外 "grep -v" 顯示不匹配的結果
- "ab?c" 匹配ac或者abc
- "ab+c" 等同於 "abb*c",匹配 abc,abbc...,但不匹配 ac
- "sleep|wakeup|idle" 匹配 sleep,wakeup,idle。注意 | 優先順序最低。
- "[Tt]he(computer|PC)is" 匹配 The 或者 the 和 is 之間出現 computer 或
PC的句子。 - "/<" 和 "/>" 用來匹配單詞,可以分開使用。
- grep 是 ed (商用unix上的vi)中 "g/re/p" 的縮寫,意思是全域性匹配並列印。 ed也是sed的基礎。
tr 是極其簡化的 sed。"tr -c -d -s [string_to_translate_from] [string_to_translate_to] < input_file"
- sed與空字串,匹配最長子串,awk也是。意思就是匹配滿足條件的從左到右最長的一段
- grep和sed的絕大部分是用來處理行(line)。awd,perl及Python處理字串(string)
cut 用來剪下資料,join用來連線資料,sort用來排列資料。(以Tab分隔
的資料)
awk -F: '{print "User", $1, "is really", $5}' /etc/passwd
第四章 文字處理
- sort (排序)屬於UNIX前十名主要的命令
- uniq刪除排序後的重複行
- wc計算字數,行數,位元組數
- head和tail顯示檔案頭和尾
第五章 管道的神奇魔力
- $$表示程式號
- trap用來捕捉訊號,並執行命令。格式如: trap [-lp] [arg] [sigspec ...]
第六章 變數判斷秉復動作
- export用於修改和列印環境變數,readonly使其不能修改。
- env 用來改變環境變數
- unset用來刪除當前Shell的變數和函式
- 未定義的變數會展開為NULL,隨意操作將會引發異常。
- ${varname:-val}如果varname存在並不是null,將返回varname,否則返回val
${varname:=val}如果 varname 存在並不是 null,將返回varname,否則賦值為val並返回val。
${vamame:?val}如果 varname 存在並不是 null,將返回varname,否則顯示varname:val。
${varname:+val}如果varname存在並不是null,將返回val,否則返回null。
如果去掉冒號,則表示存在,可以是null。 - "$#" 引數的總數,$*,$@。shift截掉$1後,$2變成$1,類推。。。
- 通用的變數(前面加上 $ 將引用變數)。# 引數個數,
- 每一條命令,不管是內建的Shell命令,還是外部的。當他退出時,都會返回一個小的整數給呼叫它的函式。0表示成功。
- exit從Shell指令碼返回一個退出狀態給呼叫者
- &&邏輯與,if...then...。|| 邏輯或,ifnot...then...。
if ....; then
....
elif ....; then
....
else
....
fi
引數說明:
[ -f "somefile" ] 判斷是否是一個檔案
[ -x "/bin/ls" ] 判斷/bin/ls是否存在並有可執行許可權
[ -n "$var" ] 判斷$var變數是否有值
[ "$a" = "$b" ] 判斷$a和$b是否相等
-r file 使用者可讀為真
-w file 使用者可寫為真
-x file 使用者可執行為真
-f file 檔案為正規檔案為真
-d file 檔案為目錄為真
-c file 檔案為字元特殊檔案為真
-b file 檔案為塊特殊檔案為真
-s file 檔案大小非0時為真
-t file 當檔案描述符(預設為1)指定的裝置為終端時為真
- 條件判斷中方括號裡的引數必須有引弓。
- 條件判斷只能做整數測試,不能針對浮點
- 條件判斷 "x$a" = "x$b",x 表示不擴充套件
- getopts簡化引數處理,支援類似 -xvf 這樣寫在一起的引數。
- 函式裡return的作用類似於exit。
第七章輸入輸出檔案與命令執行
read,將資訊讀入一個或者多個Shell變數。
while read...
do
...
done < fileset -C 當>重定向遇到目標檔案存在時,會失敗
program << delimiter 之後跟輸入的正文+delimiter。
<>開啟一個義件作為輸入和輸出- 2>&1 必須連在一起
- exec以新的程式代替shell,或者改變shell 的I/O。將不會回到指令碼里,
除非呼叫失敗。 - printf...
- 當前使用者的根目錄,~name,name使用者的根目錄。可移植性不好
- ?通配一個字元,*通配多個字元,[abc]通配a,b,c [!abc]除了 a,b, c
- $() 包括幾個命令的時候,代表一個整體,術語是 "命令替換"。
- expr用於運算
- 反斜槓""轉義(單引號--保留字面值; 雙引號--會做變數轉換之類的)
- eval告知Shell取出eval的引數,並執行他(們)。
- shell內部的解釋過程比較晦澀,定義變數儘量簡單。
- "subshell --()" 括號內的命令集將單獨開一個程式去執行。
- command 可以訪問內建命令
set
第八章 產生指令碼
- basename 從完整路徑中取出檔名。再加一個引數就是要從檔名結尾去掉的字串。
第九章 awk太強大
命令格式
awk [-F field-separator] 'commands' input-file(s)awk內建變數
ARGC 命令列引數個數
ARGV 命令列引數排列
ENVIRON 支援佇列中系統環境變數的使用
FILENAME awk瀏覽的檔名
FNR 瀏覽檔案的記錄數
FS 設定輸入域分隔符,等價於命令列 -F選項
NF 瀏覽記錄的域的個數
NR 已讀的記錄數
OFS 輸出域分隔符
ORS 輸出記錄分隔符
RS 控制記錄分隔符例項
假設last -n 5的輸出如下
[root@www ~]# last -n 5
root pts/1 192.168.1.100 Tue Feb 10 11:21 still logged in
root pts/1 192.168.1.100 Tue Feb 10 00:46 - 02:28 (01:41)
root pts/1 192.168.1.100 Mon Feb 9 11:41 - 18:30 (06:48)
dmtsai pts/1 192.168.1.100 Mon Feb 9 11:41 - 11:41 (00:00)
root tty1 Fri Sep 5 14:09 - 14:10 (00:01)如果只是顯示最近登入的5個帳號
則
#last -n 5 | awk '{print $1}'
root
root
root
dmtsai
root
第十章 檔案處理
- ls
- od 可以檢視無法顯示出來的字元。
- touch
- mktmp /tmp/myprog.xxxxxxxxxxxxx 建立一個隨機的檔名。
- /dev/random和/dev/urandom都產生隨機數,urandom比較快但是不夠隨機(基木夠用)。這兩個可以替代mktmp的功能。
- type
- find
- find sth. -type f 丨 xargs grep sth1 - /dev/null,xargs 只是在 stdout 上去的引數
列表,一行一個。 - 使用diff的慣例是把舊檔案放在第一個引數。