久久精品国产精品国产精品污,男人扒开添女人下部免费视频,一级国产69式性姿势免费视频,夜鲁夜鲁很鲁在线视频 视频,欧美丰满少妇一区二区三区,国产偷国产偷亚洲高清人乐享,中文 在线 日韩 亚洲 欧美,熟妇人妻无乱码中文字幕真矢织江,一区二区三区人妻制服国产

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

shell十三问--shell教程

發布時間:2024/3/12 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 shell十三问--shell教程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

為什么80%的碼農都做不了架構師?>>> ??

13_questions_of_shell

shell十三問--shell教程(markdown 版本)

##shell十三問之1: 何為shell?


shell是什么東西之前,不妨讓我們重新審視使用者和計算機系統的關系: (此處為使用者和計算機系統的關系圖)

我們知道計算機的運作不能離開硬件,但使用者卻無法直接操作硬件, 硬件的驅動只能通過一種稱為“操作系統(OS,Opertating System)”的軟件來管控。 事實上,我們每天所談的“linux”,嚴格來說只是一個操作系統(OS), 我們稱之為“內核(kernel)”。

然而,從使用者的角度來說,使用者沒有辦法直接操作一個kernel, 而是通過kernel的“外殼”程序,也就是所謂的shell,來與kernel溝通。 這也正是kernel跟shell的形象命名的的關系。如圖: (此處為kernel-->shell關系圖;)

從技術的角度來說,shell是一個使用者與系統的交互界面(interface), 只能讓使用者通過命令行(command line)來使用系統來完成工作。 因此,shell最簡單的定義就是----命令解釋器( Command Interpreter):

  • 將使用者的命令翻譯給kernel來處理;
  • 同時,將kernel的處理結果翻譯給使用者。

每次當我們完成系統登入(login), 我們就取得一個交互模式的shell, 也稱之為login shell 或者 primary shell。

若從進程(process)的角度來說,我們在shell所下達的命令,均是shell所產生的子進程。 這種現象,我暫可稱之為fork。

如果是執行shell腳本(shell script)的話,腳本中命令則是由另一個非交互模式的 子shell(sub shell)來執行的。 也就是primary shell產生sub shell的進程,而該sub shell 進程再產生script中所有命令的進程。 (關于進程,我們日后有機會在補充)

這里, 我們必須知道:kernel 與 shell 是不同的兩套軟件,而且都是可以被替換的:

  • 不同的OS使用不同的kernel;
  • 同一個kernel之上,也可以使用不同的shell;

在Linux的預設系統中,通常可以找到好幾種不同的shell, 且通常會被記錄在如下文件中:

/etc/shells

