Linux Shell 簡明教程

weixin_33896726發表於2016-10-22

第一章 背景知識

軟體工具的原則

  • 一次做好一件事

這個原則的結果自然就是會不斷產生出更小、更專用於特定功能的程式。

  • 處理文字行,不要處理二進位制

文字行可以用任何文字編輯器來編輯,也可以在網路與各種機器架構之間傳輸。
二進位制是平臺相關的。

  • 使用正規表示式

使用正規表示式能簡化命令指令碼的工作。
POSIX標準提供兩種正規表示式:BRE(與grep一致的正規表示式)和ERE(與egrep一致的)。

  • 預設使用標準輸入/輸出

在未明確指定檔名時,程式預設從標準輸入讀取資料,將資料寫到標準輸出。
這樣可以輕鬆地讓它們成為資料過濾器,組成複雜的管道或指令碼。

  • 避免喋喋不休

不要將“開始處理”,“即將完成”,“處理完成”這類資訊放程式序的標準輸出。
將這樣的資訊送往管道,別指望執行結果會像預期的一樣。在工具程式的世界裡,
沒有訊息就是好訊息。

  • 讓工具去做困難的部分

雖然Unix程式並非完全符合你的需求,但是現有的工具或許可以為你完成90%的工作。
接下來可以編寫一個功能特定的小型程式來完成剩下的工作。

第二章 入門

  • 指令碼中的引用命令使用絕對路徑
  • 每一個空格都能影響結果
  • #!/bin/sh可以避免某種程式的欺騙攻擊
  • ";"分號,可以分隔同一行裡的多條命令
  • "&"代表後臺執行,並且此後的命令不用等待它完成。
  • 父 Shell將等待子Shell 的所有相關程式完成後,才繼續執行
  • 變數賦值的時候"="前後沒有空格,引用的時候在變數前面加 $ 當賦值
    m衧空格的時候請加上引號
  • echo -n 會忽略結尾的換行符,但是echo版本上存在差異不建議過多使用。
  • printf "Hello $s !/n" World,幾乎複製了c中printf的所有功能
  • ctrl+D,也就是符號 "^D", 代表檔案結尾
  • < 改變標準輸入,只限於兩個程式之間
  • > 改變標準輸出,只限於兩個程式之間
  • >> 追加到檔案
  • pro1 | pro2 將 pro1 的標準輸出重定位到pro2 的標準輸入。管道符可以多個程式相連
  • tr足極其簡化的sed,他所能完成的任務sed都能,反之則不行。
  • /dev/null即是位桶檔案(bit bucket),類似垃圾桶,讀取返回檔案結束符
  • /dev/tty 會重定向到終端,讀取人工輸入時有用

    printf "Enter password:"
    stty -echo #關閉冋顯
    read pass
    printf "Enter password again:"
    read pass
    stty echo #打幵回顯
  • $PATH中加入 "." 可以包含當前目錄,不過不安全
  • $1 代表第一個引數,大於9就要用括號.,比如$(10)

    cat >finduser
#!/bin/sh
who | grep $1
^D
    finduser aaron
  • Shell將忽略#開頭的一行,註釋 。
  • Shell腳木裡set +x 會開啟執行跟蹤,set -x 關閉跟蹤。
  • Shell裡特殊字元稱作元字元(metacharacter)

