sh/bash script 備忘錄 來源:石頭閒語
----
字元

有意義字元

  " "   -  雙引號,括起一個字串,被包括的字元皆作一般字元。
  ' '   -  單引號,意義同雙引號。
  ` `   -  反單引號,執行引號內之指令,並以該指令之輸出結果替換本身。
  ;     -  指令分行。
  &     -  將指令放至背景執行。
  $     -  變數提示字元。
  { }   -  變數名稱與一般字元分隔符號。
  #     -  註解提示字元,其後之內容不視為指令。
  >, >> -  將左式行程之輸出資料,輸入到右式指定設備儲存。
  <, << -  將右式指定設備之輸入資料,輸出給左式行程處理。
  |     -  將左式行程之資料輸出管線,連接到右式行程之資料輸入管線。

通用字元

  *     -  代表零或無限個任意字元。
  ?     -  代表一個任意字元。
  [...] -  代表一個符合字元集正面列表的字元。
  [!...]-  代表一個不符合字元集負面列表的字元。

轉義字元

  \     -  將上述有意義字元,當作一般字元。

----
變數

自定變數

  以 name=value 的格式設定。  等號兩邊若有空格,將被視為name及value
  的一部份。

  欲在指令或字串中引用變數時,在變數名稱前冠上'$'符號,如: $name 。
  若有需要,可以 { } 括起變數名稱,如: ${name} 。

  變數定義後,只在目前之行程空間中可用,若要擴大可見範圍,供其他行程使
  用,則須以 export 指令,將變數匯出至行程之期間(session)中。
  如: export name。

參數變數

  代表傳遞給 shell script 的參數內容的變數,以數字表示, $1 表示第一個
  參數, $2 表示第二個參數,以下類推,最大到 $9 。

  shift 指令將使參數變數向前位移一位,使 $2, $3,... 變為 $1, $2,... ,
  同時,參數的個數亦相對減一。

預先定義變數

  由 shell 所預先定義之變數,常用的預定變數有:
  $?    代表上一個在前景執行的命令之返回值。
  $!    代表上一個在背景執行的命令之PID。
  $@    代表所有的參數。

變數之替換

  語法                  意義
  ------------------------------------------------------------------
  name1=${name2-word}   若變數name2有置值,則以其值替換變數name1的值
                        ,否則以word之內容替換name1之值。
  name1=${name2+word}   若變數name2有置值,則以word之內容替換name1之
                        值,否則不替換。
  name1=${name2?word}   若變數name2有置值,則以name2之值替換name1之值
                        ,否則印出word之內容並跳出shell。
  ${name=word}          若變數name之值為空,則以word之內容替換name之
                        值。

------------
流程控制指令

shell script 以 0 為 true ,非零值為 false 。

1.if
  if expr1; then
    cmd1 block
  elif expr2; then
    cmd2 block
  else
    cmd3 block
  fi

  若 expr1 之值為 true ,則執行 cmd1 ;否則,若 expr2 之值為 true ,則
  執行 cmd2 ;若皆不為 true ,執行 cmd3 。

  elif 及 else 可省略。

  註: then 原本要放獨立一行,但不美觀,故多將其與 if, elif 放在同一行,
      但兩行指令間,要以 ';' 分段。

2.while
  while expr; do
    cmd block
  done

  若 expr 之值為 true ,則執行 cmd 。

3.until
  until expr; do
    cmd block
  done
  
  若 expr 之值為不為 true ,則執行 cmd 。

4.for
  for 變數name; do
    cmd block
  done
  或
  for 變數name in 字串列; do
    cmd block
  done

  順序取字串列之內容為變數name之值,每取一次,則執行一次cmd。
  若字串列省略時,表示取全部參數做為字串列。

5.case
  case 字串 in
    pattern1)
      cmd1 block
    pattern2)
      cmd2 block
    .
    .
    .
  esac

  pattern為 regular expression 。將字串與 pattern 之內容做匹配動作,
  若匹配則執行該 pattern 之動作。

  注意,pattern後要加 ')' 符號。

6.其他

  break     中斷 cmd block 的執行,跳到流程控制指令的下個指令。
  continue  中斷 cmd block 的執行,跳到流程控制指令的開始。
  exit      中斷 shell script 的執行。

------------
test測試運算

1.
  一般使用 [ ] 括起 expression ,括號前後皆要空格。

2.數字比較

  -eq   equal 相等
  -ne   not equal 不等
  -gt   great then 大於
  -ge   geart then or equal 大於或等於
  -lt   little then 小於
  -le   little then or equal 小於或等於

3.字串比較

  =     相同
  !=    不相同
  -z 字串   字串長度為零。
  -n 字串   字串長度不為零。

