[Shell] [筆記]UNIX/Linux/OSX中的Shell程式設計
UNIX/Linux/OSX中的Shell程式設計(第4版)
Stephen G. Kochan Patrick Wood著
文章目錄
- UNIX/Linux/OSX中的Shell程式設計(第4版)
- 基礎
- 1. 使用檔案
- 2. 使用目錄
- 3. 檔名替換
- 4. 檔名中的空格
- 5. 標準輸入/輸出和I/O重定向
- 6. 標準錯誤
- 7. 管道
- 8. Shell
- 9. 正則表示式
- 10. 常用字元的八進位制形式
- 11. 退出狀態
- 12. 波浪符替換
- Tips
- 命令
- 1. date
- 2. who
- 3. echo
- 4. ls
- 5. cat
- 6. wc
- 7. cp
- 8. mv
- 9. rm
- 10. pwd
- 11. cd
- 12. mkdir
- 13. rmdir
- 14. ln
- 15. ps
- 16. cut
- 17. paste
- 18. tr
- 19. grep
- 20. sort
- 21. uniq
- 22. expr
- 23. shift
- 24. test
- 25. exit
- 26. 空命令`:`
- 27. sleep
- 28. nohup
- 29. break
- 30. continue
- 31. getopts
- 32. read
- 33. basename
- 34. printf
- 35. export
- 36. .(dot)命令
- 37. exec
- 38. set
- 39. readonly
- 40. unset
- 41. eval
- 42. wait
- 43. trap
- 44. return
- 45. type
- 46. history
- 47. fc
- 48. r (Korn Shell才有)
- 49. typeset (Korn Shell才有)
- 50. alias
- 51. unalias
- 52. jobs
- 53. kill
- 54. fg
- 55. bg
- 語句結構
- 引用
- 變數、引數與環境
- 編輯器
基礎
1. 使用檔案
-
UNIX系統只識別三種基本型別檔案:普通檔案(系統中包含資料、文字、程式指令或其它內容的檔案)、目錄檔案和特殊檔案(對UNIX有特殊意義,通常和某種形式的I/O相關聯)
-
檔名字元數不能超過255個
2. 使用目錄
- 登入系統後,自動處於個人主目錄中
- 以"/“起始的路徑名為絕對路徑名,不以”/"開頭的路徑為相對路徑,相對於當前工作目錄
- "…“指向當前目錄的上一級目錄,”."引用當前目錄
3. 檔名替換
*
echo *
#部分替換,限制匹配
echo chap*
? 或 []
匹配單個字元
echo a?
# 列出以小寫字母開頭且不易數字結尾的所有檔案
ls [a-z]*[!0-9]
[!chars]
不在chars中的任意單個字元
4. 檔名中的空格
兩種解決方法:
- 放在引號中
cat "my test document"
- 使用反斜槓轉義
cat my\ test\ document
5. 標準輸入/輸出和I/O重定向
Ctrl+d
終結標準輸入- 輸出重定向
# 內容覆蓋
who > users
# 追加形式
echo line 2 >> users
- 輸入重定向
wc -l < users
I/O重定向
寫法 | 含義 |
---|---|
< file | 標準輸入重定向到file |
> file | 標準輸出重定向到file |
>| file | 標準輸出重定向到file,file內容清空 |
>> file | 追加 |
<< word | 標準輸入重定向到隨後的行中,知道某行只包含了word |
<& digit | 標準輸入重定向到與檔案描述符digit相關聯的檔案 |
>& digit | 標準輸出重定向到與檔案描述符digit相關聯的檔案 |
<&- | 關閉標準輸入 |
>&- | 關閉標準輸出 |
<> file | 開啟file進行讀取和寫入 |
- file上不會執行檔名替換
- 行內輸入重定向
- 為了不讓Shell解釋輸入行中的內容,可以在文件結尾單詞前使用反斜線:
$ cat <<\FOOBAR > \\\ > `date` > $HOME > FOOBAR \\\ `date` $HOME
- 如果>>後面的第一個字是連線符-,那麼輸入中的其拿到製表符都會被Shell刪除
- 為了不讓Shell解釋輸入行中的內容,可以在文件結尾單詞前使用反斜線:
6. 標準錯誤
-
默認同終端或終端程式相關聯
-
即使標準輸出被重定向到檔案中,錯誤小心仍然顯示到終端
-
command 2> file
將標準錯誤重定向到檔案中 -
另一種寫法用於確保所有的錯誤資訊都出現在終端,哪怕監本已經將其輸出重定向了檔案或管道:
echo "Error message" 1>&2
(將應該輸出到檔案描述符#1的錯誤資訊重定向到檔案描述符#2)
7. 管道
過濾器:從標準輸入讀取資料,將結果寫入標準輸出
# wc為過濾器,cat/sort都可以作為過濾器
# who/date/cd/pwd/echo/rm/mv/cp都不算
who | wc -l
8. Shell
-
只要系統允許使用者登入,UNIX系統(
init
程式)就會在每個終端埠自動啟動一個getty程式,getty是一個裝置驅動程式,能夠讓login
程式在其所分配的終端上顯示login:
等待使用者輸入 -
login
比對/etc/passwd
中的條目驗證登入名密碼,/etc/passwd
中有驗證成功後要啟動的程式(每行最後一個冒號後面),沒有就預設使用標準Shell,即/bin/sh
。 -
登入Shell會在系統中查詢並讀取兩個特殊檔案:
/etc/profile
會檢查新郵件、預設的檔案建立掩碼、建立預設PATH及其它管理員希望登入完成的工作;.profile
位於使用者主目錄下,其對環境做出的修改會一直持續到登出Shell -
Shell的職責:解釋型程式語言、程式執行、變數及檔名替換、I/O重定向、管道、環境控制
-
Shell首先進行變數和檔名替換,查詢檔名替換字元*、?或[…]
-
Shell在磁碟搜尋命令之前,會先判斷是否為內建命令(cd/pwd/echo)
-
I/O重定向:
wc
程式在wc -l < users
中只接收了-l
一個引數,他會轉而去統計標準輸入的內容,Shell會將其的標準輸入重定向為檔案users -
管道:將上一個命令的標準輸出連線到下一個命令的標準輸入,然後執行兩者
-
環境控制:能夠定製個人環境
-
解釋型:Shell有自己的內建語言,這種語言是解釋型的,Shell會分析所遇到的每一條語句,然後執行所發現的有效的命令
-
-
Shell先進行管道和I/O重定向,然後是變數替換、命令替換,再是檔名替換,接著將命令列解析成引數,Shell會從命令列中刪除空格、製表符和換行符(空白字元),然後切分成引數交給所請求的命令
-
Shell的命令搜尋次序
- 首先檢查命令是否為保留字(如for或do)
- 如果不是保留字,也沒有引用,接著檢查別名列表,如果在其中找到匹配的別名,就執行替換操作,**如果別名定義是以空格結尾,Shell還會嘗試對下一個單詞執行別名替換。**針對替換後的最終結果,再次檢查保留字列表,如果不是保留字,繼續進行第3步
- 針對命令名檢查函式列表,如果找到,執行其中的同名函式
- 檢查是否為內建命令(如cd和pwd)
- 最後,搜尋PATH來定位命令
- 如果還沒找到,輸出錯誤資訊command not found
9. 正則表示式
記法 | 含義 | 例子 |
---|---|---|
. | 匹配任意字元(Shell 則認為? 能匹配任意單個字元) |
a… |
^ | 匹配行首 | ^wood |
$ | 匹配行尾 | x$ |
* | 重複之前的正則表示式零次或多次 | xx* (一個或多個連續x) |
+ | 重複之前的正則表示式一次或多次 | xx+ (兩個或多個連續x) |
[chars] | 匹配chars中的任意字元 | [a-z] (小寫字母) |
[^chars] | 匹配不在chars中的任意字元 | [^0-9] (非數字字元) |
\{min, max\} | 重複之前的正則表示式至少min次,至多max次 | [0-9]\{3, 9\} (連續3-9個數字) |
\(…\) | 將括號中儲存下來的字元儲存到接下來的暫存器中(1-9) | ^\(.\)\1 (行首前兩個相同的字元) |
10. 常用字元的八進位制形式
字元 | 八進位制值 |
---|---|
響鈴Bell | 7 |
退格Backspace | 10 |
製表符Tab | 11 |
回車換行Newline | 12 |
換行Linefeed | 12 |
換頁Formfeed | 14 |
回車Carriage Return | 15 |
取消Escape | 33 |
11. 退出狀態
- 退出碼為0表示程式執行成功
- 對於管道而言,退出狀態對應的是管道中的最後一個命令
- 對於檔案複製命令cp,可能的錯誤情況是1(檔案沒找到)、2(檔案不可讀)、3(目標目錄沒找到)、4(目標目錄不可寫)、5(一般性錯誤)
12. 波浪符替換
- Shell會檢查命令列中的每一個單詞及變數是否以未引用的開頭,如果是,將單詞或變數中其餘直到/的部分視為登入名,並在系統檔案/etc/passwd中查詢該使用者。如果存在,使用其主目錄替換以及登入名。如果不存在,不做任何修改
- 單獨的或/之後的會被HOME變數替換
Tips
-
一行中輸入多個命令,使用
;
分隔 -
向後臺傳送命令:
# 返回[job number] PID
$ sort bigdata > out &
[1] 1258
-
chmod +x <file>
使檔案具有可執行許可權 -
沒有引數的
echo
會產生一個空行 -
不想看到命令結果,可以將輸出重定向到系統的垃圾桶:
/dev/null
,任何寫入這個檔案的東西都會消失!要強制寫入或從終端讀取,可以利用
/dev/tty
,該檔案總是指向終端程式 -
除錯:
sh -x
跟蹤執行過程,這啟動了一個-x選項的新shell執行指定程式,命令在執行的同時列印到終端,前面加了一個+。 -
Shell的兩個特殊操作符:
&&
和||
,根據之前命令成功與否來執行後續的命令 -
如果檔案中的第一行的前兩個字元是#!,那麼該行餘下的部分指定了該檔案的直譯器:
#!/bin/bash
命令
1. date
顯示日期和時間
$ date
Thu Dec 27 19:31:25 CST 2018
2. who
獲取當前已登入到系統中所有使用者資訊
使用者ID、使用者所在的tty編號(UNIX系統為使用者所在終端或網路裝置分配的唯一標識數字)、登入時間
$ who
root pts/0 2018-12-27 19:41 (10.131.253.92)
[[email protected] ~]# who am i
root pts/0 2018-12-27 19:41 (10.131.253.92)
3. echo
- 回顯字元,壓縮單詞間多餘的空白字元;
$ echo one two three
one two three
- 會自動在最後一個引數後面加上一個用於終止的換行符,可以在最後加上轉義字元
\c
不輸出換行符(\c
是由echo解釋的,而非Shell,必須將其引用起來交給echo),有的系統不會顯示這些echo轉義字元
echo命令的轉義字元
字元 | 輸出 |
---|---|
\b | 退格 |
\c | 忽略輸出中最後的換行符 |
\f | 換頁 |
\n | 回車換行 |
\r | 回車 |
\t | 製表符 |
\\ | 反斜線 |
\0nnn | ASCII值為nnn的字元,nnn是1-3位的八進位制數 |
4. ls
列舉檔案;
-C
強制以多列形式輸出
-l
輸出檔案詳細資訊:
- total:檔案佔用的儲存塊(1024位元組)數
- 檔案型別:d為目錄,-為檔案,特殊檔案是b/c/l/p
- 訪問許可權:檔案所有者、與檔案所有者同組的其他使用者、系統其他使用者
- 連結數
- 檔案所有者
- 檔案所屬組
- 檔案大小
- 檔案最後的修改時間
$ ls
anaconda-ks.cfg
apache-maven-3.5.2-bin.tar.gz
docker-ce-17.03.2.ce-1.el7.centos.x86_64.rpm
docker-ce-selinux-17.03.2.ce-1.el7.centos.noarch.rpm
get-pip.py
go1.9.2.linux-amd64.tar.gz
jdk-8u131-linux-x64.tar.gz
nohup.out
openscap_data
privoxy-3.0.26-stable
privoxy-3.0.26-stable-src.tar.gz
$ls -l
total 314124
-rw-------. 1 root root 1089 Aug 10 2016 anaconda-ks.cfg
-rw-r--r--. 1 root root 8738691 Apr 12 2018 apache-maven-3.5.2-bin.tar.gz
-rw-r--r--. 1 root root 19529520 Apr 12 2018 docker-ce-17.03.2.ce-1.el7.cento s.x86_64.rpm
-rw-r--r--. 1 root root 29108 Apr 12 2018 docker-ce-selinux-17.03.2.ce-1.e l7.centos.noarch.rpm
-rw-r--r--. 1 root root 1780465 Apr 13 2018 get-pip.py
-rw-r--r--. 1 root root 104247844 Apr 12 2018 go1.9.2.linux-amd64.tar.gz
-rw-r--r--. 1 root root 185540433 Apr 12 2018 jdk-8u131-linux-x64.tar.gz
-rw-------. 1 root root 28908 Nov 30 11:01 nohup.out
drwxr-xr-x. 2 root root 39 Aug 10 2016 openscap_data
drwxr-xr-x. 10 root root 4096 Apr 13 2018 privoxy-3.0.26-stable
-rw-r--r--. 1 root root 1741772 Aug 27 2016 privoxy-3.0.26-stable-src.tar.gz
5. cat
(concatenate)顯示檔案內容
$cat dingtest
if (( i == 100 ))
then
echo "$i == 100"
else
echo "$i != 100"
fi
如果沒有指定引數,$*為空,cat也接受不到任何引數,這會使它從標準輸入中讀取
cat $* |
while read line
do
echo "$line"
done
6. wc
統計行數、單詞數、字元數;命令選項必須出現在檔名引數之前
$wc dingtest
6 17 69 dingtest
$wc -l dingtest
6 dingtest
$wc -w dingtest
17 dingtest
$wc -c dingtest
69 dingtest
7. cp
複製檔案,saved_names
如果存在會被覆蓋
$cp names saved_names
# 將檔案collect從目錄../programs複製到當前目錄中
$cp ../programs/collect .
8. mv
檔案重新命名,hold_it
如果存在會被覆蓋;
在目錄間移動檔案
$ mv saved_names hold_it
#將三個檔案移動到../misc目錄中
$ mv wb collect mon ../misc
9. rm
刪除檔案
$ rm hold_it
-
-f
忽略不存在的檔案,強制刪除,不給出提示。 -
-r
指示rm將引數中列出的全部目錄和子目錄均遞迴地刪除。 -
-i
進行互動式刪除。因為一旦檔案被刪除,它是不能被恢復的。為了防止這種情況的發生,可以使用“i”選項來逐個確認要刪除的檔案。如果使用者輸入“y”,檔案將被刪除。 -
rm -r <dir>
刪除指定目錄和其中的所有檔案(如果沒有使用- r
選項,則rm不會刪除目錄。 ) -
rm -rf *
刪除當前目錄下的所有檔案
10. pwd
顯示工作目錄
$pwd
/ding
11. cd
更改目錄,引數-
表示上一個目錄,無引數表示回到HOME目錄
12. mkdir
建立目錄
13. rmdir
刪除目錄,要先刪除目錄中包含的所有檔案,否則會報錯;
14. ln
檔案連結,一個檔案有連個不同的名字,不會佔用兩倍磁碟空間;
對於普通連結,被連結的檔案必須與連結檔案處於同一個檔案系統中,否則會報錯;
可以隨意刪除兩個連線檔案中的任何一個,另外一個不會因此消失
$ ln wb writeback
$ ls -l
...
-rwxr-xr-x 2 steve DP3822 89 JUL 20 15:22 wb
-rwxr-xr-x 2 steve DP3822 89 JUL 20 15:22 writeback
要在不同檔案系統的檔案之間建立連結,使用-s選項,這叫做符號連結(ls -l檔案型別為l),指向原始檔案;
例子中檔案大小為15,內容其實就是字串/users/steve/wb;
如果原始檔案被刪除,符號連結無效,但符號連結本身不會刪除->懸掛符號連結;
- -Ll獲得符號連結所指向檔案的詳細資訊
$ ln -s /users/steve/wb ./symwb
$ ls -l
...
lrwxr-xr-x 1 pat DP3822 15 JUL 20 15:22 symb -> /users/steve/wb
$ ls -Ll
...
-rwxr-xr-x 2 steve DP3725 15 JUL 20 13:30 wb
為特定目標目錄中的多個檔案建立連結:
ln <files> <directory>
15. ps
給出系統中所執行程序的資訊:PID、TTY、程序所使用的計算機時間、程序名稱;
-f
列印更多資訊:PPID(父程序ID)、程序開始時間
$ ps
PID TTY TIME CMD
4581 pts/0 00:00:00 bash
9255 pts/0 00:00:00 ps
$ ps -f
UID PID PPID C STIME TTY TIME CMD
root 4581 3875 0 19:56 pts/0 00:00:00 -bash
root 10717 4581 0 21:38 pts/0 00:00:00 ps -f
16. cut
從每行內提取欄位:cut -cchars file
-d
指定欄位分隔符;-f
指定待提取的欄位
# 提取前8個字元
$ who | cut -c1-8
# 提取前8個字元,然後提取第18個到行尾的字元
$ who | cut -c1-8,18-
# 從/etc/passwd檔案中提取每行的由:分割的第1和6欄位
$ cut -d: -f1,6 /etc/passwd
17. paste
將檔案中每行合併在一起,由製表符分隔
-d
指定分隔符;-s
將同一個檔案中的所有行合併到一起,預設製表符分隔
$ paste names numbers
Tony 123456
Emanuel 55555
# 貼上ls命令的輸出(paste將來自標準輸入`-`的所有行進行合併),使用空格作為分隔符
$ ls | paste -d' ' -s -
18. tr
過濾器,轉換標準輸入中的字元;從標準輸入獲得輸入,結果寫入標準輸出,不改動原始檔案
-s
壓縮多次連續出現的字元;-d
刪除輸入流中的個別字元
# 將:換成製表符,11為製表符的八進位制值
tr : '\11'
# 小寫換成大寫,加引號避免Shell將其解釋為模式
tr '[a-z]' '[A-Z]' < intro
# 大寫轉小寫,小寫轉大寫
tr '[a-zA-Z]' '[A-Za-z]'
# A-M轉成N-Z,N-Z轉成A-M
tr '[A-Z]' '[N-ZA-M]'
# 所有:轉成製表符,使用單個製表符替代多個製表符
tr -s ':' '\11'
# 刪除換頁符
tr -d '\14'
19. grep
在一個或多個檔案中搜索指定的模式
-i
忽略大小寫;-v
獲得不匹配的行;-l
得到匹配指定模式的行所在的檔案;-n
顯示行號
# 在當前目錄的所有檔案中搜索單詞shell
grep shell *
# *放在單引號中避免Shell誤解
grep '*' stars
20. sort
字母順序排序,特殊字元按內部編碼排序,空格32,雙引號34
-u
消除重複行-r
逆序排列-o
指定輸出檔案-n
將行中第一個欄位視為數字,對應的資料進行算數排序sort -k2 <file>
從第2個欄位開始排序-t
後的字元被視為分隔符,sort -k3n -t: /etc/passwd
對第3個以冒號分隔的欄位進行算數排序
21. uniq
uniq in_file (out_file)
查詢或刪除重複行(連續出現的重複行,所以一般需要先sort才能被判斷為重複),可做過濾器
-d
只把重複的行寫入輸出-c
統計出現的次數
sort names | uniq
sort names |uniq -d
# 找出資料檔案中詞頻最高的單詞
tr '[A-Z]' '[a-z]' datafile | sort | uniq -c | head
22. expr
數學等式解算器,運算元和操作符之間必須用空格分隔!!!
:
操作符,針對出現在第二個運算元中的正則表示式匹配第一個運算元中的字元,預設返回匹配到的字元數
$ expr $i + 1
1
$ expr "$file" : ".*"
0
23. shift
向左移動位置引數,同時,$#
的值也會自動減1;
-
如果
$#
已經為0的情況下使用shift
,會發出錯誤資訊:prog: shift: bad number
(prog
是執行不當的shift命令的程式名) -
shift 3
:一次移動3個位置
24. test
測試單個或多個條件
-
test命令的所有運算元和操作符必須是獨立的,用空白字元分隔的!
-
將test的引數放在雙引號中是一種良好的程式設計實踐
# test命令的所有運算元和操作符必須是獨立的,用空白字元分隔的
4 test "$name" = julio
$ test 1 = 1
$ echo $?
0
# =的優先順序高於-z,所以test會將命令作為等量關係測試來處理,希望在=之後還有一個引數,所以報了錯
$ symbol==
$ test -z "$symbol"
$ echo $?
1
# 下面的寫法可以防止這種情況發生
$ test X"$symbol" = X
-
test的另一種格式:
[ express ]
- express兩邊與[]之間必須有空格
$ [ -z "" ] $ echo $? 0
-
test字串操作符
操作符 | 如果滿足下列條件,則退出碼為0 |
---|---|
string1 = string2 | string1等於string2 |
string1 != string2 | string1不等於string2 |
string | string不為空 |
-n string | string不為空 |
-z string | string為空 |
- test整數操作符
操作符 | 如果滿足下列條件,則退出碼為0 |
---|---|
int1 -eq int2 | int1等於int2 |
int1 -ge int2 | int1大於等於int2 |
int1 -gt int2 | int1大於int2 |
int1 -le int2 | int1小於等於int2 |
int1 -lt int2 | int1小於int2 |
int1 -ne int2 | int1不等於int2 |
在使用整數操作符時,將變數的值視為整數的是test命令,而不是Shell
- test檔案操作符
操作符 | 如果滿足下列條件,則退出碼為0 |
---|---|
-d file | file是一個目錄 |
-e file | file存在 |
-f file | file是一個普通檔案 |
-r file | 可由程序讀取 |
-s file | 不是空檔案 |
-w file | 可由程序寫入 |
-x file | 可執行 |
-L file | 是一個符號連結 |
-
邏輯否定操作符
!
:[ ! -r /users/steve/phonebook ]
-
邏輯“與”操作符
-a
:[ ! -f "$file" -a $(who > $file) ]
,(如果-f
測試沒有通過,就不會執行who
命令) -
邏輯“或”操作符
-o
:優先順序比-a
低 -
括號:改變求值順序,括號兩邊必須有空格,且要將括號本身引用起來,因為test要求條件語句的每一個元素都是獨立的引數,且括號對Shell有特殊含義(新開一個子Shell)
[ \( "$count" -ge 0 \) -a \( "$count" -lt 10 \) ]
25. exit
-exit n
:返回退出碼n
26. 空命令:
什麼都不幹,可以用在謀改革判斷分支中,因為每個匹配的語句分支都需要對應的命令
27. sleep
sleep n
:掛起程式執行n秒
28. nohup
希望某個程式在登出後繼續執行,使用nohup
命名執行該程式
29. break
退出迴圈,break n
退出第n層內迴圈
for file
do
...
while [ "$count" -lt 10 ]
do
...
if [ -n "$error" ]
then
# 當error不為空,退出while和for迴圈
break 2
fi
done
..
done
30. continue
跳過當前迭代中剩下的命令,continue n
跳過最內側的n個迴圈中的命令,繼續往下執行
31. getopts
內建命令,專門用來在迴圈中執行處理命令列引數
getopts options variable
-
options中單個字元表示選項,如果選項後還需要引數,字元後要加冒號。
mt:
表示程式支援-m``-t
選項,其中-t
還需要一個引數 -
如果減號後的字元沒有在options中列出,會在返回為0的退出狀態之前將問號儲存在variable中,向標準錯誤寫入錯誤資訊,告訴使用者指定的選項有問題
-
如果getopts沒有在選項後找到要求的引數,會將問號儲存到變數中並向標準錯誤輸出錯誤資訊。否則,就將選項字元儲存在變數中,把使用者指定的引數放在一個叫做
OPTARG
的特殊變數中 -
特殊變數
OPTIND
初始值為1,隨後每當getopts返回時都會被更新為下一個要處理的命令列引數的序號
while getopts mt: option
do
case "$option" in
m) mailopt=TRUE;;
t) interval=$OPTARG;;
\?) exit 1;;
esac
done
32. read
-
read variables
從標準輸入中讀取一行,將第一個單詞分配給variables中第一個變數,將第二個單詞分配給第二個變數,以此類推。 -
碰到檔案結尾,或使用者鍵入
ctrl+d
,read
會返回為0的退出狀態碼
cat $* |
while read line
do
echo "$line"
done
- 如果行中包含反斜線或前導空白字元,反斜線會由Shell解釋,前導空白字元會從讀入的行中刪除。
read -r
避免解釋反斜線。(可以修改變數IFS保留前導空格)
33. basename
剝離引數的所有目錄部分,得到其基礎檔名
34. printf
-
格式化輸出資訊,格式化字串中的每個百分號(格式規範)都有一個相應的引數,除了特殊規範%%,他會顯示一個百分號。
-
不會在尾部加一個換行符,能夠理解轉義序列
printf的格式規範字符
字元 | 功能 |
---|---|
%d | 整數 |
%u | 無符號整數 |
%o | 八進位制整數 |
%x | 十六進位制整數,使用a-f |
%X | 十六進位制整數,使用A-F |
%c | 單個字元 |
%s | 字串字面量 |
%b | 包含轉義字元的字串 |
%% | 百分號 |
%s不處理轉義字元,%b強制解釋轉義字元
- 轉換規範:
%[flags] [width] [.precision] type
$ printf "%+d\n%+d\n" 10 -10
+10
-10
$ printf "%-15.15s\n" "this is more than 15 chars long."
this is more th
$ printf "%*s%*.*s\n" 12 "test one" 10 2 "test two"
test one te
printf的格式規範修飾符
修飾符 | 含義 |
---|---|
Flags | |
- | 左對齊值 |
+ | 在整數前加上+或- |
(space) | 在正數前加上空格,負數前面加上-,對齊 |
# | 在八進位制數前加上0,在十六進位制數前加上0x或0X |
width | 欄位最小寬度;*表示使用下一個引數作為寬度 |
precision | 顯示整數時使用的最小位數,值左側用0填充;顯示字串時使用的最大字元數;*表示使用下一個引數作為精度 |
35. export
匯出變數,只要子Shell已啟動,匯出的變數都會被複制到子Shell,而區域性變數不會
export -p
得到列表,包含了匯出的變數和值,這些是在使用者登入後由登入Shell所匯出的
$ export -p
declare -x CLASSPATH=".:/usr/local/jdk1.8.0_131//jre/lib/rt.jar:/usr/local/jdk1.8.0_131//lib/dt.jar:/usr/local/jdk1.8.0_131//lib/tools.jar"
declare -x HISTCONTROL="ignoredups"
declare -x HISTSIZE="1000"
declare -x HOME="/root"
declare -x HOSTNAME="CENTOS-MINION-2"
declare -x JAVA_HOME="/usr/local/jdk1.8.0_131/"
...
36. .(dot)命令
. file
:在當前Shell中執行file的內容
37. exec
-
exec program
:使用新程式替換現有的程式,不會有程序處於掛起狀態,由於UNIX系統執行程序的方式,exec所替換的程式啟動時間也更快 -
還可以用來關閉標準輸入,然後使用其他你想要讀取的檔案重新開啟它
exec < infile
exec > report
#將標準輸入重新分配回終端
exec < /dev/tty
38. set
- Shell的內建命令,設定各種Shell選項、重新為位置引數$1、$2…賦值
$ set one two three
$ echo $1:$2:$3
one:two:three
-
set -x
開啟跟蹤模式;set +x
關閉跟蹤模式; -
無引數的
set
會輸出一個按照字母順序排序的變數列表,是存在於當前環境中的區域性變數或匯出變數 -
--
:告訴set對於後續出現的連線符或引數形式的單詞,均不視為其選項;是考慮到可能會出現以-起始的行、全部是空白字元或者空行 -
set -o mode
:啟動行編輯模式,mode可以是vi或emacs
39. readonly
-
指定在程式隨後的執行過程中,值都不會發生改變的那些變數,如:
readonly PATH HOME
,如果之後再檢視給這兩個變數賦值,會輸出錯誤資訊 -
變數的只讀屬性不會傳給子Shell
-
只要將變數設為只讀,就沒有“後悔藥”
40. unset
從環境中刪除謀某個變數;不能對只讀變數、IFS/MAILCHECK/PATH/PS1/PS2使用unset,
$ x=100
$ echo $x
100
$ unset x
$ echo $x
$
-f
:刪除函式
41. eval
eval args
:使得Shell對args求值,然後執行求值結果;常用於從變數中構造命令列,實際上可以實現對命令列的二次掃描;- 如果變數中包含了任何必須由Shell解釋的字元,就必須用到eval
$ cat last
eval echo \$$#
$ last one two three four
four
#得到最後一個檔案
$ last *
zoo_report
- 還可以用來建立指向變數的“指標”
$ x=100
$ ptrx=x
$ eval echo \$$ptrx
100
$ eval $ptrx=50
$ echo $x
50
42. wait
wait job
:暫停執行,直到job所標識的程序執行結束,job可以是程序ID或作業ID。如果沒有提供job,Shell會等待所有子程序結束
43. trap
trap commands signals
:告訴Shell只要接收到signals中列出的訊號,就執行commands(如果不止一個命令,要全部放入引號中),訊號以名稱或編號形式指定
#exit是必須的,否則程式會一直停留在接收到訊號時的執行位置上
trap "rm $WORKDIR/work$$ $WORKDIR/dataout$$; exit" INT
訊號編號與名稱
訊號# | 訊號名稱 | 產生原因 |
---|---|---|
0 | EXIT | 退出Shell |
1 | HUP | 掛起 |
2 | INT | 中斷(如按下DELETE鍵或ctrl+c) |
3 | QUIT | 退出 |
6 | ABRP | 中止 |
9 | KILL | 銷燬程序 |
14 | ALRM | 超時 |
15 | TERM | 軟體終止訊號(預設由kill傳送) |
-
不使用引數,trap會打印出當前的訊號處理方式
-
如果第一個引數是空串:
trap "" signals
,當Shell接收到signals指定的訊號時,會將其忽略 -
如果忽略了某個訊號,子Shell也會忽略;如果指定了某個訊號的處理程式,子Shell自動採用預設處理方式,而不是指定的處理程式
-
使用
trap signals
,會將signals中列出的訊號處理方式恢復成預設行為 -
Shell在執行trap時掃描命令列,在接收到訊號列表中的訊號時還會再掃描一遍:
trap "echo $count lines processed >> $LOGFILE; exit" HUP INT TERM
#為了防止count被提前替換,將命令放入單引號中
trap 'echo $count lines processed >> $LOGFILE; exit' HUP INT TERM
44. return
return n
:n為函式的返回狀態,可以用變數$?訪問它
45. type
接受一個或多個命令作為引數,告訴你這些命令是什麼型別
$ type echo
echo is a shell builtin
$ type ls
ls is aliased to `ls --color=auto'
$ type cat
cat is /usr/bin/cat
$ type nu
nu is a function
46. history
訪問命令歷史記錄
$ history
....
$ history 5
885 type echo
886 type ls
887 type cat
888 history
889 history 5
47. fc
-
為歷史記錄中的若干命令啟動一個編輯器或將歷史命令列表寫入終端。後一種,使用
-l
指定命令列表 -
-n
忽略命令編號 -
fc -s old=new first
執行選中的命令,無需事先編輯
fc -l 50-53
#最近20條命令寫入到標準輸出
fc -n -l -20
#將最近的sed命令送入vi中編輯
fc -e vi sed
#將編號104的命令中的abc替換成def,然後重新執行
fc -s abc=def 104
48. r (Korn Shell才有)
重新顯示上一條命令並立即執行
#執行上一條cat命令
$ r cat
cat doc/planA
#將cat命令中第一次出現的planA替換成planB
$ r cat planA=planB
49. typeset (Korn Shell才有)
-i
:宣告整數型別- 整數表示式可以分配給整數型別的變數,甚至不需要((…))
$ typeset -i i
$ i=hello
ksh: i: bad number
50. alias
alias name=string
:自定義命令
- 如果別名以空格結束,則會對其之後的單詞執行別名替換
- 把命令引用起來或放在反斜線之後可以避免進行別名替換
alias ll='ls -l'
51. unalias
unalias name
:刪除別名
unalias -a
:刪除所有別名
52. jobs
打印出尚未完成的作業狀態
53. kill
終止後臺作業
54. fg
ctrl+z掛起當前執行的作業,fg在前臺恢復執行當前作業
55. bg
在後臺恢復執行當前作業
語句結構
1. if
if command-t1
then
command
command