學習bash

lzprgmr發表於2013-06-22

工作8年,前6年基本是Windows環境下,也就是個滑鼠黨;兩年前換工作開始用linux,也就開始了領略了命令列的強大,無論是直接在命令列組合命令,也還寫幾行簡單的shell指令碼,其能完成的功能往往令人難以置信。

如果說我工作中第一次感覺“哇”是08年左右開始使用perl處理文字 - 發現指令碼原來可以如此強大,自動化那麼多工作;那麼第二次就應當是使用bash - 原來不用寫指令碼也能如此強大。(尤其對原Windows下滑鼠+選單黨來講)

這兩天比較系統的看了下bash reference manual,記錄一下。

一、命令列互動

這裡包括兩個部分,一個是readline支援的命令列編輯功能,有不同的編輯style:emacs和vi模式:

  • set -o emacs
  • set -o vi

用vi模式的話,使用vi一些常用的命令,編輯起來自然方便,但是需要先escape一下進入操作模式。但是對於平時99%的工作,一些常用的快捷鍵已經足夠滿足了:

  • C-a, C-e:移動到行首,行尾
  • Alt->, Alt-<-:前移,後移一個單詞 (最好自己定義成右alt,額,好像是我的右alt鍵壞掉了。。。)
  • C-b, C-f:前移,後移一個字元
  • C-l:清空螢幕
  • C-w:刪除前一個單詞
  • Alt-d:刪除後一個單詞
  • C-d:刪除當前字元
  • C-y:貼上前次刪除內容

這些快快捷鍵是readline的預設定義,一般在/etc/inputrc可以找到系統全域性定義,然後個人可以定義:~/.inputrc

另一部分是歷史管理,下面是一些要點:

  • 控制歷史的一些變數:HISTSIZE,HISTFILE,HISTFILESIZE
  • 設定HISTTIMEFORMAT='%F %T '在歷史中顯示命令執行時間
  • C-r:查詢歷史並執行
  • history expansion
    • !! - 上一條命令
    • !preceding - 上一條以preceding開始的命令
    • !$ - 上一個命令的最後一個引數
    • !n - 第n個命令
    • !-n - 倒數第n個命令

 

二、語法

1. 五種quoting

  • \A:轉義,保持字元原意,如果在行末,則表示續行
  • 'string':single quoted string,不進行轉義,變數expansion
  • “string”:double quoted string,進行轉義,變數expansion
  • $'string':訪問一些特殊字元,如$'\a', $'\n'
  • $"string":locale specific translation, translated according to the current locale

2. 註釋

以#開頭的行均為註釋,除了第一行:

#!/bin/bash

3. 控制結構

  • 簡單命令:cmd
  • pipeline: cmd1 | cmd2
  • 命令序列:
    • cmd1; cmd2: 順序執行兩條命令
    • cmd1& cmd2:並行執行兩條命令,其中cmd1在後臺執行
    • cmd1 && cmd2: 如果cmd1成功了,執行cmd2
    • cmd1 || cmd2:如果cmd1失敗了,執行cmd2
  • 迴圈控制
    • until test-commands; do consequent-commands; done
    • while test-commands; do consequent-commands; done
    • for name [ [in [words …] ] ; ] do commands; done
    • for (( expr1 ; expr2 ; expr3 )) ; do commands ; done - 例子:for ((i=1; $i < 100; i++)); do echo $i; done
  • 條件控制
    • if
      if的測試表示式有三種情況:-x表示檔案或者變數測試;(==, !=, >, <)表示字串測試;(-gt, -lt, -eq, -ne, -ge)等表示數字測試。
    • if後測試的表示式可以有三種:
      • [[ expression ]]
      • [ expression ]
      • test expression
    • if test-commands; then
        consequent-commands;
      [elif more-test-commands; then
        more-consequents;]
      [else alternate-consequents;]
      fi
    • case
      case word in [ [(] pattern [| pattern]…) command-list ;;]… esac
      
      echo -n "Enter the name of an animal: "
      read ANIMAL
      echo -n "The $ANIMAL has "
      case $ANIMAL in
        horse | dog | cat) echo -n "four";;
        man | kangaroo ) echo -n "two";;
        *) echo -n "an unknown number of";;
      esac
      echo " legs."
    • select
      select name [in words …]; do commands; done
      
      select fname in *;
      do
          echo you picked $fname \($REPLY\)
          break;
      done
  • 命令組合
    • 新起shell:( list )
    • 當前shell:{ list; }

4. 函式

 

語法
name () compound-command [ redirections ]
or
function name [()] compound-command [ redirections ]

定義
function reverse() {
    echo $3-$2-$1
}

呼叫
echo `reverse hello world thanks`

 

5. 引數

引數有指令碼的引數、函式的引數,都是用$1-$9等來訪問, $0表示指令碼或者函式名字,這些叫做positional parameters,還有一些特殊的引數:$*, $@, $#, $?, $-等等

6. Shell expansion

  • brace expansion: echo a{b, c, d}e
  • tilde expansion: cd ~; cd ~user/bin
  • shell parameter expansion: ${parameter}, , ${parameter:-word}.${parameter:=word}
  • command expansion: $(cmd) or `cmd`
  • arithmetic expansion: $((1+2*6))
  • word splitting
  • filename expansion: *.txt
  • quote removal

7. Redirection

  • >: write stdout to file
  • >>: append stdout to file
  • &>: write stdout and stderr to file
  • &>>: append stdout and stderr to file
  • tee: ls | tee ls.txt

8. Variable & array

# variable
x=5
echo $x

#array:
arr[0]=100
echo ${arr[0]}

#associate array:
declare -A map
map[hello]=world
echo ${map[hello]}

 

三、內建命令與變數

builtin的命令,用help就可以全部打出來, 然後逐個help就可以看到大致介紹。

有兩個主要的設定命令:

  • set
  • shopt

控制bash的各種行為模式。

但有個eval命令我有點搞不清楚:

$ help eval
eval: eval [arg ...]
Execute arguments as a shell command.

Combine ARGs into a single string, use the result as input to the shell,
and execute the resulting commands.

Exit Status:
Returns exit status of command or success if command is null.

這個,與沒有eval,直接run命令有什麼區別呢?搜了一下,發現這麼個例子:

for i in 2 3 4; do
 eval a$i=2
 eval echo "\$a$i" 
done

動態組合變數名字並賦值,這個在shell裡直接是做不到的。

另外,三類比較常用的命令:

  • 別名:alias, unalias
  • job控制:jobs, fg, bg, kill, C-z
  • 目錄管理:dirs, popd, pushd

 

內建的變數,主要用來控制行為,或者暴露資訊,臂長常用的有PATH, PS1, PS2, PWD, HOSTNAME, HISTFILE, IFS, CDPATH(這個貌似可以好好利用一下)

 

四、常用非內建命令

這裡指的是非bash內建命令,但是linux內建的,或者另外安裝的一些常用命令,非常有效,這裡列幾個自己用的比較多的:

du
df
strace
lsof
ps aux
netstat
grep
find
wget
curl
tr
ssh
sort
uniq
awk
wc

cut
top
free
vim
p4
perl -pei

相關文章