不同的shell有著不同的功能,且彼此各異,或者說“大同小異”。 常見的shell主要分為兩大主流:

  • sh:
    • burne shell (sh)
    • burne again shell (bash)
  • csh:
    • c shell (csh)
    • tc shell (tcsh)
    • korn shell (ksh) (FIXME)
  • 大部分的Linux操作系統的預設shell都是bash,其原因大致如下兩種:

    • 自由軟件
    • 功能強大 bash是gnu project最成功的產品之一,自推出以來深受廣大Unix用戶的喜愛, 且也逐漸成為不少組織的系統標準。

    ##shell十三問之2:shell prompt(PS1)與Carriage Return(CR)關系


    當你成功登陸一個shell終端的文字界面之后,大部分的情形下, 你會在屏幕上看到一個不斷閃爍的方塊或者底線(視不同的版本而別), 我們稱之為游標(cursor). cursor作用就是告訴你接下來你從鍵盤輸入的按鍵所插入的位置, 且每輸入一個鍵,cursor便向右移動一個格子, 如果連續輸入太多的話,則自動接在下一行輸入。

    假如你剛完成登陸,還沒有輸入任何按鍵之前, 你所看到的cursor所在的位置的同一行的左邊部分,我們稱之為提示符(prompt)。

    提示符的格式或因不同的版本而各有不同, 在Linux上,只需留意最接近游標的一個提示符號,通常是如下兩者之一:

    • $: 給一般用戶賬號使用;
    • #: 給root(管理員)賬號使用;

    事實上,shell prompt的意思很簡單: 告訴shell使用者,您現在可以輸入命令行了。

    我們可以說,使用者只有在得到shell prompt才能打命令行, 而cursor是指示鍵盤在命令行的輸入位置,使用者每輸入一個鍵, cursor就往后移動一個格,直到碰到命令行讀進CR(Carriage Return, 由Enter鍵產生)字符為止。 CR的意思也很簡單: 使用者告訴shell:老兄,你可以執行的我命令行了。 嚴格來說: 所謂的命令行, 就是在shell prompt與CR之間所輸入的文字。

    (question:為何我們這里堅持使用CR字符而不說Enter按鍵呢? 答案在后面的學習中給出)。

    不同的命令可以接受的命令的格式各有不同, 一般情況下,一個標準的命令行格式為如下所列:

    command-name options argument

    若從技術的細節上來看, shell會依據IFS(Internal Field Seperator) 將 command line 所輸入的文字給拆解為字段(word). 然后在針對特殊的字符(meta)先做處理,最后在重組整行command line。

    (注意:請務必理解以上兩句的意思,我們日后的學習中常回到這里思考。)

    其中IFS是shell預設使用的字段位分隔符號,可以由一個及多個如下按鍵組成:

    • 空白鍵(White Space)
    • 表格鍵(Tab)
    • 回車鍵(Enter)

    系統可以接受的命令的名稱(command-name)可以從如下途徑獲得:

    • 確的路徑所指定的外部命令
    • 命令的別名(alias)
    • shell內建命令(built-in)
    • $PATH之下的外部命令

    每一個命令行均必須包含命令的名稱,這是不能缺少的。

    ##shell十三問之3:別人echo、你也echo,是問echo知多少?

    承接上一章介紹的command line, 這里我們用echo這個命令加以進一步說明。

    溫習 標準的command line三個組成部分:command_name option argument

    echo是一個非常簡單、直接的Linux命令:

    $echo argument

    echo將argument送出到標準輸出(stdout),通常是在監視器(monitor)上輸出。

    Note:

    在linux系統中任何一個進程默認打開三個文件:stdin、stdout、stderr.

    stdin 標準輸入

    stdout 標準輸出

    stderr 標準錯誤輸出

    為了更好理解,不如先讓我們先跑一下echo命令好了:

    $echo$

    你會發現只有一個空白行,然后又回到了shell prompt上了。 這是因為echo在預設上,在顯示完argument之后,還會送出以一個換行符號 (new-line charactor). 但是上面的command echo并沒有任何argument,那結果就只剩一個換行符號。 若你要取消這個換行符號, 可以利用echo的-n 選項:

    $echo -n $

    不妨讓我們回到command line的概念上來討論上例的echo命令好了: command line只有command_name(echo)及option(-n),并沒有顯示任何argument。

    要想看看echo的argument,那還不簡單接下來,你可以試試如下的輸入:

    $echo first line first line $echo -n first line first line $

    以上兩個echo命令中,你會發現argument的部分顯示在你的屏幕, 而換行符則視 -n 選項的有無而別。 很明顯的,第二個echo由于換行符被取消了, 接下來的shell prompt就接在輸出結果的同一行了... ^_^。

    事實上,echo除了-n 選項之外,常用選項有:

    • -e: 啟用反斜杠控制字符的轉換(參考下表)
    • -E: 關閉反斜杠控制字符的轉換(預設如此)
    • -n: 取消行末的換行符號(與-e選項下的\c字符同意)

    關于echo命令所支持的反斜杠控制字符如下表:

    轉義字符字符的意義
    \aALERT / BELL(從系統的喇叭送出鈴聲)
    \bBACKSPACE, 也就是向左退格鍵
    \c取消行末之換行符號
    \EESCAPE, 脫字符鍵
    \fFORMFEED, 換頁字符
    \nNEWLINE, 換行字符
    \rRETURN, 回車鍵
    \tTAB, 表格跳位鍵
    \vVERTICAL TAB, 垂直表格跳位鍵
    \nASCII 八進制編碼(以x開頭的為十六進制),此處的n為數字
    \反斜杠本身

    Note: 上述表格的資料來自O'Reilly出版社的Learning the Bash Shell, 2nd Ed.

    或許,我們可以通過實例來了解echo的選項及控制字符:

    例一:

    $ echo -e "a\tb\tc\n\d\te\tf" a b c d e f $

    上例中,用\t來分割abc還有def,及用\n將def換至下一行。

    例二:

    $echo -e "\141\011\142\011\143\012\144\011\145\011\146" a b c d e f

    與例一中結果一樣,只是使用ASCII八進制編碼。

    例三:

    $echo -e "\x61\x09\x62\x09\x63\x0a\x64\x09\x65\x09\x66" a b c d e f

    與例二差不多,只是這次換用ASCII的十六進制編碼。

    例四:

    $echo -ne "a\tb\tc\nd\te\bf\a" a b c d f $

    因為e字母后面是退格鍵(\b),因此輸出結果就沒有e了。 在結束的時聽到一聲鈴響,是\a的杰作。 由于同時使用了-n選項,因此shell prompt緊接在第二行之后。 若你不用-n的話,那你在\a后再加個\c,也是同樣的效果。

    事實上,在日后的shell操作及shell script設計上, echo命令是最常被使用的命令之一。 比方說,使用echo來檢查變量值:

    $ A=B $ echo $A B $ echo $? 0

    Note: 關于變量的概念,我們留到以下的兩章跟大家說明。

    好了,更多的關于command line的格式, 以及echo命令的選項, 請您自行多加練習、運用了...

    ##shell十三問之4:""(雙引號)與''(單引號)差在哪?

    還是回到我們的command line來吧...

    經過前面兩章的學習,應該很清楚當你在shell prompt后面敲打鍵盤, 直到按下Enter鍵的時候,你輸入的文字就是command line了, 然后shell才會以進程的方式執行你所交給它的命令。 但是,你又可知道:你在command line中輸入的每一個文字, 對shell來說,是有類別之分的呢?

    簡單而言,(我不敢說精確的定義,注1), command line的每一個charactor, 分為如下兩種:

    • literal:也就是普通的純文字,對shell來說沒特殊功能;
    • meta: 對shell來說,具有特定功能的特殊保留元字符。

    Note:

    對于bash shell在處理comamnd line的順序說明, 請參考O'Reilly出版社的Learning the Bash Shell,2nd Edition, 第177-180頁的說明,尤其是178頁的流程圖:Figure 7-1 ...

    literal沒什么好談的, 像abcd、123456這些"文字"都是literal...(so easy? ^_^) 但meta卻常使我們困惑...(confused?) 事實上,前兩章,我們在command line中已碰到兩個 似乎每次都會碰到的meta:

    • IFS:有space或者tab或者Enter三者之一組成(我們常用space)
    • CR: 由Enter產生;

    IFS是用來拆解command line中每一個詞(word)用的, 因為shell command line是按詞來處理的。 而CR則是用來結束command line用的,這也是為何我們敲Enter鍵, 命令就會跑的原因。

    除了常用的IFS與CR, 常用的meta還有:

    meta字符meta字符作用
    =設定變量
    $作變量或運算替換(請不要與shell prompt混淆)
    >輸出重定向(重定向stdout)
    <輸入重定向(重定向stdin)
    |命令管道
    &重定向file descriptor或將命令至于后臺(bg)運行
    ()將其內部的命令置于nested subshell執行,或用于運算或變量替換
    {}將期內的命令置于non-named function中執行,或用在變量替換的界定范圍
    ;在前一個命令執行結束時,而忽略其返回值,繼續執行下一個命令
    &&在前一個命令執行結束時,若返回值為true,繼續執行下一個命令
    ||在前一個命令執行結束時,若返回值為false,繼續執行下一個命令
    !執行histroy列表中的命令
    ......

    假如我們需要在command line中將這些保留元字符的功能關閉的話, 就需要quoting處理了。

    在bash中,常用的quoting有以下三種方法:

    • hard quote:''(單引號),凡在hard quote中的所有meta均被關閉;
    • soft quote:""(雙引號),凡在soft quote中大部分meta都會被關閉,但某些會保留(如$);
    • escape: \ (反斜杠),只有在緊接在escape(跳脫字符)之后的單一meta才被關閉;

    Note:

    在soft quote中被豁免的具體meta清單,我不完全知道, 有待大家補充,或通過實踐來發現并理解。

    下面的例子將有助于我們對quoting的了解:

    $ A=B C #空白符未被關閉,作為IFS處理 $ C:command not found. $ echo $A$ A="B C" #空白符已被關掉,僅作為空白符 $ echo $A B C

    在第一個給A變量賦值時,由于空白符沒有被關閉, command line 將被解釋為: A=B 然后碰到<IFS>,接著執行C命令 在第二次給A變量賦值時,由于空白符被置于soft quote中, 因此被關閉,不在作為IFS; A=B<space>C 事實上,空白符無論在soft quote還是在hard quote中, 均被關閉。Enter鍵字符亦然:

    $ A=`B > C > ' $ echo "$A" B C

    在上例中,由于enter被置于hard quote當中,因此不再作為CR字符來處理。 這里的enter單純只是一個斷行符號(new-line)而已, 由于command line并沒得到CR字符, 因此進入第二個shell prompt(PS2, 以>符號表示), command line并不會結束,直到第三行, 我們輸入的enter并不在hard quote里面, 因此沒有被關閉, 此時,command line碰到CR字符,于是結束,交給shell來處理。

    上例的Enter要是被置于soft quote中的話,CR字符也會同樣被關閉:

    $ A="B > C > " $ echo $A B C

    然而,由于 echo $A時的變量沒有置于soft quote中, 因此,當變量替換完成后,并作命令行重組時,enter被解釋為IFS, 而不是new-line字符。

    同樣的,用escape亦可關閉CR字符:

    $ A=B\ > C\ > $ echo $A BC

    上例中的,第一個enter跟第二個enter均被escape字符關閉了, 因此也不作為CR來處理,但第三個enter由于沒有被escape, 因此,作為CR結束command line。 但由于enter鍵本身在shell meta中特殊性,在 \ escape字符后面 僅僅取消其CR功能, 而不保留其IFS功能。

    你或許發現光是一個enter鍵所產生的字符,就有可能是如下這些可能:

    • CR
    • IFS
    • NL(New Line)
    • FF(Form Feed)
    • NULL
    • ...

    至于,什么時候解釋為什么字符,這個我就沒法去挖掘了, 或者留給讀者君自行慢慢摸索了...^-^

    至于soft quote跟hard quote的不同,主要是對于某些meta的關閉與否,以$來做說明:

    $ A=B\ C $ echo "$A" B C $ echo '$A' $A

    在第一個echo命令行中,$被置于soft quote中,將不被關閉, 因此繼續處理變量替換, 因此,echo將A的變量值輸出到屏幕,也就是"B C"的結果。

    在第二個echo命令行中,$被置于hard quote中,則被關閉, 因此,$只是一個$符號,并不會用來做變量替換處理, 因此結果是$符號后面接一個A字母:$A.

    練習與思考: 如下結果為何不同?

    tips: 單引號和雙引號,在quoting中均被關閉了。

    $ A=B\ C $ echo '"$A"' #最外面的是單引號 "$A" $ echo "'$A'" #最外面的是雙引號 'B C'

    在CU的shell版里,我發現很多初學者的問題, 都與quoting的理解有關。 比方說,若我們在awk或sed的命令參數中, 調用之前設定的一些變量時,常會問及為何不能的問題。

    要解決這些問題,關鍵點就是:區分出 shell meta 與 command meta

    前面我們提到的那些meta,都是在command line中有特殊用途的, 比方說{}就是將一系列的command line置于不具名的函數中執行(可簡單視為command block), 但是,awk卻需要用{}來區分出awk的命令區段(BEGIN,MAIN,END). 若你在command line中如此輸入:

    $ awk {print $0} 1.txt

    由于{}在shell中并沒有關閉,那shell就將{print $0}視為command block, 但同時沒有;符號作命令分隔,因此,就出現awk語法錯誤結果。

    要解決之,可用hard quote:

    awk '{print $0}'

    上面的hard quote應好理解,就是將原來的 {、<space>、$、}這幾個shell meta關閉, 避免掉在shell中遭到處理,而完整的成為awk的參數中command meta。

    Note:

    awk中使用的$0 是awk中內建的field nubmer,而非awk的變量, awk自身的變量無需使用$.

    要是理解了hard quote的功能,在來理解soft quote與escape就不難:

    awk "{print \$0}" 1.txt awk \{print \$0\} 1.txt

    然而,若要你改變awk的$0的0值是從另一個shell變量中讀進呢? 比方說:已有變量$A的值是0, 那如何在command line中解決 awk的$$A呢? 你可以很直接否定掉hard quote的方案:

    $ awk '{print $$A}' 1.txt

    那是因為$A的$在hard quote中是不能替換變量的。

    聰明的讀者(如你!),經過本章的學習,我想,你應該可以理解為 為何我們可以使用如下操作了吧:

    A=0 awk "{print \$$A}" 1.txt awk \{print\ \$$A\} 1.txt awk '{print $'$A'}' 1.txt awk '{print $'"$A"'}' 1.txt

    或許,你能給出更多方案... ^_^

    更多練習:

    • http://bbs.chinaunix.net/forum/viewtopic.php?t=207178 一個關于read命令的小問題: 很早以前覺得很奇怪:執行read命令,然后讀取用戶輸入給變量賦值, 但如果輸入是以空格鍵開始的話,這空格會被忽略,比如:
    read a #輸入: abc echo "$a" #只輸出abc

    原因: 變量a的值,從終端輸入的值是以IFS開頭,而這些IFS將被shell解釋器忽略(trim)。 應該與shell解釋器分詞的規則有關;

    read a #輸入:\ \ \ abc echo "$a" #只輸出abc

    需要將空格字符轉義

    Note:

    IFS Internal field separators, normally space, tab, and newline (see Blank Interpretation section). ...... Blank Interpretation After parameter and command substitution, the results of substitution
    are scanned for internal field separator characters (those found in IFS) and split into distinct arguments where such characters are found. Explicit null arguments ("" or '') are retained.
    Implicit null arguments(those resulting from parameters that have no values) are removed. (refre to: man sh)

    解決思路:

  • shell command line 主要是將整行line給分解(break down)為每一個單詞(word);
  • 而詞與詞之間的分隔符就是IFS (Internal Field Seperator)。
  • shell會對command line作處理(如替換,quoting等), 然后再按詞重組。(注:別忘了這個重組特性)
  • 當你用IFS來事開頭一個變量值,那shell會先整理出這個詞,然后在重組command line。 5.然而,你將IFS換成其他,那shell將視你哪些space/tab為“詞”,而不是IFS。那在重組時,可以得到這些詞。
  • 若你還是不理解,那來驗證一下下面這個例子:

    $ A=" abc" $ echo $A abc $ echo "$A" #note1abc $ old_IFS=$IFS $ IFS=; $ echo $Aabc $ IFS=$old_IFS $ echo $A abc

    Note:

  • 這里是用 soft quoting 將里面的 space 關閉,使之不是 meta(IFS), 而是一個literal(white space);
  • IFS=; 意義是將IFS設置為空字符,因為;是shell的元字符(meta);
  • 問題二:為什么多做了幾個分號,我想知道為什么會出現空格呢?

    $ a=";;;test" $ IFS=";" $ echo $a test $ a=" test" $ echo $a test $ IFS=" " $ echo $a test

    解答:

    這個問題,出在IFS=;上。 因為這個;在問題一中的command line上是一個meta, 并非";"符號本身。 因此,IFS=;是將IFS設置為 null charactor (不是space、tab、newline)。

    要不是試試下面這個代碼片段:

    $ old_IFS=$IFS $ read A ;a;b;c $ echo $A ;a;b;c $ IFS=";" #Note2 $ echo $A a b c

    Note:

    要關閉;可用";"或者';'或者\;。

    • http://bbs.chinaunix.net/forum/viewtopic.php?t=216729

    思考問題二:文本處理:讀文件時,如何保證原汁原味。

    cat file | while read i doecho $i done

    文件file的行中包含若干空,經過read只保留不重復的空格。 如何才能所見即所得。

    cat file | while read i doecho "X${i}X" done

    從上面的輸出,可以看出read,讀入是按整行讀入的; 不能原汁原味的原因:

  • 如果行的起始部分有IFS之類的字符,將被忽略;
  • echo $i的解析過程中,首先將$i替換為字符串, 然后對echo 字符串中字符串分詞,然后命令重組,輸出結果; 在分詞,與命令重組時,可能導致多個相鄰的IFS轉化為一個;
  • cat file | while read i doecho "$i" done

    以上代碼可以解決原因2中的,command line的分詞和重組導致meta字符丟失; 但仍然解決不了原因1中,read讀取行時,忽略行起始的IFS meta字符。

    回過頭來看上面這個問題:為何要原汁原味呢? cat命令就是原汁原味的,只是shell的read、echo導致了某些shell的meta字符丟失;

    如果只是IFS meta的丟失,可以采用如下方式: 將IFS設置為null,即IFS=;, 在此再次重申此處;是shell的meta字符,而不是literal字符; 因此要使用literal的 ;應該是\; 或者關閉meta 的(soft/hard) quoting的";"或者';'。

    因此上述的解決方案是:

    old_IFS=$IFS IFS=; #將IFS設置為null cat file | while read i doecho "$i" done IFS=old_IFS #恢復IFS的原始值

    現在,回過頭來看這個問題,為什么會有這個問題呢; 其本源的問題應該是沒有找到解決原始問題的最合適的方法, 而是采取了一個迂回的方式來解決了問題;

    因此,我們應該回到問題的本源,重新審視一下,問題的本質。 如果要精準的獲取文件的內容,應該使用od或者hexdump會更好些。

    ##shell十三問之5:問var=value 在export前后的差在哪?

    這次讓我們暫時丟開command line, 先了解一下bash變量(variable)吧...

    所謂的變量,就是利用一個固定的"名稱"(name), 來存取一段可以變化的"值"(value)。

    ###1. 變量設定(set) 在bash中, 你可以用"="來設定或者重新定義變量的內容:

    name=value

    在設定變量的時候,得遵守如下規則:

    • 等號左右兩邊不能使用分隔符號(IFS),也應避免使用shell的保留元字符(meta charactor);
    • 變量的名稱(name)不能使用$符號;
    • 變量的名稱(name)的首字符不能是數字(number)。
    • 變量的名稱(name)的長度不可超過256個字符。
    • 變量的名稱(name)及變量的值的大小寫是有區別的、敏感的(case sensitive,)

    如下是一些變量設定時常見的錯誤:

    A= B #=號前后不能有IFS 1A=B #變量名稱不能以數字開頭 $A=B #變量的名稱里有$ a=B #這跟a=b是不同的,(這不是錯誤,提醒windows用戶)

    如下則是可以接受的設定:

    A=" B" #IFS被關閉,參考前面的quoting章節 A1=B #并非以數字開頭 A=$B #$可用在變量的值內 This_Is_A_Long_Name=b #可用_連接較長的名稱或值,且有大小區別;

    ###2. 變量替換(substitution) shell 之所以強大,其中的一個因素是它可以在命令行中對變量作 替換(substitution)處理。 在命令行中使用者可以使用$符號加上變量名稱(除了用=定義變量名稱之外), 將變量值給替換出來,然后再重新組建命令行。

    比方:

    $ A=ls $ B=la $ C=/tmp $ $A -$B $C

    以上命令行的第一個$是shell prompt, 并不在命令行之內。 必須強調的是,我們所提的變量替換,只發生在command line上面。 (是的,請讓我們再次回到命令行吧!) 仔細分析,最后那行 command line,不難發現在被執行前(在輸入CR字符之前), $符號對每一個變量作替換處理(將變量的值替換出來再重組命令行), 最后會得出如下命令行:

    ls -la /tmp

    還記得第二章,我請大家"務必理解"的那兩句嗎? 若你忘了,我這里重貼一遍:

    Note:

    若從技術的細節來看,shell會依據IFS(Internal Field Seperator) 將command line所輸入的文字拆解為"字段"(word/field)。 然后再針對特殊字符(meta)先作處理,最后重組整行command line。

    這里的$就是command line中最經典的meta之一了, 就是作變量替換的。在日常的shell操作中, 我們常會使用echo命令來查看特定的變量的值, 例如:

    $ echo $A -$B $C

    我們已學過,echo命令只單純將其argument送至"標準輸出"(stdout, 通常是我們的屏幕)。 所以上面的命令會在屏幕上得到如下結果:

    ls -al /tmp

    這是由于echo命令在執行時,會先將$A (ls)、$B (la)跟$C (/tmp)給替換出來; 利用shell對變量的替換處理能力,我們在設定變量時就更為靈活了:

    A=B B=$A

    這樣,B的變量值就可繼承A變量"當時"的變量值了。 不過,不要以"數學邏輯"來套用變量的設定,比方說:

    A=B B=C

    這樣,并不會讓A的變量值變成C。再如:

    A=B B=$A A=C

    同樣也不會讓B的值變成C。

    上面是單純定義了兩個不同名稱的變量: A 與 B, 它們的取值分別是C與B。

    若變量被重復定義的話,則原有值為新值所取代。(這不正是"可變的量"嗎?^_^) 當我們在設定變量的時候,請記住這點:用一個名稱存儲一個數值, 僅此而已。

    此外, 我們也可以利用命令行的變量替換能力來"擴充"(append)變量的值:

    A=B:C:D A=$A:E

    這樣, 第一行我們設定A的值為"B:C:D", 然后,第二行再將值擴充為"B:C:D:E"。

    上面的擴充的范例,我們使用分隔符號(:)來達到擴充的目的, 要是沒有分隔符的話,如下是有問題的:

    A=BCD B=$AE

    因為第二次是將A的值繼承$AE的替換結果,而非$A再加E。 要解決此問題,我們可用更嚴謹的替換處理:

    A=BCD A=${A}E

    上例中,我們使用{}將變量名稱范圍給明確定義出來, 如此一來, 我們就可以將A的變量值從BCD給擴充為BCDE。

    Tips: 關于${name}事實上還可以做到更多的變量處理能力, 這些均屬于比較進階階段的變量處理,現階段暫不介紹了, 請大家自行參考資料。

    ###3. export 變量

    嚴格來說,我們在當前shell中所定義的變量,均屬于 "本地變量"(local variable), 只有經過export命令的 "輸出"處理,才能成為"環境變量"(environment variable):

    $ A=B $ export A

    或者

    $ export A=B

    經過export輸出處理之后,變量A就能成為一個環境變量 供其后的命令使用。在使用export的時候,請別忘記 shell在命令行對變量的"替換"(substitution)處理。 比方說:

    $ A=B $ B=C $ export $A

    上面的命令并未將A輸出為"環境變量",而是將B導出 這是因為在這個命令行中,$A會首先被替換為B,然后在"塞回" 作export的參數。

    要理解這個export,事實上需要從process(進程)的角度來理解才能透徹。 我們將于下一章為大家說明process(進程)的概念,敬請留意。

    ####4. 取消變量(unset) 要取消一個變量,在bash中可使用unset命令來處理:

    unset A

    與export一樣,unset命令行,也同樣會作 變量替換(這其實是shell的功能之一), 因此:

    $ A=B $ B=C $ unset $A

    事實上,所取消的是變量B而不是A。

    此外,變量一旦經過unset取消之后, 其結果是將整個變量拿掉,而不是取消變量的值。

    如下兩行其實是很不一樣的:

    $ A= $ unset A

    第一行只是將變量A設定為"空值"(null value), 但第二行則是讓變量A不存在。 雖然用眼睛來看, 這兩種變量的狀態在如下的命令結果中都是一樣的:

    $ A= $ echo $A$ unset A $ echo $A

    請學員務必能識別null value 與 unset的本質區別, 這在一些進階的變量處理上是很嚴格的。

    比方說:

    $ str= #設為null $ var=${str=expr} #定義var $ echo $var$ echo $str$ unset str #取消str $ var=${str=expr} #定義var $ echo $var expr $ echo $str expr

    聰明的讀者(yes, you!),稍加思考的話, 應該不難發現為何同樣的var=${str=expr} 在str為null與unset之下的不同吧? 若你看不出來,那可能是如下原因之一:

    • 你太笨了
    • 不了解 var=${str=expr} 這個進階處理
    • 對本篇說明還沒有來得及消化吸收
    • 我講得不好

    不知,您選哪個呢?...... ^_^.

    ##shell十三問之6:exec跟source差在哪?

    這次讓我們從CU shell版的一個實例帖子來談起吧: (論壇改版后,原鏈接已經失效)

    例中的提問原文如下:

    帖子提問:

    cd /etc/aa/bb/cc可以執行 但是把這條命令放入shell腳本后,shell腳本不執行! 這是什么原因?

    意思是:運行shell腳本,并沒有移動到/etc/aa/bb/cc目錄。

    我當時如何回答暫時別去深究,先讓我們了解一下進程 (process)的概念好了。

    首先,我們所執行的任何程序,都是父進程(parent process)產生的一個 子進程(child process),子進程在結束后,將返回到父進程去。 此現象在Linux中被稱為fork。

    (為何要稱為fork呢? 嗯,畫一下圖或許比較好理解...^_^)

    當子進程被產生的時候,將會從父進程那里獲得一定的資源分配、及 (更重要的是)繼承父進程的環境。

    讓我們回到上一章所談到的"環境變量"吧: 所謂環境變量其實就是那些會傳給子進程的變量。 簡單而言, "遺傳性"就是區分本地變量與環境變量的決定性指標。 然而,從遺傳的角度來看,我們不難發現環境變量的另一個重要特征: 環境變量只能從父進程到子進程單向傳遞。 換句話說:在子進程中環境如何變更,均不會影響父進程的環境。

    接下來,在讓我們了解一下shell腳本(shell script)的概念. 所謂shell script 講起來很簡單,就是將你平時在shell prompt輸入的多行 command line, 依序輸入到一個文件文件而已。

    再結合以上兩個概念(process + script),那應該不難理解如下的這句話的意思了: 正常來說,當我們執行一個shell script時,其實是先產生一個sub-shell的子進程, 然后sub-shell再去產生命令行的子進程。 然則,那讓我們回到本章開始時,所提到的例子在重新思考:

    帖子提問:

    cd /etc/aa/bb/cc可以執行 但是把這條命令放入shell腳本后,shell腳本不執行! 這是什么原因?

    意思是:運行shell腳本,并沒有移動到/etc/aa/bb/cc目錄。

    我當時的答案是這樣的:

    因為,我們一般跑的shell script是用sub-shell去執行的。 從process的概念來看,是 parent process產生一個child process去執行, 當child結束后,返回parent, 但parent的環境是不會因child的改變而改變的。 所謂的環境變量元數很多,如effective id(euid),variable, working dir等等... 其中的working dir($PWD) 正是樓主的疑問所在: 當用sub-shell來跑script的話,sub-shell的$pwd會因為cd而變更, 但返回primary shell時,$PWD是不會變更的。

    能夠了解問題的原因及其原理是很好的,但是? 如何解決問題,恐怕是我們更應該感興趣的是吧?

    那好,接下來,再讓我們了解一下source命令好了。 當你有了fork的概念之后,要理解soruce就不難:

    所謂source,就是讓script在當前shell內執行、 而不是產生一個sub-shell來執行。 由于所有執行結果均在當前shell內執行、而不是產生一個sub-shell來執行。

    因此, 只要我們原本單獨輸入的script命令行,變成source命令的參數, 就可輕而易舉地解決前面提到的問題了。

    比方說,原本我們是如此執行script的:

    $ ./my_script.sh

    現在改成這樣既可:

    $ source ./my_script.sh

    或者:

    $ . ./my_script.sh

    說到這里,我想,各位有興趣看看/etc底下的眾多設定的文件, 應該不難理解它們被定義后,如何讓其他script讀取并繼承了吧?

    若然,日后,你有機會寫自己的script, 應也不難專門指定一個設定的文件以供不同的script一起"共用"了... ^_^

    okay,到這里,若你搞懂fork與source的不同, 那接下來再接受一個挑戰:

    那exec又與source/fork有何不同呢?

    哦...要了解exec或許較為復雜,尤其是扯上File Decscriptor的話... 不過,簡單來說:

    exec 也是讓script在同一個進程上執行,但是原有進程則被結束了。 簡言之,原有進程能否終止,就是exec與source/fork的最大差異了。

    嗯,光是從理論去理解,或許沒那么好消化, 不如動手"實踐+思考"來得印象深刻哦。

    下面讓我們為兩個簡單的script,分別命名為1.sh以及2.sh

    1.sh

    #!/bin/bash A=B echo "PID for 1.sh before exec/source/fork:$$"export A echo "1.sh: \$A is $A"case $1 inexec)echo "using exec..."exec ./2.sh ;;source)echo "using source...". ./2.sh ;;*)echo "using fork by default..."./2.sh ;; esacecho "PID for 1.sh after exec/source/fork:$$" echo "1.sh: \$A is $A"

    2.sh

    #!/bin/bashecho "PID for 2.sh: $$" echo "2.sh get \$A=$A from 1.sh"A=C export A echo "2.sh: \$A is $A"

    然后分別跑如下參數來觀察結果:

    $ ./1.sh fork $ ./1.sh source $ ./1.sh exec

    好了,別忘了仔細比較輸出結果的不同及背后的原因哦... 若有疑問,歡迎提出來一起討論討論~~~~

    happy scripting! ^_^

    ##shell十三問之7:()與{}差在哪?

    嗯,這次輕松一下,不講太多... ^_^

    先說一下,為何要用()或者{}好了。

    許多時候,我們在shell操作上,需要在 一定的條件下執行多個命令,也就是說, 要么不執行,要么就全執行,而不是每次 依序的判斷是否要執行下一個命令。

    或者,要從一些命令執行的先后次序中得到結果, 如算術運算的2*(3+4)那樣...

    這時候,我們就可以引入"命令群組"(command group) 的概念:將許多命令集中處理。

    在shell command line中,一般人或許不太計較()與 {}這兩對符號的差異,雖然兩者都可以將多個命令當作群組處理, 但若從技術細節上,卻是很不一樣的:

    • () 將command group置于sub-shell(子shell)中去執行,也稱 nested sub-shell。
    • {} 則是在同一個shell內完成,也稱non-named command group。

    若你對上一章的fork與source的概念還記得的話, 那就不難理解兩者的差異了。

    要是在 command group中扯上變量及其他環境的修改, 我們可以根據不同的需求來使用()或{}。 通常而言, 若所作的修改是臨時的,且不想影響原有或以后的設定, 那我們就使用nested sub-shell, 即(); 反之,則用non-named command group, 即{}。

    是的,光從command line來看,() 與 {}差別就講完了,夠輕松吧~~~, ^_^

    然而,這兩個meta用在其他command meta或領域中(如Regular Expression), 還是有很多差別的。 只是,我不打算再去說明了,留給讀者慢慢發掘好了...

    我這里只想補充一個概念,就是function。 所謂function,就是用一個名字去命名一個command group, 然后再調用這個名字去執行command group。

    從non-named command group來推斷, 大概你也可以推測到我要說的是{}了吧?(yes! 你真聰明 ^_^)

    在bash中,function的定義方式有兩種:

    • 方式一:
    function function_name {command1command2command3..... }
    • 方式二:
    function_name () {command1command2command3...... }

    用哪一種方式無所謂, 只是碰到所定義的名稱與現有的命令或者別名沖突的話, 方式二或許會失敗。 但方式二起碼可以少打個function這一串英文字符, 對懶人來說(如我),有何樂而不為呢?...^_^

    function 在一定程度上來說,也可以稱為"函數", 但請不要與傳統編程所使用的"函數"(library)搞混了, 畢竟兩者差異很大。 唯一相同的是,我們都可以隨時用"已定義的名稱"來調用它們...

    若我們在shell操作中,需要不斷地重復某些命令, 我們首先想到的,或許是將命令寫成shell腳本(shell script)。 不過,我們也可以寫成function, 然后在command line中打上function_name就可當一般的shell script使用了。

    若只是你在shell中定義的function, 除了用unset function_name取消外, 一旦你退出shell, function也跟著消失。 然而,在script中使用function卻有許多好處, 除了提高整體script的執行性能外(因為已經載入), 還可以節省許多重復的代碼......

    簡單而言,若你會將多個命令寫成script以供調用的話, 那你可以將function看成script中script。... ^_^

    而且通過上一章節介紹的source命令, 我們可以自行定義許許多多好用的function, 在集中寫在特定文件中, 然后,在其他的script中用source將它們載入,并反復執行。

    若你是RedHat Linux的使用者, 或許,已經猜出 /etc/rc.d/init.d/functions這個文件時啥作用了~~~ ^_^

    okay,說要輕松點的嘛,那這次就暫時寫到這吧。 祝大家學習愉快,^_^

    ##shell十三問之8: $(())與$()還有${}差在哪?

    我們上一章介紹了()與{}的不同, 這次讓我們擴展一下,看看更多的變化: $()與${}又是啥玩意兒呢?

    在bash shell中, $()與``(反引號)都是用來做 命令替換(command substitution)的。

    所謂的命令替換與我們第五章學過的變量替換差不多, 都是用來重組命令行: 完成 `` 或者$()里面的 命令,將其結果替換出來, 再重組命令行。

    例如:

    $ echo the last sunday is $(date -d "last sunday" +%Y-%m-%d)

    如此便可方便得到上一個星期天的日期了...^_^

    在操作上, 用$()或``都無所謂, 只是我個人比較喜歡用$(),理由是:

  • ``(反引號)很容易與''(單引號)搞混亂,尤其對初學者來說。 有時在一些奇怪的字形顯示中,兩種符號是一模一樣的(只取兩點)。 當然了有經驗的朋友還是一眼就能分辨兩者。只是,若能更好的避免混亂, 又何樂而不為呢? ^_^

  • 在多次的復合替換中, ``需要額外的轉義(escape, )處理,而$()則比較直觀。 例如,一個錯誤的使用的例子:

  • command1 `command2 `command3` `

    原來的本意是要在command2 `command3` , 先將command3替換出來給command2處理, 然后再將command2的處理結果,給command1來處理。 然而真正的結果在命令行中卻是分成了`command2`與 ``。

    正確的輸入應該如下:

    command1 `command2 \`command3\` `

    要不然換成$()就沒有問題了:

    command1 $(commmand2 $(command3))

    只要你喜歡,做多少層的替換都沒有問題~~~^_^

    不過,$()并不是沒有弊端的... 首先,``基本上可用在所有的unix shell中使用, 若寫成 shell script,其移植性比較高。 而$()并不是每一種shell都能使用,我只能說, 若你用bash2的話,肯定沒問題... ^_^

    接下來,再讓我們看看${}吧...它其實就是用來做 變量替換用的啦。 一般情況下,$var與${var}并沒有啥不一樣。 但是用${}會比較精準的界定變量名稱的范圍, 比方說:

    $ A=B $ echo $AB

    原本是打算先將$A的結果替換出來, 然后在其后補一個字母B; 但命令行上, 真正的結果卻是替換變量名稱為AB的值出來... 若使用${}就沒有問題了:

    $ A=B $ echo ${A}B $ BB

    不過,假如你只看到${}只能用來界定變量名稱的話, 那你就實在太小看bash了。

    為了完整起見,我這里再用一些例子加以說明${}的一些 特異功能: 假設我們定義了一個變量file為:

    file=/dir1/dir2/dir3/my.file.txt

    我們可以用${}分別替換獲得不同的值:

    ####1. shell字符串的非貪婪(最小匹配)左刪除

    ${file#*/} #其值為:dir1/dir2/dir3/my.file.txt

    拿掉第一個/及其左邊的字符串,其結果為: dir1/dir2/dir3/my.file.txt 。

    ${file#*.} #其值為:file.txt

    拿掉第一個.及其左邊的字符串,其結果為: file.txt 。

    ####2. shell字符串的貪婪(最大匹配)左刪除:

    ${file##*/} #其值為:my.file.txt

    拿掉最后一個/及其左邊的字符串,其結果為: my.file.txt

    ${file##*.} #其值為:txt

    拿掉最后一個.及其左邊的字符串,其結果為: txt

    ####3. shell字符串的非貪婪(最小匹配)右刪除:

    ${file%/*} #其值為:/dir1/dir2/dir3

    拿掉最后一個/及其右邊的字符串,其結果為: /dir1/dir2/dir3。

    ${file%.*} #其值為:/dir1/dir2/dir3/my.file

    拿掉最后一個.及其右邊的字符串,其結果為: /dir1/dir2/dir3/my.file。

    ####4. shell字符串的貪婪(最大匹配)右刪除:

    ${file%%/*} #其值為:其值為空。

    拿掉第一個/及其右邊的字符串,其結果為: 空串。

    ${file%%.*} #其值為:/dir1/dir2/dir3/my。

    拿掉第一個.及其右邊的字符串,其結果為: /dir1/dir2/dir3/my。

    Tips:

    記憶方法:

    #是去掉左邊(在鍵盤上#在$的左邊);

    %是去掉右邊(在鍵盤上%在$的右邊);

    單個符號是最小匹配;

    兩個符號是最大匹配;

    ####5. shell字符串取子串:

    ${file:0:5} #提取最左邊的5個字符:/dir1${file:5:5} #提取第5個字符及其右邊的5個字符:/dir2

    shell字符串取子串的格式:${s:pos:length}, 取字符串s的子串:從pos位置開始的字符(包括該字符)的長度為length的的子串; 其中pos為子串的首字符,在s中位置; length為子串的長度;

    Note: 字符串中字符的起始編號為0.

    ####6. shell字符串變量值的替換:

    ${file/dir/path} #將第一個dir替換為path:/path1/dir2/dir3/my.file.txt ${file//dir/path} #將全部的dir替換為path:/path1/path2/path3/my.file.txt

    shell字符串變量值的替換格式:

    • 首次替換: ${s/src_pattern/dst_pattern} 將字符串s中的第一個src_pattern替換為dst_pattern。

    • 全部替換: ${s//src_pattern/dst_pattern} 將字符串s中的所有出現的src_pattern替換為dst_pattern.

    ####7. ${}還可針對變量的不同狀態(沒設定、空值、非空值)進行賦值:

    • ${file-my.file.txt} #如果file沒有設定,則使用 使用my.file.txt作為返回值, 否則返回${file};(空值及非空值時,不作處理。);

    • ${file:-my.file.txt} #如果file沒有設定或者${file}為空值, 均使用my.file.txt作為其返回值,否則,返回${file}.(${file} 為非空值時,不作處理);

    • ${file+my.file.txt} #如果file已設定(為空值或非空值), 則使用my.file.txt作為其返回值,否則不作處理。(未設定時,不作處理);

    • ${file:+my.file.txt} #如果${file}為非空值, 則使用my.file.txt作為其返回值,否則,(未設定或者為空值時)不作處理。

    • ${file=my.file.txt} #如果file為設定,則將file賦值為my.file.txt,同時將${file}作為其返回值;否則,file已設定(為空值或非空值),則返回${file}。

    • ${file:=my.file.txt} #如果file未設定或者${file}為空值, 則my.file.txt作為其返回值, 同時,將${file}賦值為my.file.txt,否則,(非空值時)不作處理。

    • ${file?my.file.txt} #如果file沒有設定,則將my.file.txt輸出至STDERR, 否側, 已設定(空值與非空值時),不作處理。

    • ${file:?my.file.txt} #若果file未設定或者為空值,則將my.file.txt輸出至STDERR,否則, 非空值時,不作任何處理。

    Tips:

    以上的理解在于,你一定要分清楚,unset與null以及non-null這三種狀態的賦值; 一般而言,與null有關,若不帶:, null不受影響; 若帶 :, 則連null值也受影響。

    ####8. 計算shell字符串變量的長度:${#var}

    ${#file} #其值為27, 因為/dir1/dir2/dir3/my.file.txt剛好為27個字符。

    ####9. bash數組(array)的處理方法

    接下來,為大家介紹一下bash的數組(array)的處理方法。 一般而言, A="a b c def" 這樣的變量只是將$A替換為一個字符串, 但是改為 A=(a b c def), 則是將$A定義為數組....

    #####1). 數組替換方法可參考如下方法:

    ${A[@]} #方法一 ${A[*]} #方法二

    以上兩種方法均可以得到:a b c def, 即數組的全部元素。

    #####2). 訪問數組的成員:

    ${A[0]}

    其中,${A[0]}可得到a, 即數組A的第一個元素, 而 ${A[1]}則為數組A的第二元素,依次類推。

    #####3). 數組的length:

    ${#A[@]} #方法一 ${#A[*]} #方法二 ``` 以上兩種方法均可以得到數組的長度: 4, 即數組的所有元素的個數。回憶一下,針對字符串的長度計算,使用`${#str_var}`; 我們同樣可以將該方法應用于數組的成員: ```shell ${#A[0]}

    其中,${#A[0]}可以得到:1,即數組A的第一個元素(a)的長度; 同理,${#A[3]}可以得到: 3, 即數組A的第4個元素(def)的長度。

    #####4). 數組元素的重新賦值:

    A[3]=xyz

    將數組A的第四個元素重新定義為xyz。

    Tips:

    諸如此類的...

    能夠善用bash的$()與${}可以大大提高及 簡化shell在變量上的處理能力哦~~~^_^

    ####10. $(())作用:

    好了,最后為大家介紹$(())的用途吧: $(())是用來作整數運算的

    在bash中, $(())的整數運算符號大致有這些:

    • +- * / #分別為"加、減、乘、除"。
    • % #余數運算,(模數運算)
    • & | ^ ! #分別為"AND、OR、XOR、NOT"運算。

    例如:

    $ a=5; b=7; c=2; $ echo $(( a + b * c )) 19 $ echo $(( (a + b)/c )) 6 $ echo $(( (a * b) % c )) 1

    在$(())中的變量名稱, 可以在其前面加 $符號來替換, 也可以不用,如: $(( $a + $b * $c )) 也可以得到19的結果。

    此外,$(())還可作不同進制(如二進制、八進制、十六進制)的運算, 只是輸出結果均為十進制的。

    echo $(( 16#2a )) #輸出結果為:42,(16進制的2a)

    以一個實用的例子來看看吧 : 假如當前的umask是022,那么新建文件的權限即為:

    $ umask 022 $ echo "obase=8; $(( 8#666 & (8#777 ^ 8#$(umask)) ))" | bc 644

    事實上,單純用(())也可以重定義變量值,或作testing:

    a=5; ((a++)) #可將$a 重定義為6 a=5; ((a--)) #可將$a 重定義為4 a=5; b=7; ((a< b)) #會得到0 (true)返回值。

    常見的用于(())的測試符號有如下這些:

    符號符號名稱
    <小于號
    >大于號
    <=小于或等于
    >=大于或等于
    ==等于
    !=不等于

    Note:

    使用(())作整數測試時, 請不要跟[]的整數測試搞混亂了。

    更多的測試,我們將于第10章為大家介紹。

    怎樣? 好玩吧... ^_^

    okay,這次暫時說這么多...

    上面的介紹,并沒有詳列每一種可用的狀態, 更多的,就請讀者參考手冊文件(man)吧...

    ##shell十三問之9:$@與$*差在哪?

    要說$@與$*之前, 需得先從shell script的positional parameter談起...

    我們都已經知道變量(variable)是如何定義和替換的, 這個不再多講了。

    1. shell script的positional parameter


    但是,我們還需要知道有些變量是shell內定的, 且其名稱是我們不能隨意修改的。 其中,就有positional parameter在內。

    在shell script中,我們可用$0, $1, $2, $3 ... 這樣的變量分別提取命令行中的如下部分:

    script_name parameter1 parameter2 parameter3 ...

    我們很容易就能猜出, $0就是代表 shell script名稱(路徑)本身, 而$1就是其后的第一個參數,如此類推...

    須得留意的是IFS的作用, 也就是IFS被quoting處理后, 那么positional parameter也會改變。

    如下例:

    my.sh p1 "p2 p3" p4

    由于p2與p3之間的空白鍵被soft quoting所關閉了, 因此,my.sh的中$2是"p2 p3",而$3則是p4...

    還記得前兩章,我們提到function時, 我們不是說過,它是script中的script嗎?^_^

    是的,function一樣可以讀取自己的(有別于script的) positional parameter, 唯一例外的是$0而已。

    舉例而言: 假設my.sh里有一個函數(function)叫my_fun, 若在script中跑my_fun fp1 fp2 fp3, 那么,function內的$0就是my.sh,而$1是fp1而不是p1了...

    不如寫個簡單的my.sh script 看看吧:

    #!/bin/bashmy_fun() {echo '$0 inside function is '$0echo '$1 inside function is '$1echo '$2 inside function is '$2 }echo '$0 outside function is '$0 echo '$1 outside function is '$1 echo '$2 outside function is '$2my_fun fp1 "fp2 fp3"

    然后在command line中跑一下 script就知道了:

    chmod 755 my.sh./my.sh p1 "p2 p3" $0 outside function is ./my.sh $1 outside function is p1 $2 outside function is p2 p3 $0 inside function is ./my.sh $1 inside function is fp1 $2 inside function is fp2 fp3

    然而,在使用positional parameter的時候, 我們要注意一些陷阱哦:

    $10不是替換第10個參數, 而是替換第一個參數,然后在補一個0于其后;

    也就是說, my.sh one two three four five six seven eight nine ten 這樣的command line, my.sh里的$10不是ten而是one0 哦...小心小心 要抓到ten的話,有兩種方法:

    • 方法一:使用我們上一章介紹的${}, 也就是用${10}即可。

    • 方法二:就是shift了。

    用通俗的說法來說, 所謂的shift就是取消positional parameter中最左邊的參數($0不受影響)。 其預設值為1,也就是shift 或shift 1 都是取消$1, 而原本的$2則變成$1, $3則變成$2... 那親愛的讀者,你說要shift掉多少個參數, 才可用$1取得到${10} 呢? ^_^

    okay,當我們對positional parameter有了基本的概念之后, 那再讓我們看看其他相關變量吧。

    2. shell script的positional parameter的number


    先是$#, 它可抓出positional parameter的數量。 以前面的my.sh p1 "p2 p3"為例: 由于"p2 p3"之間的IFS是在soft quote中, 因此,$#就可得到的值是2. 但如果p2與p3沒有置于quoting中話, 那$#就可得到3的值了。 同樣的規則,在function中也是一樣。

    因此,我們常在shell script里用如下方法, 測試script是否有讀進參數:

    [ $# = 0 ]

    假如為0, 那就表示script沒有參數,否則就是帶有參數...

    3. shell script中的$@與$*


    接下來就是**$@與$*: 精確來講,兩者只有在soft quote中才有差異, 否則,都表示“全部參數” ($0除外)**。

    若在comamnd line上, 跑my.sh p1 "p2 p3" p4的話, 不管$@還是$*, 都可得到 p1 p2 p3 p4就是了。

    但是,如果置于soft quote中的話:

    • "$@"則可得到 "p1" "p2 p3" "p4" 這三個不同字段(word);
    • "$*"則可得到 "p1 p2 p3 p4" 這一整個單一的字段。

    我們修改一下前面的my.sh,使之內容如下:

    #!/bin/bashmy_fun() {echo "$#" }echo 'the number of parameter in "$@" is ' $(my_fun "$@") echo 'the number of parameter in "$*" is ' $(my_fun "$*")

    然后再執行:

    ./my.sh p1 "p2 p3" p4

    就知道,$@與$*差在哪了... ^_^

    ##shell十三問之10:&& 與 || 差在哪?

    好不容易,進入了兩位數的章節了... 一路走來,很辛苦吧?也很快樂吧? ^_^

    在解答本章題目之前,先讓我們了解一個概念: return value。

    我們在shell下跑的每一個command或function, 在結束的時候都會傳回父進程一個值,稱為 return value。

    在shell command line中可用$?, 這個變量得到最"新"的一個return value, 也就是剛剛結束的那個進程傳回的值。

    Return Value(RV)的取值為0-255之間, 由進程或者script的作者自行定義:

    • 若在script里,用exit RV 來指定其值; 若沒有指定, 在結束時,以最后一個命令的RV,為script的RV值。

    • 若在function里,則用return RV 來代替exit RV即可。

    Return Value的作用:用來判斷進程的退出狀態(exit status). 進程的退出狀態有兩種:

    • 0值為"真"(true)
    • 非0值為"假"(false)

    舉個例子來說明好了: 假設當前目錄內有一個my.file的文件, 而no.file是不存在的:

    $ touch my.file $ ls my.file $ echo $? #first echo 0 $ ls no.file ls: no.file: No such file or directory $ echo $? #second echo 1 $ echo $? #third echo 0

    上例的:

    • 第一個echo是關于ls my.file的RV,可得到0的值,因此為true。
    • 第二個echo是關于ls no.file的RV,得到非0的值,因此為false。
    • 第三個echo是關于echo $?的RV,得到0值, 因此為true。

    請記住: 每一個command在結束時,都會返回return value,不管你跑什么命令... 然而,有一個命令卻是“專門”用來測試某一條而返回return value, 以供true或false的判斷, 它就是test命令。

    若你用的是bash, 請在command line下, 打man test,或者 man bash 來了解這個test的用法。 這是你可用作參考的最精準的文件了,要是聽別人說的,僅作參考就好...

    下面,我只簡單作一些輔助說明,其余的一律以 man為準: 首先,test的表達式,我們稱為expression,其命令格式有兩種:

    test expression

    或者

    [ expression ]

    Note:

    請務必注意 [] 之間的空白鍵!

    用哪一種格式無所謂,都是一樣的效果。 (我個人比較喜歡后者...)

    其次,bash的test目前支持的測試對象只有三種:

    • string:字符串,也就是純文字。
    • integer:整數(0或正整數、不含負數或小數)
    • file: 文件

    請初學者,一定要搞清楚這三者的差異, 因為test所使用的expression是不一樣的。

    以A=123這個變量為例:

    • [ "$A" = 123 ] #是字符串測試,測試$A是不是1、2、3這三個字符。

    • [ "$A" -eq 123 ] #是整數測試,以測試$A是否等于123.

    • [-e "$A" ] #文件測試,測試123這份文件是否存在.

    第三, 當expression測試為“真”時, test就返回0(true)的return value; 否則,返回非0(false).

    若在 expression 之前加一個!(感嘆號),則在expression為假時,return value為0, 否則, return value 為非0值。

    同時,test也允許多重復合測試:

    • expression1 -a expression2 #當兩個expression都為true,返回0,否則,返回非0;
    • expression1 -o expression2 #當兩個expression均為false時,返回非0,否則,返回0;

    例如:

    [ -d "$file" -a -x "$file" ]

    表示當$file是一個目錄,且同時具有x權限時,test才會為true。

    第四,在command line中使用test時,請別忘記命令行的“重組”特性, 也就是在碰到meta時,會先處理meta,在重新組建命令行。 (這個概念在第2章和第4章進行了反復強調)

    比方說, 若test碰到變量或者命令替換時, 若不能滿足 expression的格式時,將會得到語法錯誤的結果。

    舉例來說好了:

    關于[ string1 = string2 ]這個test格式, 在等號兩邊必須要有字符串,其中包括空串(null串,可用soft quote或者hard quote取得)。

    假如$A目前沒有定義,或被定義為空字符串的話, 那如下的用法將會失敗:

    $ unset A $ [ $A = abc ] [: =: unary oprator expected

    這是因為命令行碰到$這個meta時,會替換$A的值, 然后,再重組命令行,那就變成了: [ = abc ], 如此一來,=的左邊就沒有字符串存在了, 因此,造成test的語法錯誤。 但是,下面這個寫法則是成立的。

    $ [ "$A" = abc ] $ echo $? 1

    這是因為命令行重組后的結果為: [ "" = abc ], 由于等號的左邊我們用soft quote得到一個空串, 而讓test的語法得以通過...

    讀者諸君,請務必留意這些細節哦, 因為稍一不慎,將會導致test的結果變了個樣。 若您對test還不是很有經驗的話, 那在使用test時,不妨先采用如下這一個"法則":

    ** 若在test中碰到變量替換,用soft quote是最保險的***。

    若你對quoting不熟的話,請重新溫習第四章的內容吧...^_^

    okay, 關于更多的test的用法,老話一句:請看其man page (man test)吧!^_^

    雖然洋洋灑灑讀了一大堆,或許你還在嘀咕...那...那個return value有啥用?

    問得好: 告訴你:return value的作用可大了, 若你想要你的shell變"聰明"的話,就全靠它了: 有了return value, 我們可以讓shell根據不同的狀態做不同的事情...

    這時候,才讓我來揭曉本章的答案吧~~~~^_^

    && 與 || 都是用來"組建" 多個command line用的;

    • command1 && command2 # command2只有在command1的RV為0(true)的條件下執行。
    • command1 || command2 # command2 只有在command1的RV為非0(false)的條件下執行。

    以例子來說好了:

    $ A=123 $ [ -n "$A" ] && echo "yes! it's true." yes! it's true. $ unset A $ [ -n "$A" ] && echo "yes! it's true." $ [ -n "$A" ] || echo "no, it's Not true." no, it's Not true

    Note:

    [ -n string ]是測試string長度大于0, 則為true。

    上例中,第一個&&命令之所以會執行其右邊的echo命令, 是因為上一個test返回了0的RV值; 但第二個,就不會執行,因為test返回了非0的結果... 同理,||右邊的echo會被執行,卻正是因為左邊的test返回非0所引起的。

    事實上,我們在同一個命令行中,可用多個&& 或 || 來組建呢。

    $ A=123 $ [ -n "$A" ] && echo "yes! it's true." || echo "no, it's Not ture." yes! it's true. $ unset A $ [ -n "$A" ] && echo "yes! it's true." || echo "no, it's Not ture." no, it's Not true

    怎樣,從這一刻開始,你是否覺得我們的shell是“很聰明”的呢? ^_^

    好了,最后布置一道練習題給大家做做看: 下面的判斷是:當$A被賦值時,在看看其是否小于100,否則輸出too big!

    $ A=123 $ [ -n "$A" ] && [ "$A" -lt 100 ] || echo 'too big!' $ too big!

    若我取消A,照理說,應該不會輸出文字啊,(因為第一個條件不成立)。

    $ unset A $ [ -n "$A" ] && [ "$A" -lt 100 ] || echo 'too big!' $ too big!

    為何上面的結果也可得到呢? 又如何解決呢?

    Tips:

    修改的方法有很多種, 其中一種方法可以利用第7章中介紹過 command group...

    快告訴我答案,其余免談....

    解決方法1:sub-shell:

    $ unset A $ [ -n "$A" ] && ( [ "$A" -lt 100 ] || echo 'too big!' )

    解決方法二:command group:

    $ unset A $ [ -n "$A" ] && { [ "$A" -lt 100 ] || echo 'too big!'}

    ##shell十三問之11:>與< 差在哪?

    這次的題目,之前我在CU的shell版說明過了: (原帖的連接在論壇改版后,已經失效) 這次我就不重寫了,將帖子的內容“抄”下來就是了...

    1. 文件描述符(fd, File Descriptor)


    談到I/O redirection,不妨先讓我們認識一下File Descriptor(fd,文件描述符)。

    進程的運算,在大部分情況下,都是進行數據(data)的處理, 這些數據從哪里,讀進來?又輸出到哪里呢? 這就是file descriptor(fd)的功用了。

    在shell的進程中,最常使用的fd大概有三個,分別為:

    • 0:standard Input (STDIN)
    • 1: standard output(STDOUT)
    • 2: standard Error output (STDERR)

    在標準情況下,這些fd分別跟如下設備(device)關聯:

    • stdin(0): keyboard
    • stdout(1): monitor
    • stderr(2): monitor

    Tips: linux中的文件描述符(fd)用整數表示。 linux中任何一個進程都默認打開三個文件, 這三個文件對應的文件描述符分別是:0, 1, 2; 即stdin, stdout, stderr.

    我們可以用如下命令測試一下:

    $ mail -s test root this is a test mail。 please skip. ^d (同時按下ctrl 跟d鍵)

    很明顯,mail進程所讀進的數據,就是從 stdin 也就是keyboard讀進的。 不過,不見得每個進程的stdin都跟mail一樣 從keyboard讀進,因為進程的作者可以從文件參數讀進stdin, 如:

    $ cat /etc/passwd

    但,要是cat之后沒有文件參數則如何呢? 哦, 請你自己玩玩看...^_^

    $ cat

    Tips:

    請留意數據輸出到哪里去了, 最后別忘了按ctrl+d(^d), 退出stdin輸入。

    至于stdout與stderr,嗯...等我有空再續吧...^_^ 還是,有哪位前輩來玩接龍呢?

    相信,經過上一個練習后, 你對stdin與stdout應該不難理解了吧? 然后,讓我們看看stderr好了。

    事實上,stderr沒什么難理解的: 說白了就是“錯誤信息”要往哪里輸出而已... 比方說, 若讀進的文件參數不存在的, 那我們在monitor上就看到了:

    $ ls no.such.file ls: no.such.file: No such file or directory

    若同一個命令,同時成生stdout與stderr呢? 那還不簡單,都送到monitor來就好了:

    $ touch my.file $ ls my.file on.such.file ls: no.such.file: No such file or directory my.file

    okay, 至此,關于fd及其名稱、還有相關聯的設備, 相信你已經沒問題了吧?


    2. I/O 重定向(I/O Redirection)


    那好,接下來讓我們看看如何改變這些fd的預設數據通道。

    • 用< 來改變讀進的數據通道(stdin),使之從指定的文件讀進。
    • 用> 來改變輸出的數據通道(stdout,stderr),使之輸出到指定的文件。

    #####2.1 輸入重定向n<(input redirection)

    比方說:

    $ cat < my.file

    就是從my.file讀入數據

    $ mail -s test root < /etc/passwd

    則是從/etc/passwd讀入...

    這樣一來,stdin將不再是從keyboard讀入, 而是從指定的文件讀入了...

    嚴格來說,<符號之前需要指定一個fd的(之前不能有空白),但因為0是<的預設值,因此,<與0<是一樣的*。

    okay,這樣好理解了吧?

    那要是用兩個<,即<<又是啥呢? 這是所謂的here document, 它可以讓我們輸入一段文本, 直到讀到<< 后指定的字符串

    比方說:

    $ cat <<EOF first line here second line here third line here EOF

    這樣的話, cat會讀入3個句子, 而無需從keyboard讀進數據且要等到(ctrl+d, ^d)結束輸入。


    #####2.2 重定向輸出>n(output redirection)

    當你搞懂了0< 原來就是改變stdin的數據輸入通道之后, 相信要理解如下兩個redirection就不難了:

    • 1> #改變stdout的輸出通道;
    • 2> #改變stderr的輸出通道;

    兩者都是將原來輸出到monitor的數據, 重定向輸出到指定的文件了。

    由于1是>的預設值, 因此,1>與>是相同的,都是改變stdout.

    用上次的ls的例子說明一下好了:

    $ ls my.file no.such.file 1>file.out ls: no.such.file: No such file or directory

    這樣monitor的輸出就只剩下stderr的輸出了, 因為stdout重定向輸出到文件file.out去了。

    $ ls my.file no.such.file 2>file.err my.file

    這樣monitor就只剩下了stdout, 因為stderr重定向輸出到文件file.err了。

    $ ls my.file no.such.file 1>file.out 2>file.err

    這樣monitor就啥也沒有了, 因為stdout與stderr都重定向輸出到文件了。

    呵呵,看來要理解>一點也不難啦是不? 沒騙你吧? ^_^ 不過有些地方還是要注意一下的

    $ ls my.file no.such.file 1>file.both 2>file.both

    假如stdout(1)與stderr(2)都同時在寫入file.both的話, 則是采取"覆蓋"的方式:后來寫入覆蓋前面的。

    讓我們假設一個stdout與stderr同時寫入到file.out的情形好了;

    • 首先stdout寫入10個字符
    • 然后stderr寫入6個字符

    那么,這時原本的stdout輸出的10個字符, 將被stderr輸出的6個字符覆蓋掉了。

    那如何解決呢?所謂山不轉路轉,路不轉人轉嘛, 我們可以換一個思維: 將stderr導進stdout 或者將stdout導進到stderr, 而不是大家在搶同一份文件,不就行了。 bingo就是這樣啦:

    • 2>&1 #將stderr并進stdout輸出
    • 1>&2 或者 >&2 #將stdout并進stderr輸出。

    于是,前面的錯誤操作可以改寫為:

    $ ls my.file no.such.file 1>file.both 2>&1 $ ls my.file no.such.file 2>file.both >&2

    這樣,不就皆大歡喜了嗎? ~~~ ^_^

    不過,光解決了同時寫入的問題還不夠, 我們還有其他技巧需要了解的。 故事還沒有結束,別走開廣告后,我們在回來....


    #####2.3 I/O重定向與linux中的/dev/null

    okay,這次不講I/O Redirection, 請佛吧... (有沒有搞錯?網中人是否頭殼燒壞了?...)嘻~~~^_^

    學佛的最高境界,就是"四大皆空"。 至于是空哪四大塊,我也不知,因為我還沒有到那個境界.. 這個“空”字,卻非常值得反復把玩: ---色即是空,空即是色 好了,施主要是能夠領會"空"的禪意,那離修成正果不遠了。

    在linux的文件系統中,有個設備文件: /dev/null. 許多人都問過我,那是什么玩意兒? 我跟你說好了,那就是"空"啦。

    沒錯空空如也的空就是null了... 請問施主是否忽然有所頓悟了呢? 然則恭喜了。

    這個null在 I/O Redirection中可有用的很呢?

    • 將fd 1跟fd 2重定向到/dev/null去,就可忽略stdout, stderr的輸出。
    • 將fd 0重定向到/dev/null,那就是讀進空(nothing).

    比方說,我們在執行一個進程時,會同時輸出到stdout與stderr, 假如你不想看到stderr(也不想存到文件), 那就可以:

    $ ls my.file no.such.file 2>/dev/null my.file

    若要相反:只想看到stderr呢? 還不簡單將stdout,重定向的/dev/null就行:

    $ ls my.file no.such.file >/dev/null ls: no.such.file: No such file or directory

    那接下來,假如單純的只跑進程,而不想看到任何輸出呢? 哦,這里留了一手,上次沒講的法子,專門贈與有緣人... ^_^ 除了用 >/dev/null 2>&1之外,你還可以如此:

    $ ls my.file no.such.file &>/dev/null

    Tips:

    將&>換成>&也行!


    #####2.4 重定向輸出append (>>)

    okay? 請完佛,接下來,再讓我們看看如下情況:

    $ echo "1" > file.out $ cat file.out 1 $ echo "2" > file.out $ cat file.out 2

    看來,我們在重定向stdout或stderr進一個文件時, 似乎永遠只能獲得最后一次的重定向的結果. 那之前的內容呢?

    呵呵,要解決這個問題,很簡單啦,將>換成>> 就好了;

    $ echo "3" >> file.out $ cat file.out 2 3

    如此一來,被重定向的文件的之前的內容并不會丟失, 而新的內容則一直追加在最后面去。so easy?...

    但是,只要你再次使用>來重定向輸出的話, 那么,原來文件的內容被truncated(清洗掉)。 這是,你要如何避免呢? ----備份, yes,我聽到了,不過,還有更好的嗎? 既然與施主這么有緣分,老衲就送你一個錦囊妙法吧:

    $ set -o noclobber $ echo "4" > file.out -bash:file: cannot overwrite existing file.

    那,要如何取消這個限制呢? 哦,將set -o換成 set +o就行了:

    $ set +o noclobber $ echo "5" > file.out $ cat file.out 5

    再問:那有辦法不取消而又“臨時”改寫目標文件嗎? 哦,佛曰:不可告也。 啊,~開玩笑的,開玩笑啦~^_^, 哎,早就料到人心是不足的了

    $ set -o noclobber $ echo "6" >| file.out $ cat file.out 6

    留意到沒有: 在>后面加個|就好, 注意: >與|之間不能有空白哦...


    #####2.5 I/O Redirection的優先級

    呼....(深呼吸吐納一下吧)~~~ ^_^ 再來還有一個難題要你去參透呢:

    $ echo "some text here" >file $ cat < file some text here $cat < file >file.bak $cat < file.bak some text here $cat < file >file

    嗯?注意到沒有? ---怎么最后那個cat命令看到file是空的呢? why? why? why?

    前面提到:$cat < file > file之后, 原本有內容的文件,結果卻被清空了。 要理解這個現象其實不難, 這只是priority的問題而已: ** 在IO Redirection中, stdout與stderr的管道先準備好, 才會從stdin讀入數據。** 也就是說,在上例中,>file會將file清空, 然后才讀入 < file。 但這時候文件的內容已被清空了,因此就變成了讀不進任何數據。

    哦,~原來如此~^_^ 那...如下兩例又如何呢?

    $ cat <> file $ cat < file >>file

    嗯...同學們,這兩個答案就當練習題嘍, 下課前交作業。

    Tips: 我們了解到>file能夠快速把文件file清空; 或者使用:>file同樣可以清空文件, :>file與>file的功能: 若文件file存在,則將file清空; 否則,創建空文件file (等效于touch file); 二者的差別在于>file的方式不一定在所有的shell的都可用。

    exec 5<>file; echo "abcd" >&5; cat <&5 將file文件的輸入、輸出定向到文件描述符5, 從而描述符5可以接管file的輸入輸出; 因此,cat <>file等價于cat < file。

    而cat < file >>file則使file內容成幾何級數增長。

    好了, I/O Redirection也快講完了, sorry,因為我也只知道這么多而已啦~嘻~^_^ 不過,還有一樣東東是一定要講的,各位觀眾(請自行配樂~!#@$%): 就是pipe line也。


    #####2.6 管道(pipe line)

    談到pipe line,我相信不少人都不會陌生: 我們在很多command line上常看到|符號就是pipe line了。

    不過,pipe line究竟是什么東東呢? 別急別急...先查一下英文字典,看看pipe是什么意思? 沒錯他就是“水管”的意思... 那么,你能想象一下水管是怎樣一個根接一根的嗎? 又, 每根水管之間的input跟output又如何呢? 靈光一閃:原來pipe line的I/O跟水管的I/O是一模一樣的: 上一個命令的stdout接到下一個命令的stdin去了 的確如此。不管在command line上使用了多少個pipe line, 前后兩個command的I/O是彼此連接的 (恭喜:你終于開放了 ^_^ )

    不過...然而...但是... ...stderr呢? 好問題不過也容易理解: 若水管漏水怎么辦? 也就是說:在pipe line之間, 前一個命令的stderr是不會接進下一個命令的stdin的, 其輸出,若不用2>file的話,其輸出在monitor上來。 這點請你在pipe line運用上務必要注意的。

    那,或許你有會問: 有辦法將stderr也喂進下一個命令的stdin嗎? (貪得無厭的家伙),方法當然是有的,而且,你早已學習過了。 提示一下就好:**請問你如何將stderr合并進stdout一同輸出呢? 若你答不出來,下課后再來問我...(如果你臉皮足夠厚的話...)

    或許,你仍意猶未盡,或許,你曾經碰到過下面的問題: 在cmd1 | cmd2 | cmd3 | ... 這段pipe line中如何將cmd2的輸出保存到一個文件呢?

    若你寫成cmd1 | cmd2 >file | cmd3的話, 那你肯定會發現cmd3的stdin是空的,(當然了,你都將 水管接到別的水池了) 聰明的你或許會如此解決:

    cmd1 | cmd2 >file; cmd3 < file

    是的,你可以這樣做,但最大的壞處是: file I/O會變雙倍,在command執行的整個過程中, file I/O是最常見的最大效能殺手。 凡是有經驗的shell操作者,都會盡量避免或降低file I/O的頻度。

    那上面問題還有更好的方法嗎? 有的,那就是tee命令了。 所謂的tee命令是在不影響原本I/O的情況下, 將stdout賦值到一個文件中去。 因此,上面的命令行,可以如此執行:

    cmd1 | cmd2 | tee file | cmd3

    在預設上,tee會改寫目標文件, 若你要改為追加內容的話,那可用-a參數選項。

    基本上,pipe line的應用在shell操作上是非常廣泛的。 尤其是在text filtering方面, 如,cat, more, head, tail, wc, expand, tr, grep, sed, awk...等等文字處理工具。 搭配起pipe line 來使用,你會覺得 command line 原來活得如此精彩的。 常讓人有“眾里尋他千百度,驀然回首,那人卻在燈火闌珊處”之感...

    好了,關于I/O Redirection的介紹就到此告一段落。 若日后,有空的話,在為大家介紹其他在shell上好玩的東西。

    ##shell十三問之12:你要if還是case呢?

    還記得我們在第10章所介紹的return value嗎?

    是的,接下來的介紹的內容與之有關, 若你的記憶也被假期所抵消的話, 那建議您還是回去溫習溫習再回來...

    若你記得return value,我想你也應該記得了 && 與 || 什么意思吧? 用這兩個符號再搭配 command group的話, 我們可讓shell script變得更加聰明哦。 比方說:

    cmd1 && {cmd2cmd3; } || {cmd4cmd5 }

    意思是說: 若 cmd1的return value為true的話, 然后執行cmd2與cmd3, 否則執行cmd4與cmd5.

    事實上, 我們在寫shell script的時候, 經常需要用到這樣、那樣的條件 以作出不同的處理動作。 用&&與||的確可以達成條件執行的結果, 然而,從“人類語言”上來理解, 卻不是那么直觀。 更多時候,我們還是喜歡用if...then...else... 這樣的的keyword來表達條件執行。

    在bash shell中,我們可以如此修改上一段代碼:

    if cmd1 thencmd2cmd3 elsecmd4cmd5 fi

    這也是我們在shell script中最常用的if判斷式: 只要if后面的command line返回true的return value (我們常用test命令返回的return value), 然則就執行then后面的命令,否則,執行else之后的命令, fi則是用來結束判斷式的keyword。

    在if的判斷式中,else部分可以不用,但then是必需的。 (若then后不想跑任何command,可用:這個null command代替)。 當然,then或else后面,也可以再使用更進一層的條件判斷式, 這在shell script的設計上很常見。 若有多項條件需要"依序"進行判斷的話, 那我們則可使用elif這樣的keyword:

    if cmd1; thencmd2; elif cmd3; thencmd4 elsecmd5 fi

    意思是說: 若cmd1為true,然則執行cmd2; 否則在測試cmd3,若為true則執行cmd4; 倘若cmd1與cmd3均不成立,那就執行cmd5。

    if判斷式的例子很常見,你可從很多shell script中 看得到,我這里不再舉例子了...

    接下來為要為大家介紹的是case判斷式。 雖然if判斷式已可應付大部分的條件執行了, 然而,在某些場合中,卻不夠靈活, 尤其是在string式樣的判斷上,比方如下:

    QQ() {echo -n "Do you want to continue? (Yes/No): "read YNif [ "$YN" = Y -o "$YN" = y -o "$YN" = "Yes" -o "$YN" = "yes" -o "$YN" = YES]thenQQelseexit 0fi }QQ

    從例中,我們看得出來, 最麻煩的部分是在判斷YN的值可能有好幾種樣式。

    聰明的你或許會如此修改:

    QQ() {echo -n "Do you want to continue? (Yes/No): "read YNif echo "$YN" | grep -q '^[Yy]\([Ee][Ss]\)*$'thenQQelseexit 0fi }QQ

    也就是用Regular Expression來簡化代碼。 (我們有機會,再來介紹RE) 只是...是否有其他更方便的方法呢? 有的,就是用case判斷式即可:

    QQ() {echo -n "Do you want to continue? (Yes/No): "read YNcase "$YN" in[Yy]|[Yy][Ee][Ss])QQ;;*)exit 0;;esac }QQ

    我們常用的case的判斷式來判斷某一變量 在不同的值(通常是string)時,作出不同的處理, 比方說, 判斷script參數,以執行不同的命令

    若你有興趣,且用linux系統的話, 不妨挖一挖/etc/init.d/*中的那堆script中的case用法. 如下就是一例:

    case "$1" instart)start;;stop)stop;;status)rhstatus;;restart|reload)restart;;condrestart)[ -f /var/lock/subsys/syslog ] && restart || :;;*)echo $"Usage: $0 {start|stop|status|restart|condrestart}"exit 1 esac

    (若你對 postional parameter的印象已經模糊了,請重看第9章吧。)

    okay,是十三問還剩一問而已,過幾天再來搞定之...^_^

    ##shell十三問之13: for what? while與until差在哪?

    終于,來到了shell十三問的最后一問了... 長長吐一口氣~~~~

    最后要介紹的是shell script設計中常見的循環(loop). 所謂的loop就是script中的一段在一定條件下反復執行的代碼。

    bash shell中常用的loop有如下三種:

    • for
    • while
    • until

    ###1. for loop

    for loop 是從一個清單列表中讀進變量的值, 并依次的循環執行do到done之間的命令行。 例:

    for var in one two three four five doecho -----------------echo '$var is '$varecho done

    上例的執行結果將會是:

  • for會定義一個叫var的變量,其值依次是one two three four five。
  • 因為有5個變量值,因此,do與done之間的命令行會被循環執行5次。
  • 每次循環均用echo產生3個句子。而第二行中不在hard quote之內的$var會被替換。
  • 當最后一個變量值處理完畢,循環結束。
  • 我們不難看出,在for loop中,變量值的多寡,決定循環的次數。 然而,變量在循環中是否使用則不一定,得視設計需求而定。 倘若for loop沒有使用in這個keyword來制變量清單的話,其值將從 $@(或$*)中繼承:

    for var; do...... done

    Tips:

    若你忘記了`positional parameter, 請溫習第9章...

    for loop用于處理“清單”(list)項目非常方便, 其清單除了明確指定或從postional parameter取得之外, 也可以從變量替換或者命令替換取得... (再一次提醒:別忘了命令行的“重組”特性) 然而,對于一些“累計變化”的項目(整數的加減),for也能處理:

    for ((i = 1; i <= 10; i++)) doecho "num is $i" done

    ###2. while loop

    除了for loop, 上面的例子, 我們也可改用while loop來做到:

    num=1 while [ "$num" -le 10 ]; doecho "num is $num"num=$(($num + 1)) done

    while loop的原理與for loop稍有不同: 它不是逐次處理清單中的變量值, 而是取決于while 后面的命令行的return value:

    • 若為true, 則執行do與done之間的命令, 然后重新判斷while后的return value。
    • 若為false,則不再執行do與done之間的命令而結束循環。

    分析上例:

  • 在while之前,定義變量num=1.
  • 然后測試(test)$num是否小于或等于10.
  • 結果為true,于是執行echo并將num的值加1.
  • 再作第二輪測試,此時num的值為1+1=2,依然小于或等于10,因此,為true,循環繼續。
  • 直到num為10+1=11時,測試才會失敗...于是結束循環。
  • 我們不難發現: 若while的測試結果永遠為true的話,那循環將一直永久執行下去

    while:; doecho looping... done

    上面的**:是bash的null command,不做任何動作, 除了返回true的return value**。 因此這個循環不會結束,稱作死循環。

    死循環的產生有可能是故意設計的(如跑daemon), 也可能是設計的錯誤。

    若要結束死循環,可通過signal來終止(如按下ctrl-c). (關于process與signal,等日后有機會再補充,十三問略過。)

    ####3.until loop

    一旦你能夠理解while loop的話,那就能理解until loop: **與while相反, until是在return value 為false時進入循環,否則,結束。 因此,前面的例子,我們也可以輕松的用until來寫:

    num=1 until [ ! "$num" -le 10 ]; doecho "num is $num"num=$(($num + 1)) done

    或者:

    num=1until [ "$num" -gt 10 ]; doecho "num is $num"num=$(($num + 1)) done

    okay, 關于bash的三個常用的loop暫時介紹到這里。

    ###4. shell loop中的break與continue

    在結束本章之前,再跟大家補充兩個loop有關的命令:

    • break
    • continue 這兩個命令常用在復合式循環里, 也就是do ... done之間又有更進一層的loop, 當然,用在單一循環中也未嘗不可啦... ^_^

    break用來中斷循環,也就是強迫結束循環。 若break后面指定一個數值n的話,則從里向外中斷第n個循環, 預設值為 break 1,也就是中斷當前循環。 在使用break時,需要注意的是,它與return及exit是不同的:

    • break是結束loop;
    • return是結束function;
    • exit是結束script/shell;

    而continue則與break相反:強迫進入下一次循環動作.

    若你理解不來的話,那你可簡單的看成: 在continue在done之間的句子略過而返回到循環的頂端...

    與break相同的是:continue后面也可以指定一個數值n, 以決定繼續哪一層(從里往外計算)的循環, 預設值為 continue 1,也就是繼續當前的循環。

    在shell script設計中,若能善用loop, 將能大幅度提高script在復雜條件下的處理能力。 請多加練習吧...


    shell是十三問的總結語


    好了,該是到了結束的時候了。 婆婆媽媽地跟大家啰嗦了一堆shell的基礎概念。

    目的不是要告訴大家“答案”,而是要帶給大家“啟發”...

    在日后的關于shell的討論中,我或許經常用"連接"的方式 指引十三問中的內容。

    以便我們在進行技術探討時,彼此能有一些討論的基礎, 而不至于各說各話、徒費時力。

    但更希望十三問能帶給你更多的思考與樂趣, 至為重要的是通過實踐來加深理解。

    是的,我很重視實踐獨立思考這兩項學習要素。

    若你能夠掌握其中的真諦,那請容我說聲: 恭喜十三問你沒白看了 ^_^

    p.s. 至于補充問題部分,我暫時不寫了。 而是希望:

  • 大家補充題目。
  • 一起來寫心得。
  • Good luck and happy studing!


    ##shell十三問原作者**網中人**簽名中的bash的fork bomb

    最后,Markdown整理者補上本書的原作者網中人的個性簽名:

    ** 君子博學而日叁省乎己,則知明而行無過矣。**

    一個能讓系統shell崩潰的shell 片段:

    :() { :|:& }; : # <--- 這個別亂跑!好奇會死人的! echo '十人|日一|十十o' | sed 's/.../&\n/g' # <--- 跟你講就不聽,再跑這個就好了...

    原來是一個bash的fork炸彈:ref:http://en.wikipedia.org/wiki/Fork_bomb

    :() {:|:& } :

    代碼分析:

    (即除最后一行外)

    定義了一個 shell 函數,函數名是:,

    而這個函數體執行一個后臺命令:|:

    即冒號命令(或函數,下文會解釋)的輸出 通過管道再傳給冒號命令做輸入

    最后一行執行“:”命令

    在各種shell中運行結果分析:

    這個代碼只有在 bash 中執行才會出現不斷創建進程而耗盡系統資源的嚴重后果;

    在 ksh (Korn shell), sh (Bourne shell)中并不會出現,

    在 ksh88 和傳統 unix Bourne shell 中冒號不能做函數名,

    即便是在 unix-center freebsd 系統中的 sh 和 pdksh(ksh93 手邊沒有,沒試)中冒號可以做函數名,但還是不會出現那個效果。

    原因是 sh、ksh 中內置命令的優先級高于函數,所以執行“:”, 總是執行內置命令“:”而不是剛才定義的那個恐怖函數。

    但是在 bash 中就不一樣,bash 中函數的優先級高于內置命令, 所以執行“:”結果會導致不斷的遞歸,而其中有管道操作, 這就需要創建兩個子進程來實現,這樣就會不斷的創建進程而導致資源耗盡。

    眾所周知,bash是一款極其強大的shell,提供了強大的交互與編程功能。

    這樣的一款shell中自然不會缺少“函數”這個元素來幫助程序進行模塊化的高效開發與管理。 于是產生了由于其特殊的特性,bash擁有了fork炸彈。

    Jaromil在2002年設計了最為精簡的一個fork炸彈的實現。

    所謂fork炸彈是一種惡意程序,它的內部是一個不斷在fork進程的無限循環.

    fork炸彈并不需要有特別的權限即可對系統造成破壞。

    fork炸彈實質是一個簡單的遞歸程序。

    由于程序是遞歸的,如果沒有任何限制,

    這會導致這個簡單的程序迅速耗盡系統里面的所有資源.

    ##shell十三問之14: [^ ] 跟[! ]差在哪? (wildcard)

    這個題目說穿了, 就是要探討Wildcard與Regular Expression的差別的。 這也是很多初學shell的朋友很容易混淆的地方。

    首先,讓我們回到十三問之第2問, 再一次將我們提到的command line format 溫習一次:

    command_name options arguments

    同時,也再來理解一下,我在第5章所提到的變量替換的特性:

    先替換,再重組 command line!

    有了這個兩個基礎后,再讓我們來看Wildcard是什么回事吧。

    Part-I Wildcard (通配符)


    首先,

    `Wildcard` 也是屬于 `command line` 的處理工序,作用于 `arguments` 里的 `path` 之上。

    沒錯,它不用在command_name,也不用在options上。 而且,若argument不是path的話,那也與wildcard無關。

    換句更為精確的定義來講,

    `wildcard`是一種命令行的路徑擴展(path expansion)功能。

    提到這個擴展,那就不要忘了 command line的“重組”特性了!

    是的,這與變量替換(variable subtitution)及 命令替換(command substitution)的重組特性是一樣的。

    也就是在wildcard進行擴展后, 命令行會先完成重組,才會交給shell來處理。

    了解了wildcard的擴展與重組特性后, 接下來,讓我們了解一些常見的wildcard吧。

    wildcard功能
    *匹配0個或多個字符
    ?匹配任意單一字符
    [list]匹配list中任意單一字符
    [!list]匹配不在list中任意單一字符
    {string1,string2,...}匹配string1或者stsring2或者(...)中其一字符串

    Note: list 中可以指定單個字符,如abcd, 也可以指定ASCII字符的起止范圍,如 a-d。 即[abcd] 與 [a-d] 是等價的,稱為一個自定義的字符類。

    例如:

    a*b # a 與 b 之間可以有任意個字符(0個或多個),如aabcb, axyzb, a012b,ab等。 a?b # a 與 b 之間只能有一個字符,但該字符可以任意字符,如 aab, abb, acb, azb等。 a[xyz]b # a 與 b 之間只能有一個字符,但這個字符只能是x或者y或者z,如:axb, ayb, azb這三個。 a[!0-9]b# a 與 b 之間只能有一個字符,但這個字符不能是阿拉伯數字,如aab,ayb,a-b等。 a{abc,xyz,123}b # a 與 b之間只能是abc或者xyz或者123這三個字串之一,擴展后是aabcb,axyzb,a123b。
  • [! ] 中的! 只有放在第一位時,才有取反的功效。 eg: [!a]* 表示當前目錄下不以a開頭的路徑名稱; /tmp/[a\!]*表示/tmp目錄下所有以a 或者 ! 開頭的路徑名稱;

    思考:為何!前面要加\呢?提示是十三問之4.

  • [ - ]中-左右兩邊均有字符時,才表示一個范圍,否則,僅作-(減號)字符來處理。 舉例: /tmp/*[-z]/[a-zA-Z]* 表示/tmp 目錄下所有以z或者-結尾的子目錄中, 以英文字母(不分大小寫)開頭的目錄名稱。

  • 以*或?開頭的wildcard不能匹配隱藏文件(即以.開頭的文件名)。 eg: *.txt并不能匹配.txt但能匹配1.txt這樣的路徑名。 但1*txt及1?txt均可匹配1.txt這樣的路徑名。

  • 基本上,要掌握wildcard并不難, 只要多加練習,再勤于思考,就能靈活運用了。

    再次提醒:

    別忘了wildcard的"擴展" + "重組" 這個重要特性,而且只作用在 argument的path上。

    比方說, 假如當前目錄下有: a.txt b.txt c.txt 1.txt 2.txt 3.txt 這幾個文件。

    當我們在命令行中執行ls -l [0-9].txt的命令行時, 因為wildcard處于argument的位置上,

    于是根據匹配的路徑,擴展為: 1.txt 2.txt 3.txt, 在重組出ls -l 1.txt 2.txt 3.txt 這樣的命令行。

    因此,你在命令行上敲 ls -l [0-9].txt 與 ls -l 1.txt 2.txt 3.txt 輸出的結果是一樣, 原因就是在于此。

    ##shell十三問之15: [^ ] 跟[! ]差在哪? (RE: Regular Expression)

    Part-II Regular Expression (正則表達式)


    接下來的Regular Expression(RE) 可是個大題目,要講的很多。 我這里當然不可能講得很全。 只希望能帶給大家一個基本的入門概念,就很足夠了...

    先來考一下英文好了:What is expression? 簡單來說,就是"表達",也就是人們在溝通的時候所要陳述的內容。

    然而,生活中,表達方要清楚的將意思描述清楚, 而讓接收方完整無誤地領會,可不是件容易的事情。

    因而才會出現那么多的"誤會", 真可嘆句"表達不易"啊......

    同樣的情形也發生在計算機的數據處理過程中, 尤其是當我們在描述一段"文字內容"的時候.... 那么,我們不禁要問: 有何方法可以讓大家的誤會降至最低程度, 而讓表達的精確度達到最高程度呢? 答案就是"標準化"了, 也就是我們這里要談的Regular Expression啦...^_^

    然而,在進入RE介紹之前,不妨先讓我們溫習一下shell十三問之第4問, 那就是關于quoting的部分。

    關鍵是要能夠區分 shell command line上的meta與literal的這兩種不同的字符類型

    然后,我這里也跟你講: RE 表達式里字符也分meta與literal這兩種

    呵,不知親愛的讀者是否被我搞混亂了呢?... ^_^

    這也難怪啦,因為這的確是最容易混淆的地方, 剛學RE的朋友很多時候,都死在這里! 因此,請特別小心理解哦...

    簡單而言,除非你將RE寫在特定程序使用的腳本里, 否則,我們的RE也是通過 command line輸入的。 然而, 不少RE所使用的meta字符,跟shell 的meta字符是沖突的

    比方說, *這個字符,在RE里是一個modifier(修飾符);而在command line上,確是wildcard(通配符)

    那么,我們該如何解決這樣的沖突呢? 關鍵就是看你對shell十三問的第4問中所提的quoting是否足夠理解了!

    若你明白到 shell quoting 就是用來在command line上關閉shell meta這一基本原理, 那你就能很輕松的解決 RE meta與shell meta的沖突問題了: 用shell quoting 關閉掉shell meta就是了。 就這么簡單... ^_^

    再以剛提到*字符為例, 若在command line的path中沒有quoting處理的話, 如abc* 就會被作為wildcard expression來擴充及重組了。 若將其置于quoting中,即"abc*",則可以避免wildcard expand的處理。

    好了,說了大半天,還沒有進入正式的RE介紹呢.... 大家別急,因為我的教學風格就是要先建立基礎,循序漸進的... ^_^ 因此, 我這里還要再啰嗦一個觀念,才會到RE的說明啦...(哈...別打我...)

    當我們在談到RE時,千萬別跟wildcard搞混在一起! 尤其是

    在command line的位置里,wildcard只作用于argument的path上; 而RE卻只用于"字符串處理" 的程序中,這與路徑名一點關系也沒有。

    Tips: RE 所處理的字符串,通常是指純文本或通過stdin讀進的內容。

    okay,夠了夠了,我已看到一堆人開始出現不耐煩的樣子了... ^_^ 現在,就讓我們登堂入室,揭開RE的神秘面紗吧, 這樣可以放過我了吧? 哈哈...

    在RE的表達式里,主要分為兩種字符:literal與meta。 所謂literal就是在RE里不具有特殊功能的字符,如abc,123等; 而meta,在RE里具有特殊的功能。 要關閉之,需要在meta之前使用escape()轉義字符。

    然而,在介紹meta之前,先讓我們來認識一下字符組合(character set)會更好些。

    一、所謂的char set就是將多個連續的字符作為一個集合。 例如:

    char set意義
    abc表示abc三個連續的字符,但彼此獨立而非集合。(可簡單視為三個char set)
    (abc)表示abc這三個連續字符的集合。(可簡單視為一個char set)
    abc|xyz表示abc或xyz這連個char set之一
    [abc]表示單一字符,可為a或b或c;與wildcard的[abc]原理相同,稱之為字符類。
    [^abc]表示單一字符,不為a或b或c即可。(與wildcard [!abc]原理相同)
    .表示任意單個字符,(與wildcard的?原理相同)

    note: abc|xyz 表示abc或xyz這連個char set之一

    在認識了RE的char set這個概念之后,然后,在讓我們多認識幾個RE中常見的meta字符:

    二、 錨點(anchor): 用以標識RE在句子中的位置所在。 常見的有:

    錨點說明
    ^表示句首。如,^abc表示以abc開頭的句子。
    $表示句尾。如,abc$表示以abc結尾的句子。
    <表示詞首。如,<abc表示以abc開頭的詞。
    >表示詞尾。如,abc>表示以abc結尾的詞。

    三、 修飾符(modifier):獨立表示時本身不具意義,專門用以修飾前一個char set出現的次數。 常見的有:

    modifier說明
    *表示前一個char set出現0次或多次,即任意次。如ab*c表示a與c之間可以有0個或多個b。
    ?表示前一個char set出現0次或1次,即至多出現1次。如ab?c 表示a與c之間可以有0個或1個b。
    +表示前一個char set出現1次或多次,即至少出現1次。如ab+c 表示a與c之間可以有1個或多個b。
    {n}表示前一個char set出現n次。如ab{n}c 表示a與c之間可以有n個b。
    {n, }表示前一個char set至少出現n次。如ab{n}c 表示a與c之間至少有n個b。
    {n, m}表示前一個char set至少出現n次,至多出現m次。如ab{n,m}c 表示a與c之間至少有n個b,至多有m個b。

    然而,當我們在識別modifier時,卻很容易忽略"邊界(boundary)字符"的重要性。

    以ab{3,5}c為例,這里的a與c就是邊界字符了。 若沒有邊界字符的幫忙,我們很容易做出錯誤的解讀。 比方說: 我們用ab{3,5}這個RE(少了c這個邊界字符) 可以抓到"abbbbbbbbbb"(a后面有10個b)的字符串嗎? 從剛才的modifier的說明,我們一般認為,我們要的b是3到5個, 若超出了此范圍,就不是我們所要表達的。 因此,我們或許會很輕率地認為這個RE抓不到結果(上述"abbbbbbbbbb"字符串)。

    然而,答案卻是可以的!為什么呢? 讓我們重新解讀ab{3,5}這個RE看看: 我們要表達的是a后接3到5個b即可,但3到5個b后面,我們卻沒有規定什么, 因此,在RE后面可以是任意的字符串,當然包括b也可以啦!(明白了嗎?)

    同樣,我們用b{3,5}c也同樣可以抓到"abbbbbbbbbbc" 這樣的字符串。

    但當我們用ab{3,5}c這樣的RE時, 由于同時有a與c這連個邊界字符,就截然不同了!

    有空在思考一下,為何我們用下面這些RE都抓到abc這樣的字符串呢?

    x* ax*, abx*, ax*b abcx*, abx*c, ax*bc bx*c, bcx*, x*bc

    但, 若我們在這些RE前后分別加^與$這樣的anchor,那又如何呢?

    剛學RE時,只要能掌握上面這些基本的meta的大概就可以入門了。 一如前述,RE是一種規范化的文字表達式, 主要用于某些文字處理工具之間,如: grep, perl, vi,awk,sed,等等, 常用于表示一段連續的字符串,查找和替換。

    然而每種工具對RE表達式的具體解讀或有一些細微差別, 不過節本原理還是一致的。 只要掌握RE的基本原理,那就一理通百理了, 只是在實踐時,稍加變通即可。

    比方以grep來說, 在Linux上,你可以找到grep,egrep,fgrep這些程序, 其差異大致如下:

    grep: 傳統的grep程序,在沒有任何選項(options)的情況下,只輸出符合RE字串的句子, 其常見的選項如下:

    選項 (option)用途
    -v反模式, 只輸出“不含”RE的字符串的行。
    -r 遞歸模式,可同時處理所有層級的子目錄里的文件
    -q靜默模式,不輸出任何結果(stderr 除外,常用于獲取return value,符合為true,否則,為false.
    -i忽略大小寫
    -w整詞匹配,類似 <RE>
    -n同時輸出行號
    -l輸出匹配RE的文件名
    -o只輸出匹配RE的字符串。(gna新版獨有,不見得所有版本支持)
    -E切換為egrep

    egrep:為grep的擴充版本,改良了許多傳統grep不能或者不便的操作,

    • grep下不支持?與+這兩種meta,但egrep支持;
    • grep 不支持a|b或(abc|xyz)這類“或一”的匹配,但egrep支持;
    • grep 在處理{n,m}時,需要\{ 與 \}處理,但egrep不需。

    等諸如此類的。我個人建議能用egrep就不用grep啦...^_^

    fgrep: 不作RE處理,表達式僅作一般的字符串處理,所有的meta均市區功能。

    好了,關于RE的入門,我們暫時就介紹到這里。 雖然有點亂,且有些觀念也不恨精確, 不過,姑且算是對大家的一個交差吧...^_^ 若這兩天有時間的話,我在舉些范例來分析一下,以幫助大家更好的理解。 假如更有可能的話,也順道為大家介紹一下sed這個工具。


    Part-III eval


    講到command line的重組特性, 真的需要我們好好的加以解釋的。

    如此便能抽絲剝繭的一層層的將整個command line分析的 一清二楚,而不至于含糊。

    假如這個重組的特性理解了,那我們介紹一個好玩的命令:eval.

    我們在變量替換的過程中,常會碰到所謂的復式變量的問題: 如:

    a=1 A1=abc

    我們都知道echo $A1就可以得到abc的結果。 然而,我們能否用$A$a來取代$A1,而同一樣替換為abc呢?

    這個問題我們可用很輕松的用eval來解決:

    eval echo \$A$a

    說穿了,eval 只不過是在命令行完成替換重組后, 在來一次替換重組罷了... 就是這么簡單啦~~~ ^_^

    ##shell十三問之16:學習總結與原帖目錄

    本人(markdown譯者)是解決工作中shell腳本的一個問題, 偶爾的一次機會遇到了CU論壇中這樣一個神貼:shell十三問.

    shell十三問是CU的shell版的臺灣的網中人是2003年用繁體發布的。 第一次讀到shell十三問,由于是繁體,第一感覺有點抵觸, 但是還是耐著性子讀完了一貼,沒想到竟然讀懂了, 而且還被網中人的幽默的寫作風格,獨到的思維方式, 循序漸進的認識事物的過程所折服。

    盡管帖子是10多年前寫的,今天看來也幾乎沒有一點過時的感覺。 從這個方面來說,shell十三問應該shell的(思想)精華本質所在, 就像武功的內功心法,可能我說的點過, 但是我曾經看過一本shell腳本學習指南,看完后的感覺,還是有感念很朦朧, 而shell十三問是我最容易理解和接受的,這也是我整理的Markdown版本初衷。 為什么不讓好東西讓更多的人熟知呢,恰好年前項目管理開始遷移到git上, 在git上認識一個好東西Markdown,用它可以很簡單地整理出條例清晰篇章。 在年假的時候,覺得這個假期該做點什么, 畢竟馬總都說了,改變世界,不如改變自己。

    本人整理的 [簡體中文Markdown版本的shell十三問][shell-markdown] 的鏈接地址: https://github.com/wzb56/13_questions_of_shell

    網中人的CU原帖shell十三問地址:http://bbs.chinaunix.net/thread-218853-1-1.html

    我簡單將原文整理如下:

    我在CU的日子并不長,有幸在shell版上與大家結緣。 除了跟前輩學習到不少技巧之外,也常看到不少朋友的問題。 然而,在眾多問題中,我發現許多瓶頸都源于shell的基礎而已。 每次要解說,卻總有千言萬語不知從何而起之感......

    這次,我不是來回答,而是準備了關于shell基礎的十三個問題要問大家。 希望的shell的學習者們能夠通過尋找答案的過程,好好的將shell基礎打扎實一點。

    當然了,這些問題我也會逐一解說一遍。 只是,我不敢保證什么時候能夠完成這趟任務。

    除了時間關系外,個人功力實在有限,很怕匆忙間誤導觀眾就糟糕了。 若能拋磚引玉,誘得,其他前輩出馬補充,那才是功德一件。

    ###shell十三問:

  • 為何叫做 shell?

  • shell prompt(PS1) 與 Carriage Return(CR) 的關系? (2008-10-30 02:05 最后更新)

  • 別人 echo、你也 echo ,是問 echo 知多少?( 2008-10-30 02:08 最后更新)

  • " "(雙引號) 與 ' '(單引號)差在哪? (2008-10-30 02:07 最后更新)

  • var=value 在export前后差在哪? (2008-10-30 02:12 最后更新)

  • exec 跟 source 差在哪? (2008-10-30 02:17 最后更新)

  • ( ) 與 { } 差在哪?

  • $(( )) 與 $( ) 還有${ } 差在哪? (2008-10-30 02:20 最后更新)

  • $@ 與 $* 差在哪?

  • && 與 || 差在哪? (2008-10-30 02:21 最后更新)

  • > 與 < 差在哪? (2008-10-30 02:24 最后更新)

  • [你要 if 還是 case 呢?] 12 (2008-10-30 02:25最后更新)

  • for what? while 與 until 差在哪? (2008-10-30 02:26最后更新)

  • [^ ] 跟 [! ] 差在哪?

  • Part-I: Wildcard (2008-10-30 02:25 最後更新)

  • Part-II Regular Expression (2008-10-30 02:26 最后更新)


  • 說明:

  • 歡迎大家補充/擴充問題。

  • 我接觸電腦的中文名稱時是在臺灣,因此一些術語或與大陸不同,請自行轉換。

  • 我會不定時"逐題"說明(以 Linux 上的 bash 為環境) 同時,也會在任何時候進行無預警的修改。請讀者自行留意。

  • 本人于本系列所發表的任文章均可自由以電子格式(非印刷)引用、修改、轉載, 且不必注明出處(若能注明 CU 更佳)。當然,若有錯漏或不當結果,本人也不負任何責任。

  • 若有人愿意整理成冊且付印者,本人僅保留著作權,版權收益之 30% 須捐贈于 CU 論壇管理者,剩余不究。


  • 建議參考談論:

  • shaoping0330 兄關于變量替換的補充:(鏈接在改版后已經失效)

  • shaoping0330 兄關于 RE 的說明:

  • 關于 nested subshell 的討論:(鏈接在改版后已經失效)

  • 關于 IFS 的討論:


    • 感謝 lkydeer 兄整理 word/pdf 版本方便大家參考:

    轉載于:https://my.oschina.net/michao/blog/758884

    總結

    以上是生活随笔為你收集整理的shell十三问--shell教程的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    又粗又大又硬毛片免费看 | 久久99热只有频精品8 | 99久久精品午夜一区二区 | 色婷婷综合激情综在线播放 | a片在线免费观看 | 综合人妻久久一区二区精品 | 精品无码一区二区三区爱欲 | av无码电影一区二区三区 | 亚洲精品午夜国产va久久成人 | 久久人人爽人人人人片 | 无套内射视频囯产 | 高潮毛片无遮挡高清免费 | 又紧又大又爽精品一区二区 | 国产人妻精品一区二区三区不卡 | 97无码免费人妻超级碰碰夜夜 | 四十如虎的丰满熟妇啪啪 | 国产做国产爱免费视频 | 国产精品99久久精品爆乳 | 中国女人内谢69xxxx | 久久久久久国产精品无码下载 | 久久久www成人免费毛片 | 日韩人妻无码中文字幕视频 | 日欧一片内射va在线影院 | 妺妺窝人体色www在线小说 | 白嫩日本少妇做爰 | 国产综合色产在线精品 | 狠狠cao日日穞夜夜穞av | 给我免费的视频在线观看 | 天下第一社区视频www日本 | 久久久久成人精品免费播放动漫 | 女人被男人躁得好爽免费视频 | 色一情一乱一伦一视频免费看 | 色五月丁香五月综合五月 | 成人精品天堂一区二区三区 | 无码福利日韩神码福利片 | 丰满人妻一区二区三区免费视频 | 7777奇米四色成人眼影 | 国产激情综合五月久久 | 国产无遮挡吃胸膜奶免费看 | 97久久超碰中文字幕 | 99久久精品国产一区二区蜜芽 | 成年美女黄网站色大免费视频 | 成人性做爰aaa片免费看不忠 | 日日天日日夜日日摸 | 成年美女黄网站色大免费全看 | 久久久久免费看成人影片 | 99久久精品午夜一区二区 | 狠狠cao日日穞夜夜穞av | 大色综合色综合网站 | 日本精品久久久久中文字幕 | v一区无码内射国产 | 久久国产精品萌白酱免费 | 中文字幕人妻丝袜二区 | 国产成人久久精品流白浆 | 国产小呦泬泬99精品 | 国产精品亚洲专区无码不卡 | 日韩欧美群交p片內射中文 | 人人超人人超碰超国产 | 久在线观看福利视频 | 欧美国产日产一区二区 | 亚洲精品中文字幕 | 成年美女黄网站色大免费视频 | 亚洲国产欧美日韩精品一区二区三区 | 88国产精品欧美一区二区三区 | 久久综合久久自在自线精品自 | 成人影院yy111111在线观看 | 国产福利视频一区二区 | 欧美丰满少妇xxxx性 | 久久精品国产99精品亚洲 | 成人无码视频免费播放 | 亚洲一区二区三区香蕉 | 300部国产真实乱 | 国产97人人超碰caoprom | 99riav国产精品视频 | 少妇高潮喷潮久久久影院 | 内射后入在线观看一区 | 久久国产精品偷任你爽任你 | 97资源共享在线视频 | 久久久久久a亚洲欧洲av冫 | 久久久婷婷五月亚洲97号色 | 国产乱人伦偷精品视频 | 人妻夜夜爽天天爽三区 | 国产免费久久精品国产传媒 | 久久人人97超碰a片精品 | 国产一区二区不卡老阿姨 | 国产色xx群视频射精 | 久久综合九色综合97网 | 久青草影院在线观看国产 | 国产激情一区二区三区 | 国产精品香蕉在线观看 | 曰本女人与公拘交酡免费视频 | 精品人妻中文字幕有码在线 | 中文字幕无线码免费人妻 | 97色伦图片97综合影院 | 乱人伦人妻中文字幕无码 | 亚洲成a人片在线观看无码3d | 国产精品国产自线拍免费软件 | 少妇人妻偷人精品无码视频 | 美女黄网站人色视频免费国产 | 精品无码av一区二区三区 | 欧美阿v高清资源不卡在线播放 | 一二三四在线观看免费视频 | 中文字幕乱码亚洲无线三区 | 一本大道伊人av久久综合 | 国产精品久久久久影院嫩草 | 国产女主播喷水视频在线观看 | 在线播放亚洲第一字幕 | 在线а√天堂中文官网 | 欧洲美熟女乱又伦 | 精品国产乱码久久久久乱码 | 香港三级日本三级妇三级 | 久久精品无码一区二区三区 | 国产成人无码av片在线观看不卡 | 国产va免费精品观看 | 精品 日韩 国产 欧美 视频 | 欧美丰满熟妇xxxx性ppx人交 | 久久亚洲国产成人精品性色 | 4hu四虎永久在线观看 | 牲欲强的熟妇农村老妇女视频 | 亚洲va中文字幕无码久久不卡 | 伊在人天堂亚洲香蕉精品区 | 97无码免费人妻超级碰碰夜夜 | 国产精品-区区久久久狼 | 中文字幕无码热在线视频 | 午夜免费福利小电影 | 欧美色就是色 | 青青青手机频在线观看 | 亚无码乱人伦一区二区 | 婷婷丁香五月天综合东京热 | 性欧美疯狂xxxxbbbb | 黑森林福利视频导航 | 乱码午夜-极国产极内射 | 久久久精品人妻久久影视 | 国产真实伦对白全集 | 午夜精品久久久内射近拍高清 | 强伦人妻一区二区三区视频18 | 乌克兰少妇xxxx做受 | 国产情侣作爱视频免费观看 | 无码av免费一区二区三区试看 | 蜜桃臀无码内射一区二区三区 | 中文字幕中文有码在线 | 丰满人妻一区二区三区免费视频 | 丰满少妇熟乱xxxxx视频 | 成人无码视频免费播放 | 人妻熟女一区 | 亚洲国产欧美国产综合一区 | 国产人妻人伦精品 | 国产精品福利视频导航 | 欧美老妇与禽交 | 77777熟女视频在线观看 а天堂中文在线官网 | 亚洲成色www久久网站 | 亚洲精品www久久久 | 色婷婷综合激情综在线播放 | 夜夜夜高潮夜夜爽夜夜爰爰 | 日本精品久久久久中文字幕 | 未满小14洗澡无码视频网站 | 伊人久久大香线蕉av一区二区 | 亚洲色欲色欲天天天www | 草草网站影院白丝内射 | 久久 国产 尿 小便 嘘嘘 | 欧美丰满熟妇xxxx性ppx人交 | 久久综合九色综合欧美狠狠 | 久久精品无码一区二区三区 | 99视频精品全部免费免费观看 | 精品无码国产一区二区三区av | 日本乱偷人妻中文字幕 | 中文字幕+乱码+中文字幕一区 | 丰满少妇人妻久久久久久 | 日本大乳高潮视频在线观看 | 日本一区二区三区免费播放 | 好男人www社区 | 免费视频欧美无人区码 | 中文字幕久久久久人妻 | 国产日产欧产精品精品app | 久久久久se色偷偷亚洲精品av | 奇米影视888欧美在线观看 | 国产三级精品三级男人的天堂 | 久久久久成人精品免费播放动漫 | 亚洲 a v无 码免 费 成 人 a v | 一本加勒比波多野结衣 | 亚洲色偷偷偷综合网 | 久久久久久久久蜜桃 | 国产精品欧美成人 | 少妇人妻av毛片在线看 | 十八禁真人啪啪免费网站 | 爆乳一区二区三区无码 | 久久久久久亚洲精品a片成人 | 一二三四社区在线中文视频 | 熟妇女人妻丰满少妇中文字幕 | 日韩欧美群交p片內射中文 | 欧美精品国产综合久久 | 国产亚洲tv在线观看 | 18精品久久久无码午夜福利 | 国产婷婷色一区二区三区在线 | 亚洲精品中文字幕久久久久 | 国产免费久久久久久无码 | 欧美freesex黑人又粗又大 | 精品人妻人人做人人爽夜夜爽 | 无码纯肉视频在线观看 | 精品日本一区二区三区在线观看 | 无码午夜成人1000部免费视频 | 亚洲人成人无码网www国产 | 国产激情精品一区二区三区 | 荫蒂被男人添的好舒服爽免费视频 | 奇米影视7777久久精品人人爽 | 中文精品久久久久人妻不卡 | 亚洲国产精品毛片av不卡在线 | 日韩亚洲欧美精品综合 | 捆绑白丝粉色jk震动捧喷白浆 | 99久久精品国产一区二区蜜芽 | 天天摸天天透天天添 | 国产精品永久免费视频 | 欧美 丝袜 自拍 制服 另类 | 强开小婷嫩苞又嫩又紧视频 | 秋霞成人午夜鲁丝一区二区三区 | 亚洲国产成人av在线观看 | 天堂亚洲2017在线观看 | 久久国产精品二国产精品 | 午夜免费福利小电影 | 国产精品久免费的黄网站 | 少妇性l交大片 | 亚洲欧洲日本无在线码 | 国产在线一区二区三区四区五区 | 无码国产乱人伦偷精品视频 | 图片区 小说区 区 亚洲五月 | 少妇一晚三次一区二区三区 | 波多野结衣 黑人 | 波多野结衣乳巨码无在线观看 | 最近的中文字幕在线看视频 | 国产亚洲精品久久久久久 | 国产精品久久久久影院嫩草 | 成人性做爰aaa片免费看不忠 | 久久人人97超碰a片精品 | √天堂资源地址中文在线 | 99久久无码一区人妻 | 波多野结衣 黑人 | 麻豆md0077饥渴少妇 | 日本高清一区免费中文视频 | 国产福利视频一区二区 | 粗大的内捧猛烈进出视频 | 日本一卡2卡3卡4卡无卡免费网站 国产一区二区三区影院 | 日韩精品成人一区二区三区 | 无码国内精品人妻少妇 | 色婷婷综合中文久久一本 | 中文无码伦av中文字幕 | 狠狠色噜噜狠狠狠狠7777米奇 | 2020久久香蕉国产线看观看 | 色情久久久av熟女人妻网站 | 蜜桃无码一区二区三区 | 偷窥村妇洗澡毛毛多 | 国产精品国产三级国产专播 | 少妇无套内谢久久久久 | 国产亚洲人成a在线v网站 | 黑人巨大精品欧美黑寡妇 | 国产精品理论片在线观看 | 精品无码国产自产拍在线观看蜜 | 爆乳一区二区三区无码 | 嫩b人妻精品一区二区三区 | 99久久人妻精品免费一区 | 国内精品久久毛片一区二区 | 国产亲子乱弄免费视频 | 日本护士xxxxhd少妇 | 性史性农村dvd毛片 | 丰满人妻精品国产99aⅴ | 九九久久精品国产免费看小说 | 搡女人真爽免费视频大全 | 成人亚洲精品久久久久软件 | 国产精品人人妻人人爽 | 九九在线中文字幕无码 | 无码人妻精品一区二区三区下载 | 久久99国产综合精品 | 国产欧美精品一区二区三区 | 日韩 欧美 动漫 国产 制服 | 丰满肥臀大屁股熟妇激情视频 | 午夜无码区在线观看 | 精品一区二区三区波多野结衣 | 久久久成人毛片无码 | 中文字幕+乱码+中文字幕一区 | 俺去俺来也www色官网 | 国产无遮挡吃胸膜奶免费看 | 亚洲男人av天堂午夜在 | 日本丰满熟妇videos | 国产亚洲精品久久久ai换 | 国产精品无码成人午夜电影 | 偷窥日本少妇撒尿chinese | 欧美丰满老熟妇xxxxx性 | 强伦人妻一区二区三区视频18 | 秋霞特色aa大片 | 日韩精品无码一本二本三本色 | 俄罗斯老熟妇色xxxx | 77777熟女视频在线观看 а天堂中文在线官网 | 国产一区二区三区精品视频 | 无码人妻精品一区二区三区不卡 | 亚洲一区二区三区 | 无码任你躁久久久久久久 | 久久国产精品二国产精品 | 久久精品中文字幕大胸 | 亚洲国产欧美在线成人 | 久久视频在线观看精品 | 欧美zoozzooz性欧美 | 中文字幕日韩精品一区二区三区 | 内射后入在线观看一区 | 中文字幕色婷婷在线视频 | 久久综合色之久久综合 | 性欧美牲交xxxxx视频 | 日本一本二本三区免费 | 成年女人永久免费看片 | 亚洲gv猛男gv无码男同 | 岛国片人妻三上悠亚 | 成人免费视频在线观看 | 国产av剧情md精品麻豆 | 无码福利日韩神码福利片 | 欧美亚洲日韩国产人成在线播放 | 人妻少妇被猛烈进入中文字幕 | 免费看少妇作爱视频 | 日韩在线不卡免费视频一区 | 亚洲国产欧美在线成人 | 免费网站看v片在线18禁无码 | 成人免费视频一区二区 | 东北女人啪啪对白 | 综合网日日天干夜夜久久 | 国产人妻精品一区二区三区 | 国产亚洲日韩欧美另类第八页 | 亚洲成a人片在线观看无码 | 色综合久久网 | 亚洲s码欧洲m码国产av | 国产黄在线观看免费观看不卡 | 亚洲中文字幕无码中文字在线 | 国产香蕉97碰碰久久人人 | 99麻豆久久久国产精品免费 | 亚洲色欲久久久综合网东京热 | 久久精品国产一区二区三区肥胖 | 国产偷国产偷精品高清尤物 | 亚洲另类伦春色综合小说 | 国产精品亚洲专区无码不卡 | 国内精品久久毛片一区二区 | 色综合久久88色综合天天 | 久久精品国产99久久6动漫 | 久久天天躁狠狠躁夜夜免费观看 | 国产精品久久久久7777 | www一区二区www免费 | 欧美成人高清在线播放 | 日韩成人一区二区三区在线观看 | 免费国产成人高清在线观看网站 | 亚洲一区av无码专区在线观看 | 国产av无码专区亚洲awww | 精品乱子伦一区二区三区 | 爱做久久久久久 | 牲欲强的熟妇农村老妇女视频 | 人人超人人超碰超国产 | 亚洲欧美日韩综合久久久 | 亚洲а∨天堂久久精品2021 | 天海翼激烈高潮到腰振不止 | 男女爱爱好爽视频免费看 | 亚洲精品久久久久avwww潮水 | 日本一本二本三区免费 | 在线看片无码永久免费视频 | 67194成是人免费无码 | 狠狠色噜噜狠狠狠7777奇米 | 丰满少妇熟乱xxxxx视频 | 久久国产精品_国产精品 | www国产精品内射老师 | 国产内射老熟女aaaa | 中文亚洲成a人片在线观看 | 亚洲欧美综合区丁香五月小说 | 色欲久久久天天天综合网精品 | 无码人妻出轨黑人中文字幕 | 久久99精品国产.久久久久 | 蜜桃视频插满18在线观看 | 大地资源网第二页免费观看 | 国产明星裸体无码xxxx视频 | 国产免费无码一区二区视频 | 综合人妻久久一区二区精品 | 久久久久成人精品免费播放动漫 | 成人欧美一区二区三区 | 98国产精品综合一区二区三区 | av在线亚洲欧洲日产一区二区 | 性欧美熟妇videofreesex | 丰满少妇高潮惨叫视频 | 男女作爱免费网站 | 亚洲国产精品久久久天堂 | 免费国产黄网站在线观看 | 国产美女极度色诱视频www | 欧美xxxxx精品 | 在线精品亚洲一区二区 | 天堂久久天堂av色综合 | 人人妻人人澡人人爽欧美一区九九 | 搡女人真爽免费视频大全 | 国内精品久久毛片一区二区 | 女人被男人爽到呻吟的视频 | 曰韩无码二三区中文字幕 | 欧美日韩一区二区免费视频 | 午夜福利试看120秒体验区 | 美女扒开屁股让男人桶 | 奇米影视888欧美在线观看 | 国产性猛交╳xxx乱大交 国产精品久久久久久无码 欧洲欧美人成视频在线 | 亚洲伊人久久精品影院 | 人妻有码中文字幕在线 | 精品无码一区二区三区爱欲 | 亚洲日韩一区二区 | 成熟人妻av无码专区 | 国产国语老龄妇女a片 | 激情亚洲一区国产精品 | 亚洲中文字幕在线观看 | 欧美 亚洲 国产 另类 | 麻豆精产国品 | 国产亲子乱弄免费视频 | 精品偷自拍另类在线观看 | 国产精品亚洲专区无码不卡 | 六月丁香婷婷色狠狠久久 | 亚洲国产精品无码一区二区三区 | 人人妻人人澡人人爽人人精品浪潮 | 色狠狠av一区二区三区 | 性开放的女人aaa片 | 撕开奶罩揉吮奶头视频 | 风流少妇按摩来高潮 | 久久久久久亚洲精品a片成人 | 樱花草在线社区www | a在线观看免费网站大全 | 2020最新国产自产精品 | 人妻少妇被猛烈进入中文字幕 | 欧美兽交xxxx×视频 | 亚洲日韩乱码中文无码蜜桃臀网站 | 玩弄人妻少妇500系列视频 | 国产色视频一区二区三区 | 乱码av麻豆丝袜熟女系列 | 国产猛烈高潮尖叫视频免费 | 亚洲中文字幕久久无码 | 亚洲自偷自拍另类第1页 | 99久久精品无码一区二区毛片 | 搡女人真爽免费视频大全 | 东京热无码av男人的天堂 | 帮老师解开蕾丝奶罩吸乳网站 | 国产明星裸体无码xxxx视频 | 四虎国产精品一区二区 | 婷婷综合久久中文字幕蜜桃三电影 | 亚洲精品成人av在线 | 99riav国产精品视频 | 国内精品九九久久久精品 | 日日噜噜噜噜夜夜爽亚洲精品 | 亚洲国产精品久久人人爱 | 国产国语老龄妇女a片 | 国产成人精品一区二区在线小狼 | 国产亚洲精品久久久ai换 | 伊人久久大香线焦av综合影院 | 婷婷丁香六月激情综合啪 | 国产亚洲精品久久久久久久 | 天海翼激烈高潮到腰振不止 | 强伦人妻一区二区三区视频18 | 久久综合九色综合97网 | 综合激情五月综合激情五月激情1 | 亚洲精品综合一区二区三区在线 | 国产无套粉嫩白浆在线 | 亚洲精品成a人在线观看 | 久久国产精品萌白酱免费 | 欧美丰满熟妇xxxx性ppx人交 | 国产乱人伦偷精品视频 | 性生交大片免费看女人按摩摩 | 午夜精品一区二区三区在线观看 | 中文字幕人妻无码一区二区三区 | 久久国产精品二国产精品 | 国产一区二区三区四区五区加勒比 | 国产成人一区二区三区在线观看 | 亚洲色欲色欲天天天www | 少妇激情av一区二区 | 强辱丰满人妻hd中文字幕 | 正在播放老肥熟妇露脸 | 亚洲成av人影院在线观看 | 成年美女黄网站色大免费全看 | 亚洲阿v天堂在线 | 国产人妻久久精品二区三区老狼 | 国产精品丝袜黑色高跟鞋 | 国产在线一区二区三区四区五区 | 欧美第一黄网免费网站 | 欧美成人午夜精品久久久 | 久久99精品国产麻豆蜜芽 | 真人与拘做受免费视频一 | 久久久精品国产sm最大网站 | 国产乱子伦视频在线播放 | 国产精品久久久久无码av色戒 | 丁香啪啪综合成人亚洲 | 中文字幕乱码亚洲无线三区 | 老熟妇仑乱视频一区二区 | 久久精品女人天堂av免费观看 | 亚洲精品中文字幕乱码 | 亚洲人成网站免费播放 | 亚洲第一网站男人都懂 | 蜜桃臀无码内射一区二区三区 | 久久婷婷五月综合色国产香蕉 | 国产av人人夜夜澡人人爽麻豆 | 国产乱子伦视频在线播放 | 亚洲色在线无码国产精品不卡 | 任你躁国产自任一区二区三区 | 亚洲日韩av一区二区三区中文 | 午夜丰满少妇性开放视频 | 日本免费一区二区三区最新 | 日日噜噜噜噜夜夜爽亚洲精品 | 天堂亚洲免费视频 | 福利一区二区三区视频在线观看 | 131美女爱做视频 | 荡女精品导航 | 免费无码一区二区三区蜜桃大 | 窝窝午夜理论片影院 | 国产精品福利视频导航 | 欧美xxxxx精品 | 人妻中文无码久热丝袜 | 又色又爽又黄的美女裸体网站 | 国产女主播喷水视频在线观看 | 无码福利日韩神码福利片 | 男人扒开女人内裤强吻桶进去 | 亚洲国产av美女网站 | 国产美女极度色诱视频www | 欧美熟妇另类久久久久久多毛 | 久久无码专区国产精品s | 久久精品成人欧美大片 | 欧洲精品码一区二区三区免费看 | 日韩精品一区二区av在线 | 国内少妇偷人精品视频免费 | 中文精品无码中文字幕无码专区 | 成 人 网 站国产免费观看 | 黑人大群体交免费视频 | 国产av一区二区三区最新精品 | 欧美日本免费一区二区三区 | 亚洲成av人片在线观看无码不卡 | 欧美 日韩 亚洲 在线 | 色婷婷av一区二区三区之红樱桃 | a在线观看免费网站大全 | 麻豆国产97在线 | 欧洲 | 老熟妇乱子伦牲交视频 | 久久久无码中文字幕久... | 水蜜桃色314在线观看 | 丰满人妻翻云覆雨呻吟视频 | 亚洲国产综合无码一区 | 国产va免费精品观看 | 亚洲国产精品一区二区美利坚 | 国产精品久久久午夜夜伦鲁鲁 | 午夜福利一区二区三区在线观看 | 日韩精品无码免费一区二区三区 | 中文字幕人妻无码一区二区三区 | 亚洲国产欧美国产综合一区 | 在线观看免费人成视频 | 又色又爽又黄的美女裸体网站 | 波多野结衣aⅴ在线 | 人人妻人人澡人人爽精品欧美 | 国产精品无码成人午夜电影 | 99久久久无码国产aaa精品 | 国产亚洲美女精品久久久2020 | 国产国产精品人在线视 | 狠狠色欧美亚洲狠狠色www | 久久国产精品精品国产色婷婷 | 免费人成在线观看网站 | 精品厕所偷拍各类美女tp嘘嘘 | 又大又黄又粗又爽的免费视频 | 中文精品无码中文字幕无码专区 | 久久精品国产一区二区三区 | 狂野欧美激情性xxxx | 黑人粗大猛烈进出高潮视频 | 无码人妻丰满熟妇区毛片18 | 免费无码午夜福利片69 | 欧美 日韩 亚洲 在线 | 中文字幕无码av波多野吉衣 | 一本色道久久综合狠狠躁 | 日本高清一区免费中文视频 | 99麻豆久久久国产精品免费 | 偷窥村妇洗澡毛毛多 | 久久熟妇人妻午夜寂寞影院 | 无码一区二区三区在线 | 伊人久久大香线蕉亚洲 | 国产高清av在线播放 | 亚洲日韩av一区二区三区四区 | 欧美日韩视频无码一区二区三 | 曰本女人与公拘交酡免费视频 | 日韩精品乱码av一区二区 | 国产精品久久国产精品99 | 自拍偷自拍亚洲精品被多人伦好爽 | 无码吃奶揉捏奶头高潮视频 | 成人免费无码大片a毛片 | 福利一区二区三区视频在线观看 | 日本一区二区三区免费播放 | 妺妺窝人体色www在线小说 | 亚洲熟女一区二区三区 | 高潮毛片无遮挡高清免费视频 | 成人免费视频在线观看 | 国产激情精品一区二区三区 | 无码人妻精品一区二区三区下载 | 欧美激情内射喷水高潮 | 偷窥村妇洗澡毛毛多 | 67194成是人免费无码 | 人人爽人人爽人人片av亚洲 | 久久五月精品中文字幕 | 久久久久人妻一区精品色欧美 | 一二三四在线观看免费视频 | 日日麻批免费40分钟无码 | 欧美国产亚洲日韩在线二区 | 夜夜影院未满十八勿进 | 欧美怡红院免费全部视频 | 一区二区三区乱码在线 | 欧洲 | 日本在线高清不卡免费播放 | 亚洲 激情 小说 另类 欧美 | 欧美怡红院免费全部视频 | 国产精品香蕉在线观看 | 在线观看免费人成视频 | 国产成人精品久久亚洲高清不卡 | 强开小婷嫩苞又嫩又紧视频 | 亚洲欧洲日本无在线码 | 国产日产欧产精品精品app | 国产成人综合在线女婷五月99播放 | 久久人人爽人人爽人人片ⅴ | 国产综合在线观看 | 成人影院yy111111在线观看 | 中文字幕无码热在线视频 | 日本肉体xxxx裸交 | 色婷婷欧美在线播放内射 | 久久久久免费精品国产 | 人妻插b视频一区二区三区 | 欧美黑人巨大xxxxx | 久久久久久a亚洲欧洲av冫 | 人妻无码久久精品人妻 | 久久天天躁夜夜躁狠狠 | 亚洲午夜福利在线观看 | 色偷偷人人澡人人爽人人模 | 国产一区二区不卡老阿姨 | 人妻少妇精品无码专区动漫 | 任你躁在线精品免费 | 午夜精品一区二区三区的区别 | 十八禁真人啪啪免费网站 | 在线亚洲高清揄拍自拍一品区 | 亚洲精品国产精品乱码不卡 | 亚洲一区二区三区四区 | 日本熟妇人妻xxxxx人hd | 中国大陆精品视频xxxx | 精品国产一区二区三区四区 | 丁香花在线影院观看在线播放 | 日本丰满护士爆乳xxxx | 成人无码视频在线观看网站 | 午夜福利一区二区三区在线观看 | 中文字幕乱码人妻二区三区 | 女人被男人爽到呻吟的视频 | 在线视频网站www色 | 一二三四社区在线中文视频 | 久久久www成人免费毛片 | 少妇无码一区二区二三区 | 久久国产精品精品国产色婷婷 | 久久99精品久久久久婷婷 | 男女作爱免费网站 | 亚洲 a v无 码免 费 成 人 a v | 草草网站影院白丝内射 | 免费观看黄网站 | 中文字幕精品av一区二区五区 | 久久久久亚洲精品男人的天堂 | 影音先锋中文字幕无码 | 欧美丰满少妇xxxx性 | 国产激情艳情在线看视频 | 国产精品自产拍在线观看 | 亚洲日韩精品欧美一区二区 | 国产人妻久久精品二区三区老狼 | 国产黑色丝袜在线播放 | 亚洲天堂2017无码 | 九九久久精品国产免费看小说 | 国精产品一区二区三区 | 日韩精品成人一区二区三区 | 久久午夜无码鲁丝片秋霞 | 少妇愉情理伦片bd | 免费无码av一区二区 | 大胆欧美熟妇xx | 麻豆av传媒蜜桃天美传媒 | 人人妻人人澡人人爽人人精品 | 帮老师解开蕾丝奶罩吸乳网站 | 国产成人久久精品流白浆 | 窝窝午夜理论片影院 | 人妻插b视频一区二区三区 | 久久久久成人片免费观看蜜芽 | 奇米影视7777久久精品 | 成人毛片一区二区 | 国产亚洲精品久久久闺蜜 | 樱花草在线播放免费中文 | 午夜成人1000部免费视频 | 国产色在线 | 国产 | 97人妻精品一区二区三区 | 人人妻人人澡人人爽人人精品 | 国产绳艺sm调教室论坛 | 国产性生交xxxxx无码 | 国产成人无码一二三区视频 | 色诱久久久久综合网ywww | 97精品国产97久久久久久免费 | 成 人 网 站国产免费观看 | 最近免费中文字幕中文高清百度 | 午夜无码区在线观看 | 日产精品99久久久久久 | 熟女少妇人妻中文字幕 | 亚洲高清偷拍一区二区三区 | 欧美熟妇另类久久久久久不卡 | 色综合天天综合狠狠爱 | 亚洲日本va午夜在线电影 | 精品无码国产自产拍在线观看蜜 | 无码任你躁久久久久久久 | 漂亮人妻洗澡被公强 日日躁 | 性色av无码免费一区二区三区 | 亚洲中文字幕久久无码 | 免费看男女做好爽好硬视频 | 理论片87福利理论电影 | 亚洲一区二区三区国产精华液 | 国产精品久久久久久久影院 | 天海翼激烈高潮到腰振不止 | 国产精品免费大片 | 少妇高潮喷潮久久久影院 | 4hu四虎永久在线观看 | 亚洲午夜无码久久 | 亚洲色大成网站www国产 | 内射巨臀欧美在线视频 | 久久久精品欧美一区二区免费 | 久久无码中文字幕免费影院蜜桃 | 欧美日韩一区二区免费视频 | 亚洲成a人片在线观看无码 | 高中生自慰www网站 | 精品国精品国产自在久国产87 | 久久久www成人免费毛片 | 国产成人无码av在线影院 | 麻豆蜜桃av蜜臀av色欲av | 亚洲欧洲中文日韩av乱码 | 亚洲日韩一区二区 | 精品久久久无码人妻字幂 | 欧美精品在线观看 | 亚洲啪av永久无码精品放毛片 | 中文字幕无码日韩欧毛 | 精品国精品国产自在久国产87 | 日日摸夜夜摸狠狠摸婷婷 | 秋霞成人午夜鲁丝一区二区三区 | 男女爱爱好爽视频免费看 | 亚洲国产午夜精品理论片 | 欧美丰满熟妇xxxx | 蜜桃臀无码内射一区二区三区 | 欧美肥老太牲交大战 | 精品人妻av区 | 无码av最新清无码专区吞精 | 欧美丰满少妇xxxx性 | 丰满妇女强制高潮18xxxx | 青青青爽视频在线观看 | 国内精品九九久久久精品 | 久久久久人妻一区精品色欧美 | 波多野结衣一区二区三区av免费 | 学生妹亚洲一区二区 | 国产成人精品久久亚洲高清不卡 | 中文字幕人成乱码熟女app | 国产 精品 自在自线 | 久久综合九色综合欧美狠狠 | 日日鲁鲁鲁夜夜爽爽狠狠 | 午夜时刻免费入口 | 4hu四虎永久在线观看 | 亚洲热妇无码av在线播放 | 在线成人www免费观看视频 | 精品偷拍一区二区三区在线看 | 久久熟妇人妻午夜寂寞影院 | 日本乱偷人妻中文字幕 | 无套内谢的新婚少妇国语播放 | 狠狠色丁香久久婷婷综合五月 | www国产精品内射老师 | 亚洲欧美国产精品久久 | 偷窥日本少妇撒尿chinese | 人人妻人人澡人人爽欧美精品 | 久激情内射婷内射蜜桃人妖 | 欧美激情内射喷水高潮 | 亚洲毛片av日韩av无码 | 欧美变态另类xxxx | 免费视频欧美无人区码 | 无码免费一区二区三区 | 一本色道久久综合亚洲精品不卡 | 97资源共享在线视频 | 粉嫩少妇内射浓精videos | 亚洲欧美日韩国产精品一区二区 | 亚洲熟妇色xxxxx欧美老妇y | 无码国模国产在线观看 | 国产亚洲精品久久久久久国模美 | 国产精品二区一区二区aⅴ污介绍 | 国产精品久久国产三级国 | 欧美丰满少妇xxxx性 | 乌克兰少妇xxxx做受 | 狠狠躁日日躁夜夜躁2020 | 日日碰狠狠躁久久躁蜜桃 | 精品熟女少妇av免费观看 | 久久综合九色综合97网 | 好屌草这里只有精品 | 久久久久亚洲精品中文字幕 | 日产国产精品亚洲系列 | 国产激情无码一区二区app | 亚洲精品久久久久久久久久久 | 亚洲精品综合一区二区三区在线 | а天堂中文在线官网 | 精品无码av一区二区三区 | 好屌草这里只有精品 | 偷窥村妇洗澡毛毛多 | 国产精品久久久久9999小说 | 久久五月精品中文字幕 | 色偷偷人人澡人人爽人人模 | 国产色精品久久人妻 | 成人亚洲精品久久久久 | 在线精品国产一区二区三区 | 国产肉丝袜在线观看 | 国产成人无码av一区二区 | 99久久人妻精品免费一区 | 极品尤物被啪到呻吟喷水 | 国产成人精品优优av | 亚洲国产精品一区二区美利坚 | 青草青草久热国产精品 | 亚洲国产欧美日韩精品一区二区三区 | 国产av无码专区亚洲awww | 色综合久久中文娱乐网 | 中文字幕人妻丝袜二区 | 九一九色国产 | 国产精品人妻一区二区三区四 | 国产熟妇另类久久久久 | 粗大的内捧猛烈进出视频 | 国产97在线 | 亚洲 | 精品国产成人一区二区三区 | 少妇高潮一区二区三区99 | 5858s亚洲色大成网站www | 亚洲色欲色欲欲www在线 | 水蜜桃亚洲一二三四在线 | 色一情一乱一伦 | 国产日产欧产精品精品app | 无码帝国www无码专区色综合 | 美女张开腿让人桶 | 精品人妻人人做人人爽 | 国产无av码在线观看 | 亚洲欧美国产精品久久 | 在线亚洲高清揄拍自拍一品区 | 久久久www成人免费毛片 | 色综合久久久无码网中文 | 国产亚洲精品久久久ai换 | 大屁股大乳丰满人妻 | 特黄特色大片免费播放器图片 | 18无码粉嫩小泬无套在线观看 | 亚洲色偷偷男人的天堂 | 强伦人妻一区二区三区视频18 | 激情人妻另类人妻伦 | www成人国产高清内射 | 女人被爽到呻吟gif动态图视看 | 又紧又大又爽精品一区二区 | 国产区女主播在线观看 | 一本久道高清无码视频 | 成人一区二区免费视频 | 精品人妻av区 | 在教室伦流澡到高潮hnp视频 | 国产又爽又黄又刺激的视频 | 日韩精品a片一区二区三区妖精 | 亚洲欧洲无卡二区视頻 | 欧美丰满熟妇xxxx性ppx人交 | 色婷婷综合激情综在线播放 | 亚洲乱码国产乱码精品精 | 少妇无码av无码专区在线观看 | 久久综合香蕉国产蜜臀av | 久久综合给合久久狠狠狠97色 | 精品国产av色一区二区深夜久久 | 成人综合网亚洲伊人 | 福利一区二区三区视频在线观看 | 亚洲精品无码国产 | 天干天干啦夜天干天2017 | 97人妻精品一区二区三区 | 国产精品亚洲а∨无码播放麻豆 | 亚洲一区二区三区在线观看网站 | 精品人人妻人人澡人人爽人人 | 亚洲欧美精品伊人久久 | 免费国产成人高清在线观看网站 | 亚洲七七久久桃花影院 | 国产亚洲欧美在线专区 | 亚洲七七久久桃花影院 | 精品久久综合1区2区3区激情 | 成人亚洲精品久久久久软件 | 秋霞成人午夜鲁丝一区二区三区 | 国产精品嫩草久久久久 | 国产黄在线观看免费观看不卡 | 波多野结衣乳巨码无在线观看 | 扒开双腿疯狂进出爽爽爽视频 | 国产精品人人妻人人爽 | 在教室伦流澡到高潮hnp视频 | 国产香蕉尹人综合在线观看 | 搡女人真爽免费视频大全 | 久久久精品国产sm最大网站 | 亚洲日本一区二区三区在线 | 日日橹狠狠爱欧美视频 | 成年女人永久免费看片 | 亚洲无人区午夜福利码高清完整版 | 熟妇人妻激情偷爽文 | 乱人伦人妻中文字幕无码久久网 | 97无码免费人妻超级碰碰夜夜 | 久久精品女人天堂av免费观看 | 亚洲欧美日韩成人高清在线一区 | 久久99精品久久久久久动态图 | 日日麻批免费40分钟无码 | 老熟女重囗味hdxx69 | 特级做a爰片毛片免费69 | 久久久精品国产sm最大网站 | 人妻与老人中文字幕 | 日韩欧美中文字幕在线三区 | 麻豆国产丝袜白领秘书在线观看 | 波多野结衣一区二区三区av免费 | 免费乱码人妻系列无码专区 | 久久精品女人的天堂av | 成人一在线视频日韩国产 | 亚洲精品综合五月久久小说 | 未满小14洗澡无码视频网站 | 亚洲色欲色欲欲www在线 | 人妻尝试又大又粗久久 | 又大又硬又黄的免费视频 | 在线a亚洲视频播放在线观看 | 欧美日韩一区二区免费视频 | 亚洲国产高清在线观看视频 | 亚洲自偷精品视频自拍 | 成人aaa片一区国产精品 | 思思久久99热只有频精品66 | 人人妻人人澡人人爽欧美精品 | 亚洲精品无码人妻无码 | 国产精品第一区揄拍无码 | 欧美人与动性行为视频 | 中文字幕无码日韩欧毛 | 东京一本一道一二三区 | 女高中生第一次破苞av | 中文字幕无码乱人伦 | 中文字幕乱码人妻二区三区 | 少妇人妻偷人精品无码视频 | 欧美自拍另类欧美综合图片区 | 欧美亚洲国产一区二区三区 | 中文字幕色婷婷在线视频 | 亚洲熟妇色xxxxx欧美老妇y | 国产麻豆精品一区二区三区v视界 | 毛片内射-百度 | 色五月五月丁香亚洲综合网 | 丰满少妇人妻久久久久久 | 免费人成网站视频在线观看 | 免费观看黄网站 | 性开放的女人aaa片 | 亚洲乱码国产乱码精品精 | 日本xxxx色视频在线观看免费 | 波多野结衣高清一区二区三区 | 少妇人妻偷人精品无码视频 | 天堂亚洲免费视频 | 成人无码视频免费播放 | 曰本女人与公拘交酡免费视频 | 99riav国产精品视频 | 国产另类ts人妖一区二区 | 女人被爽到呻吟gif动态图视看 | 色噜噜亚洲男人的天堂 | 国产莉萝无码av在线播放 | 国产一区二区三区精品视频 | 无遮挡国产高潮视频免费观看 | 一本色道久久综合亚洲精品不卡 | 日本www一道久久久免费榴莲 | 日本大香伊一区二区三区 | 精品成在人线av无码免费看 | 国产麻豆精品一区二区三区v视界 | 高潮毛片无遮挡高清免费 | 三级4级全黄60分钟 | 国产手机在线αⅴ片无码观看 | 国产莉萝无码av在线播放 | 131美女爱做视频 | 青春草在线视频免费观看 | 无码av免费一区二区三区试看 | 国产真人无遮挡作爱免费视频 | 97人妻精品一区二区三区 | 美女黄网站人色视频免费国产 | 国产成人人人97超碰超爽8 | 欧美日韩在线亚洲综合国产人 | 中文字幕无码免费久久99 | 真人与拘做受免费视频 | 成人动漫在线观看 | 免费播放一区二区三区 | 亚洲 欧美 激情 小说 另类 | 国产成人无码av一区二区 | 蜜桃av蜜臀av色欲av麻 999久久久国产精品消防器材 | 日本护士xxxxhd少妇 | 国产精品久久福利网站 | 久久久久久a亚洲欧洲av冫 | 色婷婷香蕉在线一区二区 | 精品国产精品久久一区免费式 | 性生交片免费无码看人 | 欧美一区二区三区视频在线观看 | 久久综合九色综合欧美狠狠 | 又紧又大又爽精品一区二区 | 国产精品亚洲一区二区三区喷水 | 国产免费久久精品国产传媒 | 中文字幕乱码人妻二区三区 | 亚洲人成人无码网www国产 | 亚洲精品美女久久久久久久 | 亚洲精品久久久久avwww潮水 | 人妻aⅴ无码一区二区三区 | 成年女人永久免费看片 | 日本大乳高潮视频在线观看 | 亚洲综合色区中文字幕 | 中文字幕 人妻熟女 | 在线欧美精品一区二区三区 | 国产手机在线αⅴ片无码观看 | 激情亚洲一区国产精品 | 亚洲男女内射在线播放 | 久久成人a毛片免费观看网站 | 九九综合va免费看 | 亚洲国产精品久久人人爱 | 久久人人爽人人人人片 | 亚洲乱码中文字幕在线 | 扒开双腿疯狂进出爽爽爽视频 | 久久精品无码一区二区三区 | 免费无码午夜福利片69 | 真人与拘做受免费视频一 | 精品水蜜桃久久久久久久 | 大乳丰满人妻中文字幕日本 | 亚洲色在线无码国产精品不卡 | 人人妻人人澡人人爽欧美一区 | 大肉大捧一进一出好爽视频 | 亚洲人成人无码网www国产 | 国内揄拍国内精品少妇国语 | 亚洲综合精品香蕉久久网 | 久久精品人妻少妇一区二区三区 | 欧美喷潮久久久xxxxx | 国产女主播喷水视频在线观看 | 99精品视频在线观看免费 | 国产情侣作爱视频免费观看 | 精品国产av色一区二区深夜久久 | 动漫av网站免费观看 | 性生交片免费无码看人 | 亚洲综合另类小说色区 | 国产麻豆精品精东影业av网站 | 麻豆人妻少妇精品无码专区 | 日本大乳高潮视频在线观看 | 蜜臀av无码人妻精品 | 国产国产精品人在线视 | 日产精品99久久久久久 | 国产精品无码久久av | 国产亚洲精品久久久久久久久动漫 | 中文无码成人免费视频在线观看 | 综合人妻久久一区二区精品 | 一区二区三区乱码在线 | 欧洲 | 老太婆性杂交欧美肥老太 | 日韩欧美群交p片內射中文 | 色偷偷av老熟女 久久精品人妻少妇一区二区三区 | 国产精品自产拍在线观看 | 日日碰狠狠躁久久躁蜜桃 | 精品夜夜澡人妻无码av蜜桃 | 精品欧美一区二区三区久久久 | 亚洲精品久久久久久一区二区 | 精品国精品国产自在久国产87 | 久久精品无码一区二区三区 | 国产精品第一国产精品 | 精品亚洲韩国一区二区三区 | av无码电影一区二区三区 | 亚洲精品久久久久中文第一幕 | 人人超人人超碰超国产 | 乱人伦人妻中文字幕无码 | 色五月丁香五月综合五月 | 色偷偷人人澡人人爽人人模 | 国产成人无码av片在线观看不卡 | 国产成人久久精品流白浆 | 在教室伦流澡到高潮hnp视频 | 人人超人人超碰超国产 | 国产精品人妻一区二区三区四 | 熟妇女人妻丰满少妇中文字幕 | 国产一区二区三区精品视频 | 亚洲成熟女人毛毛耸耸多 | 亚洲精品美女久久久久久久 | 国产精品福利视频导航 | 国产精品无码一区二区桃花视频 | 特黄特色大片免费播放器图片 | 久久久无码中文字幕久... | 亚洲熟妇自偷自拍另类 | 人妻尝试又大又粗久久 | 国产精品国产自线拍免费软件 | 国产av无码专区亚洲a∨毛片 | 丰满诱人的人妻3 | 久久亚洲中文字幕无码 | 特级做a爰片毛片免费69 | 国产精品第一国产精品 | 精品人妻人人做人人爽夜夜爽 | 久久97精品久久久久久久不卡 | 国产精品99爱免费视频 | 麻豆av传媒蜜桃天美传媒 | 无码一区二区三区在线观看 | 蜜臀av无码人妻精品 | 国产精品a成v人在线播放 | av在线亚洲欧洲日产一区二区 | 午夜无码人妻av大片色欲 | 秋霞特色aa大片 | 色五月丁香五月综合五月 | 无码吃奶揉捏奶头高潮视频 | 无码人妻精品一区二区三区下载 | aⅴ亚洲 日韩 色 图网站 播放 | 老司机亚洲精品影院无码 | 国产精品久久国产三级国 | 日本欧美一区二区三区乱码 | a在线观看免费网站大全 | 国产va免费精品观看 | 国产人妻精品一区二区三区 | 国产精品久久久一区二区三区 | 精品人妻人人做人人爽夜夜爽 | 亚洲毛片av日韩av无码 | 亚洲日韩乱码中文无码蜜桃臀网站 | 麻豆国产人妻欲求不满谁演的 | 窝窝午夜理论片影院 | 4hu四虎永久在线观看 | 色老头在线一区二区三区 | 欧美35页视频在线观看 | 日本一卡2卡3卡四卡精品网站 | 亚洲 激情 小说 另类 欧美 | 久久熟妇人妻午夜寂寞影院 | 国产精品人妻一区二区三区四 | 精品午夜福利在线观看 | 国产另类ts人妖一区二区 | 无码人妻少妇伦在线电影 | 婷婷综合久久中文字幕蜜桃三电影 | 激情内射亚州一区二区三区爱妻 | 亚洲精品午夜无码电影网 | 少妇人妻偷人精品无码视频 | 少妇性l交大片 | 中文无码伦av中文字幕 | 人妻中文无码久热丝袜 | 精品无码av一区二区三区 | 亚洲中文字幕乱码av波多ji | 黑人粗大猛烈进出高潮视频 | 国产精品视频免费播放 | 亚洲精品久久久久久一区二区 | 国产人妻精品一区二区三区不卡 | 国产亚洲美女精品久久久2020 | 玩弄少妇高潮ⅹxxxyw | 亚洲欧美精品aaaaaa片 | 免费观看又污又黄的网站 | www国产精品内射老师 | 色婷婷欧美在线播放内射 | 蜜臀aⅴ国产精品久久久国产老师 | 国内少妇偷人精品视频免费 | 久久97精品久久久久久久不卡 | 成人无码精品一区二区三区 | 国产精品美女久久久久av爽李琼 | 久9re热视频这里只有精品 | 国产亚洲精品久久久闺蜜 | 国产又粗又硬又大爽黄老大爷视 | 国产午夜精品一区二区三区嫩草 | 中文字幕乱码中文乱码51精品 | 综合网日日天干夜夜久久 | 强伦人妻一区二区三区视频18 | 大肉大捧一进一出视频出来呀 | 欧美人与善在线com | 丰满妇女强制高潮18xxxx | 7777奇米四色成人眼影 | 亚洲综合伊人久久大杳蕉 | 日韩精品无码一区二区中文字幕 | 天堂а√在线中文在线 | 日本一卡二卡不卡视频查询 | 在线观看欧美一区二区三区 | 亚洲欧美日韩综合久久久 | 国产亚洲精品久久久闺蜜 | 精品无码一区二区三区爱欲 | 99er热精品视频 | 免费播放一区二区三区 | 亚洲一区二区三区含羞草 | 精品乱码久久久久久久 | 蜜桃av蜜臀av色欲av麻 999久久久国产精品消防器材 | 亚洲午夜久久久影院 | 51国偷自产一区二区三区 | 国产亚洲精品久久久久久国模美 | 国产小呦泬泬99精品 | 国产超级va在线观看视频 | 无码人妻黑人中文字幕 | 国产内射爽爽大片视频社区在线 | 欧洲美熟女乱又伦 | 成人精品一区二区三区中文字幕 | 99久久亚洲精品无码毛片 | 水蜜桃色314在线观看 | 久久精品国产日本波多野结衣 | 久久精品99久久香蕉国产色戒 | 色婷婷av一区二区三区之红樱桃 | 中文字幕人妻无码一区二区三区 | 成人一区二区免费视频 | 香港三级日本三级妇三级 | 色情久久久av熟女人妻网站 | 国产午夜手机精彩视频 | 荫蒂添的好舒服视频囗交 | 亚洲一区二区三区含羞草 | 日韩人妻无码一区二区三区久久99 | 亚洲精品中文字幕 | 久久精品人人做人人综合 | 国产人妻人伦精品1国产丝袜 | 丁香花在线影院观看在线播放 | 欧美亚洲日韩国产人成在线播放 | 成人亚洲精品久久久久软件 | 99麻豆久久久国产精品免费 | 国产乡下妇女做爰 | 又大又硬又爽免费视频 | 中文字幕乱码中文乱码51精品 | 国产精品沙发午睡系列 | 99精品久久毛片a片 | 国产成人精品必看 | 国产av无码专区亚洲a∨毛片 | 久久久www成人免费毛片 | 99久久婷婷国产综合精品青草免费 | 伊人久久婷婷五月综合97色 | 成人女人看片免费视频放人 | 中文毛片无遮挡高清免费 | 美女黄网站人色视频免费国产 | 人人超人人超碰超国产 | 97资源共享在线视频 | 亚洲爆乳大丰满无码专区 | 亚洲va欧美va天堂v国产综合 | 中文精品无码中文字幕无码专区 | 六十路熟妇乱子伦 | 国产内射爽爽大片视频社区在线 | 俄罗斯老熟妇色xxxx | 亚洲精品午夜无码电影网 | 亚欧洲精品在线视频免费观看 | 亚洲va欧美va天堂v国产综合 | 国产乱人伦偷精品视频 | 狠狠色丁香久久婷婷综合五月 | 丰满少妇熟乱xxxxx视频 | 欧美日韩一区二区免费视频 | 亚洲伊人久久精品影院 | 高潮毛片无遮挡高清免费 | 青青青手机频在线观看 | 女人和拘做爰正片视频 | 男人的天堂av网站 | 国产莉萝无码av在线播放 | 久久综合香蕉国产蜜臀av | 亚洲大尺度无码无码专区 | 成年女人永久免费看片 | 国产午夜福利100集发布 | 俺去俺来也www色官网 | 偷窥村妇洗澡毛毛多 | 国产精品va在线观看无码 | 国产精品久久久久9999小说 | 国产偷自视频区视频 | 亚洲精品久久久久中文第一幕 | 性做久久久久久久免费看 | 国产精品爱久久久久久久 | 国产精品亚洲专区无码不卡 | 天堂无码人妻精品一区二区三区 | 青青青爽视频在线观看 | 成人欧美一区二区三区 | 亚洲成av人片天堂网无码】 | 麻豆av传媒蜜桃天美传媒 | 午夜福利电影 | 国产农村妇女高潮大叫 | 97se亚洲精品一区 | 久久亚洲精品成人无码 | 国内精品久久久久久中文字幕 | 中文无码成人免费视频在线观看 | 亚洲精品久久久久中文第一幕 | 成人一在线视频日韩国产 | 欧美一区二区三区视频在线观看 | 无码午夜成人1000部免费视频 | 国产精品久久久av久久久 | 日韩精品久久久肉伦网站 | 精品无码国产一区二区三区av | 成人欧美一区二区三区 | a在线亚洲男人的天堂 | 日韩欧美成人免费观看 | 色五月五月丁香亚洲综合网 | 日韩欧美中文字幕公布 | 99久久精品午夜一区二区 | 国产无遮挡又黄又爽又色 | 亚洲精品一区二区三区婷婷月 | 女人色极品影院 | 国产xxx69麻豆国语对白 | 亚洲色偷偷偷综合网 | 国产精品久久久久久亚洲影视内衣 | 国产成人精品一区二区在线小狼 | 国产精品高潮呻吟av久久4虎 | 亚洲一区二区三区四区 | 国产又爽又黄又刺激的视频 | 丝袜 中出 制服 人妻 美腿 | 国产一区二区三区精品视频 | 四虎影视成人永久免费观看视频 | 少妇高潮喷潮久久久影院 | 精品人妻人人做人人爽夜夜爽 | 精品欧洲av无码一区二区三区 | 大地资源中文第3页 | 久久久精品成人免费观看 | 亚洲成a人一区二区三区 | 任你躁国产自任一区二区三区 | аⅴ资源天堂资源库在线 | 在线欧美精品一区二区三区 | 欧美日韩色另类综合 | 亚洲乱码日产精品bd | 亚洲日韩av一区二区三区中文 | 一区二区传媒有限公司 | a国产一区二区免费入口 | 亚洲区欧美区综合区自拍区 | 久久久中文字幕日本无吗 | 亚洲理论电影在线观看 | 日本护士毛茸茸高潮 | 中文字幕av无码一区二区三区电影 | 日本熟妇人妻xxxxx人hd | 色婷婷综合中文久久一本 | 西西人体www44rt大胆高清 | 大乳丰满人妻中文字幕日本 | 亚洲 a v无 码免 费 成 人 a v | 精品乱码久久久久久久 | 荫蒂被男人添的好舒服爽免费视频 | 狠狠色欧美亚洲狠狠色www | 未满小14洗澡无码视频网站 | 中文无码精品a∨在线观看不卡 | 国产精品欧美成人 | 九月婷婷人人澡人人添人人爽 | 免费国产黄网站在线观看 | 思思久久99热只有频精品66 | 亚洲色大成网站www国产 | 欧美人与禽猛交狂配 | 午夜丰满少妇性开放视频 | 偷窥日本少妇撒尿chinese | 国产精品va在线观看无码 | 国产激情无码一区二区app | 久久精品人妻少妇一区二区三区 | 大乳丰满人妻中文字幕日本 | 亚洲日韩中文字幕在线播放 | 又大又硬又黄的免费视频 | 真人与拘做受免费视频 | 午夜精品一区二区三区在线观看 | 国产一区二区三区影院 | 蜜桃av抽搐高潮一区二区 | 国产乱人伦app精品久久 国产在线无码精品电影网 国产国产精品人在线视 | 成人片黄网站色大片免费观看 | 性色欲网站人妻丰满中文久久不卡 | 国产麻豆精品一区二区三区v视界 | 亚洲精品一区二区三区婷婷月 | 欧美性猛交xxxx富婆 | 国内精品一区二区三区不卡 | 国产一精品一av一免费 | 日本va欧美va欧美va精品 | 日日天日日夜日日摸 | 鲁鲁鲁爽爽爽在线视频观看 | 国产卡一卡二卡三 | 亚洲毛片av日韩av无码 | 国模大胆一区二区三区 | 欧美国产日韩亚洲中文 | 亚洲成在人网站无码天堂 | 色噜噜亚洲男人的天堂 | 久久久国产精品无码免费专区 | 亚洲日本va中文字幕 | 久久97精品久久久久久久不卡 | 丰满岳乱妇在线观看中字无码 | 自拍偷自拍亚洲精品被多人伦好爽 | 精品乱子伦一区二区三区 | 国产精品va在线播放 | 自拍偷自拍亚洲精品10p | 亚洲精品国偷拍自产在线麻豆 | 精品一区二区三区无码免费视频 | 少妇人妻大乳在线视频 | 夜先锋av资源网站 | 国产成人一区二区三区在线观看 | 亚洲精品无码国产 | 人妻有码中文字幕在线 | 亚洲高清偷拍一区二区三区 | 无码av岛国片在线播放 | 国产又粗又硬又大爽黄老大爷视 | √天堂中文官网8在线 | 国产真实乱对白精彩久久 | 日本免费一区二区三区最新 | 国产性生大片免费观看性 | 日本在线高清不卡免费播放 | 国产成人精品一区二区在线小狼 | 精品国产一区二区三区av 性色 | 日韩视频 中文字幕 视频一区 | 色一情一乱一伦一区二区三欧美 | 野外少妇愉情中文字幕 | 国产九九九九九九九a片 | 国产精品资源一区二区 | 久久久国产精品无码免费专区 | 三上悠亚人妻中文字幕在线 | 亚洲综合精品香蕉久久网 | 欧美成人高清在线播放 | 奇米影视7777久久精品 | 亚洲最大成人网站 | 一本加勒比波多野结衣 | 无码成人精品区在线观看 | 少妇激情av一区二区 | 巨爆乳无码视频在线观看 | 国产极品视觉盛宴 | 又大又紧又粉嫩18p少妇 | 国产成人人人97超碰超爽8 | 久久久精品人妻久久影视 | 久久精品国产日本波多野结衣 | 在线播放亚洲第一字幕 | 特级做a爰片毛片免费69 | 精品国产av色一区二区深夜久久 | 人妻无码久久精品人妻 | 精品国产精品久久一区免费式 | 无码人妻丰满熟妇区五十路百度 | 四虎永久在线精品免费网址 | 国产精品久免费的黄网站 | av在线亚洲欧洲日产一区二区 | 亚洲国产精品一区二区第一页 | 亚洲国产精品无码一区二区三区 | 国产精品二区一区二区aⅴ污介绍 | 国产免费无码一区二区视频 | 欧美日韩一区二区免费视频 | 欧美国产日韩亚洲中文 | 欧美丰满少妇xxxx性 | 成熟妇人a片免费看网站 | 日本欧美一区二区三区乱码 | 性欧美牲交在线视频 | 宝宝好涨水快流出来免费视频 | 国产性生交xxxxx无码 | 日本免费一区二区三区最新 | 人人妻人人澡人人爽人人精品 | 久久综合九色综合97网 | 大色综合色综合网站 | 无码毛片视频一区二区本码 | 久久久精品成人免费观看 | 亚洲乱亚洲乱妇50p | 国产精品毛多多水多 | 久久人人爽人人爽人人片av高清 | 国产人成高清在线视频99最全资源 | 老子影院午夜精品无码 | 激情国产av做激情国产爱 | 国产特级毛片aaaaaaa高清 | 国产成人无码区免费内射一片色欲 | 少妇性l交大片 | 色综合久久久无码中文字幕 | 日本大乳高潮视频在线观看 | 久久久久99精品国产片 | 四十如虎的丰满熟妇啪啪 | 性生交片免费无码看人 | 中文字幕色婷婷在线视频 | 欧美性黑人极品hd | 中文精品无码中文字幕无码专区 | 欧美freesex黑人又粗又大 | 亚洲国产精品久久久久久 | 亚洲人成影院在线观看 | 性欧美牲交在线视频 | 性生交大片免费看l | 久久久久成人精品免费播放动漫 | 四虎永久在线精品免费网址 | 伊人久久大香线焦av综合影院 | 亚洲精品一区二区三区四区五区 | 7777奇米四色成人眼影 | 樱花草在线社区www | 久久www免费人成人片 | 东京热一精品无码av | 成人亚洲精品久久久久软件 | 亚洲精品国产精品乱码视色 | 中文无码成人免费视频在线观看 | 性欧美videos高清精品 | 无码中文字幕色专区 | 色欲综合久久中文字幕网 | 国产精品久久福利网站 | 国产精品高潮呻吟av久久 | 人妻体内射精一区二区三四 | 亚洲爆乳精品无码一区二区三区 | 中国大陆精品视频xxxx | 无码国产色欲xxxxx视频 | 亚洲色欲色欲天天天www | 国产三级精品三级男人的天堂 | 兔费看少妇性l交大片免费 | 精品亚洲韩国一区二区三区 | 色一情一乱一伦一区二区三欧美 | 天天做天天爱天天爽综合网 | 久久综合九色综合欧美狠狠 | 日本一区二区三区免费播放 | 国产激情一区二区三区 | 久久99精品久久久久婷婷 | 久久99热只有频精品8 | 精品 日韩 国产 欧美 视频 | 奇米影视888欧美在线观看 | 成人免费视频视频在线观看 免费 | √8天堂资源地址中文在线 | 国产无套粉嫩白浆在线 | 国产精品久久久一区二区三区 | 无遮无挡爽爽免费视频 | 国产福利视频一区二区 | 日日鲁鲁鲁夜夜爽爽狠狠 | 精品久久综合1区2区3区激情 | 国产片av国语在线观看 | 精品厕所偷拍各类美女tp嘘嘘 | 美女黄网站人色视频免费国产 | 高清不卡一区二区三区 | av人摸人人人澡人人超碰下载 | 亚洲精品久久久久中文第一幕 | 无码人妻精品一区二区三区不卡 | 中文无码成人免费视频在线观看 | 亚洲va中文字幕无码久久不卡 | 国产精品久久精品三级 | 波多野结衣 黑人 | 成人精品天堂一区二区三区 | 中文字幕色婷婷在线视频 | 俄罗斯老熟妇色xxxx | 天堂久久天堂av色综合 | 国产成人久久精品流白浆 | 国产精品永久免费视频 | av无码久久久久不卡免费网站 | 乱人伦中文视频在线观看 | 亚洲精品午夜国产va久久成人 | 久久精品丝袜高跟鞋 | 国产9 9在线 | 中文 | 久久zyz资源站无码中文动漫 | 成人欧美一区二区三区黑人免费 | 最近中文2019字幕第二页 | 久久久久久久女国产乱让韩 | 午夜福利一区二区三区在线观看 | 日韩欧美群交p片內射中文 | 国产九九九九九九九a片 | aa片在线观看视频在线播放 | 少妇被黑人到高潮喷出白浆 | 377p欧洲日本亚洲大胆 | 4hu四虎永久在线观看 | √8天堂资源地址中文在线 | 无码国产色欲xxxxx视频 | 人妻天天爽夜夜爽一区二区 | 丰满少妇熟乱xxxxx视频 | 自拍偷自拍亚洲精品10p | 久久99精品久久久久久动态图 | 国产在线精品一区二区三区直播 | 久久综合网欧美色妞网 | 中国大陆精品视频xxxx | 高清无码午夜福利视频 | 精品久久久无码人妻字幂 | 俺去俺来也www色官网 | 窝窝午夜理论片影院 | 国产午夜无码精品免费看 | 国产成人无码a区在线观看视频app | 午夜无码人妻av大片色欲 | 亚洲色欲久久久综合网东京热 | 国产精品美女久久久 | 国产成人无码午夜视频在线观看 | 国产午夜亚洲精品不卡下载 | 亚洲精品久久久久avwww潮水 | 天堂亚洲2017在线观看 | 久在线观看福利视频 | 樱花草在线社区www | 人人爽人人澡人人人妻 | 无码精品国产va在线观看dvd | √8天堂资源地址中文在线 | 水蜜桃色314在线观看 | 亚洲 a v无 码免 费 成 人 a v | 亚洲精品国产精品乱码视色 | 大色综合色综合网站 | 在线欧美精品一区二区三区 | 亚洲狠狠婷婷综合久久 | 最近的中文字幕在线看视频 | 亚洲日韩av一区二区三区中文 | 欧美日本日韩 | 国产特级毛片aaaaaaa高清 | 国产 精品 自在自线 | 亚洲成色在线综合网站 | 国产猛烈高潮尖叫视频免费 | 无遮无挡爽爽免费视频 | 色婷婷av一区二区三区之红樱桃 | 国产片av国语在线观看 | 国产精品亚洲综合色区韩国 | 久久精品国产亚洲精品 | 樱花草在线播放免费中文 | 国产免费无码一区二区视频 | 国产精品va在线观看无码 | 午夜精品久久久久久久久 | 在线精品国产一区二区三区 | 少妇一晚三次一区二区三区 | 亚洲无人区午夜福利码高清完整版 | 台湾无码一区二区 | 天天av天天av天天透 | 午夜福利电影 | 国产卡一卡二卡三 | 日韩精品无码一区二区中文字幕 | 青春草在线视频免费观看 | 双乳奶水饱满少妇呻吟 | 日韩精品成人一区二区三区 | 性史性农村dvd毛片 | 99久久人妻精品免费二区 | 国产成人无码区免费内射一片色欲 | 欧美喷潮久久久xxxxx | 日本丰满护士爆乳xxxx | 午夜福利一区二区三区在线观看 | 国产人妻人伦精品1国产丝袜 | 久久久久久国产精品无码下载 | 亚洲精品国产精品乱码不卡 | 人人妻人人澡人人爽欧美一区 | 亚洲阿v天堂在线 | 亚洲精品一区三区三区在线观看 | 国产电影无码午夜在线播放 | 亚洲精品一区二区三区四区五区 | 狠狠综合久久久久综合网 | 蜜桃无码一区二区三区 | 中文亚洲成a人片在线观看 | 久久久久se色偷偷亚洲精品av | 国产av无码专区亚洲awww | 亚洲综合伊人久久大杳蕉 | 日日碰狠狠躁久久躁蜜桃 | 亚洲欧美日韩成人高清在线一区 | 国产精品久久久久久亚洲影视内衣 | 欧美国产日韩久久mv | 在线 国产 欧美 亚洲 天堂 | 99久久久国产精品无码免费 | 激情内射日本一区二区三区 | 波多野结衣 黑人 | 在教室伦流澡到高潮hnp视频 | 国产偷自视频区视频 | 亚洲无人区午夜福利码高清完整版 | 国产av人人夜夜澡人人爽麻豆 | 狠狠色噜噜狠狠狠狠7777米奇 | 嫩b人妻精品一区二区三区 | 亚洲a无码综合a国产av中文 | 日本一卡2卡3卡4卡无卡免费网站 国产一区二区三区影院 | 亚洲熟悉妇女xxx妇女av | 国产精品亚洲五月天高清 | 国产无遮挡吃胸膜奶免费看 | 国产在线aaa片一区二区99 | 在线播放无码字幕亚洲 | 精品国产一区av天美传媒 | 国产亚洲精品久久久久久大师 | 国产内射老熟女aaaa | 熟女俱乐部五十路六十路av | 国产精品无码永久免费888 | 国产乱码精品一品二品 | 曰本女人与公拘交酡免费视频 | 俺去俺来也www色官网 | 久久国产精品萌白酱免费 | 久久精品国产99久久6动漫 | 大肉大捧一进一出好爽视频 | 国产精华av午夜在线观看 | 无套内谢老熟女 | 日本精品人妻无码免费大全 | 欧美怡红院免费全部视频 | 内射爽无广熟女亚洲 | 国产精品久久久久久久9999 | 水蜜桃亚洲一二三四在线 | 性开放的女人aaa片 | 国内综合精品午夜久久资源 | 国产激情一区二区三区 | 夜夜夜高潮夜夜爽夜夜爰爰 | 好屌草这里只有精品 | 中文无码精品a∨在线观看不卡 | 国内揄拍国内精品少妇国语 | 亚洲熟悉妇女xxx妇女av | 国产区女主播在线观看 | 亚洲乱码国产乱码精品精 | 欧美丰满老熟妇xxxxx性 | 国产三级久久久精品麻豆三级 | 欧洲vodafone精品性 | 伊人久久大香线焦av综合影院 | 国产办公室秘书无码精品99 | 性生交大片免费看l | 国内揄拍国内精品少妇国语 | 亚洲精品一区二区三区在线观看 | 亚洲a无码综合a国产av中文 | 亚洲国产精品一区二区第一页 | 亚洲一区二区三区播放 | 少妇无套内谢久久久久 | 久久人妻内射无码一区三区 | 亚洲の无码国产の无码影院 | 亚洲一区二区三区在线观看网站 | 国产人妻精品午夜福利免费 | 樱花草在线播放免费中文 | 无码人妻少妇伦在线电影 | 爽爽影院免费观看 | 无码毛片视频一区二区本码 | 国产日产欧产精品精品app | 波多野结衣乳巨码无在线观看 | 欧美日韩久久久精品a片 | 色偷偷人人澡人人爽人人模 | 一本久久a久久精品亚洲 | 天天拍夜夜添久久精品大 | 亚洲精品一区二区三区婷婷月 | 大肉大捧一进一出视频出来呀 | 熟女俱乐部五十路六十路av | 日韩成人一区二区三区在线观看 | 日本熟妇浓毛 | 成人女人看片免费视频放人 | 日韩av无码中文无码电影 | 一本久道久久综合婷婷五月 | 全黄性性激高免费视频 | 娇妻被黑人粗大高潮白浆 | 无码国产色欲xxxxx视频 | 国产精品香蕉在线观看 | 亚洲无人区午夜福利码高清完整版 | 色婷婷av一区二区三区之红樱桃 | 久久久久se色偷偷亚洲精品av | 欧美野外疯狂做受xxxx高潮 | 国产亚洲精品久久久久久 | 久久久亚洲欧洲日产国码αv | 国产又爽又猛又粗的视频a片 | 人妻少妇被猛烈进入中文字幕 | 老熟妇仑乱视频一区二区 | 狠狠cao日日穞夜夜穞av | 精品国产av色一区二区深夜久久 |