第三章 查詢與替換

  • [] 內的 "^" 表示取反
  • [0-9a-zA-F】,範圍表示不建議在新程式裡運用。
  • "a/{5/}"表示重複5個a,"q/{10,42/}"表示10到42個q
  • 正規表示式中"^"表示開頭,"$" 表示結尾 "^$" 表示空行。另外 "grep -v" 顯示不匹配的結果
  • "ab?c" 匹配ac或者abc
  • "ab+c" 等同於 "abb*c",匹配 abc,abbc...,但不匹配 ac
  • "sleep|wakeup|idle" 匹配 sleep,wakeup,idle。注意 | 優先順序最低。
  • "[Tt]he(computer|PC)is" 匹配 The 或者 the 和 is 之間出現 computer 或
    PC的句子。
  • "/<" 和 "/>" 用來匹配單詞,可以分開使用。
  • grep 是 ed (商用unix上的vi)中 "g/re/p" 的縮寫,意思是全域性匹配並列印。 ed也是sed的基礎。
  • tr 是極其簡化的 sed。"tr -c -d -s [string_to_translate_from] [string_to_translate_to] < input_file"

  • sed與空字串,匹配最長子串,awk也是。意思就是匹配滿足條件的從左到右最長的一段
  • grep和sed的絕大部分是用來處理行(line)。awd,perl及Python處理字串(string)
  • cut 用來剪下資料,join用來連線資料,sort用來排列資料。(以Tab分隔
    的資料)
    awk -F: '{print "User", $1, "is really", $5}' /etc/passwd

第四章 文字處理

  • sort (排序)屬於UNIX前十名主要的命令
  • uniq刪除排序後的重複行
  • wc計算字數,行數,位元組數
  • head和tail顯示檔案頭和尾

第五章 管道的神奇魔力

  • $$表示程式號
  • trap用來捕捉訊號,並執行命令。格式如: trap [-lp] [arg] [sigspec ...]

第六章 變數判斷秉復動作

  • export用於修改和列印環境變數,readonly使其不能修改。
  • env 用來改變環境變數
  • unset用來刪除當前Shell的變數和函式
  • 未定義的變數會展開為NULL,隨意操作將會引發異常。
  • ${varname:-val}如果varname存在並不是null,將返回varname,否則返回val
    ${varname:=val}如果 varname 存在並不是 null,將返回varname,否則賦值為val並返回val。
    ${vamame:?val}如果 varname 存在並不是 null,將返回varname,否則顯示varname:val。
    ${varname:+val}如果varname存在並不是null,將返回val,否則返回null。
    如果去掉冒號,則表示存在,可以是null。
  • "$#" 引數的總數,$*,$@。shift截掉$1後,$2變成$1,類推。。。
  • 通用的變數(前面加上 $ 將引用變數)。# 引數個數,
  • 每一條命令,不管是內建的Shell命令,還是外部的。當他退出時,都會返回一個小的整數給呼叫它的函式。0表示成功。
  • exit從Shell指令碼返回一個退出狀態給呼叫者
  • &&邏輯與,if...then...。|| 邏輯或,ifnot...then...。

if ....; then
....
elif ....; then
....
else
....
fi

引數說明:


[ -f "somefile" ] 判斷是否是一個檔案
[ -x "/bin/ls" ] 判斷/bin/ls是否存在並有可執行許可權
[ -n "$var" ] 判斷$var變數是否有值
[ "$a" = "$b" ] 判斷$a和$b是否相等
-r file     使用者可讀為真
-w file     使用者可寫為真
-x file     使用者可執行為真
-f file     檔案為正規檔案為真
-d file     檔案為目錄為真
-c file     檔案為字元特殊檔案為真
-b file     檔案為塊特殊檔案為真
-s file     檔案大小非0時為真
-t file     當檔案描述符(預設為1)指定的裝置為終端時為真

  • 條件判斷中方括號裡的引數必須有引弓。
  • 條件判斷只能做整數測試,不能針對浮點
  • 條件判斷 "x$a" = "x$b",x 表示不擴充套件
  • getopts簡化引數處理,支援類似 -xvf 這樣寫在一起的引數。
  • 函式裡return的作用類似於exit。

第七章輸入輸出檔案與命令執行

  • read,將資訊讀入一個或者多個Shell變數。


    while read...
    do
    ...
    done < file
  • set -C 當>重定向遇到目標檔案存在時,會失敗
    program << delimiter 之後跟輸入的正文+delimiter。
    <>開啟一個義件作為輸入和輸出

  • 2>&1 必須連在一起
  • exec以新的程式代替shell,或者改變shell 的I/O。將不會回到指令碼里,
    除非呼叫失敗。
  • printf...
  • 當前使用者的根目錄,~name,name使用者的根目錄。可移植性不好
  • ?通配一個字元,*通配多個字元,[abc]通配a,b,c [!abc]除了 a,b, c
  • $() 包括幾個命令的時候,代表一個整體,術語是 "命令替換"。
  • expr用於運算
  • 反斜槓""轉義(單引號--保留字面值; 雙引號--會做變數轉換之類的)
  • eval告知Shell取出eval的引數,並執行他(們)。
  • shell內部的解釋過程比較晦澀,定義變數儘量簡單。
  • "subshell --()" 括號內的命令集將單獨開一個程式去執行。
  • command 可以訪問內建命令
  • set

第八章 產生指令碼

  • basename 從完整路徑中取出檔名。再加一個引數就是要從檔名結尾去掉的字串。

第九章 awk太強大

  • 命令格式
    awk [-F field-separator] 'commands' input-file(s)

  • awk內建變數


    ARGC 命令列引數個數
    ARGV 命令列引數排列
    ENVIRON 支援佇列中系統環境變數的使用
    FILENAME awk瀏覽的檔名
    FNR 瀏覽檔案的記錄數
    FS 設定輸入域分隔符,等價於命令列 -F選項
    NF 瀏覽記錄的域的個數
    NR 已讀的記錄數
    OFS 輸出域分隔符
    ORS 輸出記錄分隔符
    RS 控制記錄分隔符
  • 例項


    假設last -n 5的輸出如下

[root@www ~]# last -n 5
root pts/1 192.168.1.100 Tue Feb 10 11:21 still logged in
root pts/1 192.168.1.100 Tue Feb 10 00:46 - 02:28 (01:41)
root pts/1 192.168.1.100 Mon Feb 9 11:41 - 18:30 (06:48)
dmtsai pts/1 192.168.1.100 Mon Feb 9 11:41 - 11:41 (00:00)
root tty1 Fri Sep 5 14:09 - 14:10 (00:01)如果只是顯示最近登入的5個帳號

#last -n 5 | awk '{print $1}'
root
root
root
dmtsai
root

第十章 檔案處理

  • ls
  • od 可以檢視無法顯示出來的字元。
  • touch
  • mktmp /tmp/myprog.xxxxxxxxxxxxx 建立一個隨機的檔名。
  • /dev/random和/dev/urandom都產生隨機數,urandom比較快但是不夠隨機(基木夠用)。這兩個可以替代mktmp的功能。
  • type
  • find
  • find sth. -type f 丨 xargs grep sth1 - /dev/null,xargs 只是在 stdout 上去的引數
    列表,一行一個。
  • 使用diff的慣例是把舊檔案放在第一個引數。

相關文章