4.邏輯運算

  -a    And
  -o    Or
  !     Not

5.檔案測試

  -r    readable and existing
  -w    writeable and existing
  -f    regular file
  -t    directory
  -s    Not empty file
  -x    executable
  -u    SetUID
  -g    SetGID

--------
其他指令

1.eval 字串

  解譯並執行字串的內容。

2.exec 命令

  執行命令,該命令將被載入並取代 shell 在行程空間中之位置。

3.read 變數名稱串列

  自標準輸入中謮取一列內容,第一字的內容指定給第一個變數,以下類推。
  當有讀取到資料時, read 返回 true ,否則(遇到eof)返回 false 。
  變數名稱前不用加 '$' 提示。

4.set

  無參數時,顯示各變數的值。若有參數,則將第一個參數置為 $1 ,第二個
  參數置為 $2 ,以下類推。

--------------
資料輸出入管線

在 unix 下,資料被視為位元串流 (術語稱為 streaming) ,而假想在設備間,
存在著一條條的管線 (術語稱為 pipe) ,資料串流就藉由這些管線,在設備間
流動。

當使用者簽入系統後, shell 便會開啟三個虛擬設備做為預設的資料輸出入設
備,此三者為: STDIN, STDOUT, STDERR 。 通常 STDIN 是鍵盤(輸入),
STDOUT 及 STDERR 則為顯示器(輸出)。

由於多數的程式皆由 shell 啟動 (fork + exec),因此也繼承了那三個設備,
故不須特別設定,便可接受來自使用者的鍵盤輸入,將結果輸出至顯示器。

而 shell 提供一種機制,可以改變那三個虛擬設備所連接的實際設備,藉此改
變程式的輸出入目標,這個動作,就像是將管線的一頭,從一個設備改接到另
一個設備,便可讓資料串流導向其他設備,因此一般稱為「重導」。

shell 提供五個符號進行資料的重導,分別是 >, >>, <, <<, | 。

1. >, >>
  此符號可改變程序的 STDOUT 資料輸出串流的方向,符號的左式為要執行的
  程式,而右式必須為一有效的設備。

  例如:
  # who > Onlineuser.txt
  # ps > /dev/null

  若設備為一正規檔案,則檔案原有內容將被清除。欲保留原有內容,則改用
  >> 符號,此符號可讓資料新增在原有內容之後。

  若想將 STDERR 的輸出導向到 STDOUT ,則寫成' 2>&1 ',例如:
  # make 2>&1

  2 是 STDERR 的檔案描述子, 1 是 STDOUT 的檔案描述子。

2. <, <<
  此符號可改變程序的 STDIN 資料輸入串流的方向,符號的左式為要執行的程
  式,而右式必須為一有效的設備。

  例如:
  # adduser < userlist.txt

  下例示範在 script 中,如何將一段文字加入指定檔案中:
  -----------------------------------------------------
  #!/bin/sh
  cat >> test.txt << LABEL
  在此之後的文字,一直到 LABEL 為止的內容,都將被加入指定
  檔案中。
  LABEL

  cat test.txt
  -----------------------------------------------------

3. |
  此符號連接兩程序間的輸出入設備,符號左右兩式則為要執行的程式,執行
  後,左式的程序之 STDOUT 將被連接到右式的程序之 STDIN 。

  例如:
  # ps -ax | more

  ps -ax 將資料送至 STDOUT ,而 more 則將來自 STDIN 的資料內容,做分頁
  顯示,藉由 | 連接兩程序的 STDOUT 及 STDIN 後,便可將 ps -ax 的資料串
  流,直接流向 more 的 STDIN ,而由 more 進行分頁顯示。

  這項重導符號皆可組合使用,例如:
  # dd if=/dev/fd0 bs=1k count=1440 | gzip -9 > disk_image.gz

  dd 從 /dev/fd0 (第一台軟碟機) 設備讀取 1440 KB 的資料,輸出到其
  STDOUT,而 dd 的 STDOUT 連接到 gzip 的 STDIN ,因此 gzip 可由其
  STDIN 中,讀取資料,進行壓縮處理,處理過的資料,再被存入
  disk_image.gz 這個正規檔案中。

--------
相關文件

regular expression (正規運算式或常規表示法)
[Regular Expression Introduction]
http://phi.sinica.edu.tw/aspac/aspac/reports/94/94019/

sed
[Sed Guide]
http://phi.sinica.edu.tw/aspac/aspac/reports/96/96005/

awk
[AWK Tutorial Guide]
http://phi.sinica.edu.tw/aspac/aspac/reports/94/94011/

小恐龍工作坊 提供