0%

BASH 筆記

介紹

BASH 是相當 unix 用戶愛用的選擇 shell。有很多方便好用的指令,可以方便日常的工作。
但是有些不常用的指令常常會忘記,這邊主要是加強一下自已的記憶。

這部分參考了Learn bash in Y minutes

我會重新安排一下,這篇會以在命令列直接使用的部分。命令列可以使用的在腳本中也都可以使用。

簡單指令

echo

印出文字,提示訊息。

1
$ echo Hello world!

一行多個指令。

1
$ echo Hello world!; echo "印出第二行。"

變數

定義變數,在後面的指令使用。

1
Variable="Some string"

注意變數的定義,有一定的限制

  1. 不能有空白
  2. 一定是英文字母及底線開頭
  3. 很多特殊字元不能使用
  4. 變數後的’=’之間不能有空白
  5. ‘=’之後也不能有空白
  6. 變數的值如果有空白必須用單引號或是雙引號

使用變數

變數的使用也有些事項要注意。尤其是和引號搭配時。

  1. 不使用引號,可以直接用變數。
  2. 雙引號裡可以使用變數,會代換為變數的值。
  3. 單引號裡的代數不會有作用。

參考下面的例子。

1
2
3
4
5
6
7
bash-3.2$ Variable="Some thing"
bash-3.2$ echo $Variable
Some thing
bash-3.2$ echo "$Variable"
Some thing
bash-3.2$ echo '$Variable'
$Variable

變數和其他字串間的區別

在和其他字串相處時,記得用大括號來和其他字串接,用以分別字串。

1
2
3
4
$ echo ${Variable}abc
Some thingabc
$ echo $Variableabc

字串變數中取代字串

我們可以在使用字串時取代字串.

1
2
echo ${Variable/Some/A}
A thing

注意,其中的 Some 變今了 A。

子字串

我們也可以取字串中的部分

1
2
3
 $ Length=7
$ echo ${Variable:0:Length}
Some th

上面的例子只取了變數字串中的前 7 個。
我們也可以從後面來取字串。

1
2
 $ echo ${Variable: -5}
thing

這個例子我們只取最後5個需要注意的是,在 -5 前面那個空白是必要的,不是我多打的。

字串長度

1
2
 $ echo ${#Variable}
11

變數擴展

1
2
3
 $ OtherVariable="Variable"
$ echo ${!OtherVariable}
Some String

變數預設值

1
2
 $ echo ${Foo:-"DefaultValueIfFooIsMissingOrEmpty"}
DefaultValueIfFooIsMissingOrEmpty

陣列變數

定義陣列

1
$ array0=(one two three four five six)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
bash-3.2$ echo $array0 # 印第一個元素
one
bash-3.2$ echo ${array0[0]} # 印第一個元素
one
bash-3.2$ echo ${array0[@]} # 印全部元素
one two three four five six
bash-3.2$ echo ${#array0[@]} # 印元素個數
6
bash-3.2$ echo ${#array0[2]} # 印第3個元素長度
5
bash-3.2$ echo ${array0[@]:3:2} # 從第四個開始印2個元素
four five
bash-3.2$ for i in "${array0[@]}"; do # 迴圈
echo "$i"
done
one
two
three
four
five
six

大括號擴展

1
2
3
4
 $ echo {1..10} # 印 1 - 10
1 2 3 4 5 6 7 8 9 10
$ echo {a..z}
a b c d e f g h i j k l m n o p q r s t u v w x y z

預設變數取得執行結果字串

1
2
$ echo "I'm in $(pwd)"
$ echo "I'm in $PWD"
  • $PWD 存放的目前目錄位置的路徑。
  • $(pwd) pwd是取得目前路徑的指令,在字串中使用,也會取得目前路徑。

清除 output

1
$ clear

當目前的輸出很雜亂,可以清乾淨,也可以搭配 Ctrl+L 快鍵來達到同樣目的。

變數判斷,分支

1
2
3
4
5
6
7
$ Name=owen
$ if [ $Name != $User ]
then
echo "username 不一樣"
else
echo "名字一樣"
fi

上面的語法沒有錯,不過實務上我們不會用下面的寫法 if [ "$Name" != $USER ] ...
有兩點要注意:

  1. 中括號前後的空白是重要的要特別注意。
  2. 沒有雙引號的變數可能會引發語法錯誤,所以一般我們該加上雙引號,避免語法錯誤。
    當變數是空值時會不正常。要讓指令不出錯需要加上雙引號。

條件執行

除了上面用 if 來進行條件執行,也可以用 ||&& 羅輯的運算進行

1
2
$ echo "永遠執行" || echo "除非前面的指令有錯才會執行"
$ echo "永遠執行" && echo "除非前面的指令沒錯才會執行"
  • || 根據前行指令的執行結果來執行,前行指令正確執行就不會執行後面的指令。
  • && 根據前行指令的執行結果來執行,前行指令正確執行會才執行後面的指令。

||&& 搭配條件,或是複合條件

1
2
3
4
5
6
$ if [ "$Name" == "Steve" ] && [ "$Age" -eq 15 ]; then
echo "Name is Steve and Age is 15"
fi
$ if [ "$Name" == "Daniya" ] || [ "$Name" == "Zach" ]; then
echo "Name is Steve or Zach"
fi

字元匹配

1
2
3
4
$ Email=me@example.com
$ if [[ "$Email" =~ [a-z]+@[a=z]{2,}\.(com|net|org) ]]; then
echo "Valid email!"
fi
  • 注意這兒用到的是兩個方括號,和一般的單方括號是很不一樣的,使用 =~ 時要特別注意。

指令別名

1
$ alias ping='ping -c 4'

可以覆蓋原來的指令,就好像有預設參數一樣。

數字運算

1
$ echo $(( 10 + 5 ))
  • 可以進行 + - * /
  • 注意這兒使用的是雙括號
  • ** 是指數算

ls 指令

  • ls -l 每一行一個結果輸出
  • ls -t 以最後更改時間排序輸出
  • ls -R 遞迴執行,包含子目錄

cat

1
$ cat file.txt
  • 輸出檔案內容到 stdout

我們可以將檔案內容指定到變數

1
2
$ Contents=$(cat file.txt)
$ echo -e "START OF FILE\n$Conents\nEND OF FILE"
  • -e 可以印斷行

cp 指令

1
2
$ cp srcFile.txt clone.txt
$ cp -r srcDir/ dst/
  • -r 目錄遞迴執行,包含子目錄。

cd 指令

  • ~ 家目錄
  • cd 不加參數也是回到家目錄
  • .. 上層目錄
    • 回到上一個目錄

也可以用組合技,將上面的組合起來。

subshell

1
(echo "First, I'm here: $PWD) && (cd ..; echo "Then, I'm here: $PWD") && (echo "Then, I'm here: $PWD)

我們現在還是在原目錄, subshell 中的目錄位置切換,在結束後不會影響原來的執行層的目錄位置。

mkdir

  • -p 我常會搭 -p 的參數,這樣可以不用去檢查要建立的目錄是否存在,而且可以建多層目錄。

cat 建新檔案

有時候在很精簡的系統中,會沒有像 vi 這類的編輯器,安裝也不切實際。
可以用 cat 來建立檔案,只是不能改動比較麻煩。

1
2
3
4
5
6
7
 $ cat > hello.txt << EOF
This is a hello world!
Test multiple lines txt file creation.

Empty Line is ok.
Space in line head is OK.
EOF
  • 其中的 EOF 可以換為其他的標記文字
  • 最後一行的標記一定只能有那個標記文字,不能有空白
  • 從第一行到最後一行前的文字會輸出到檔案。

結論

今天寫不完了,應該還有很多,下次再補完。
還有很多在腳本中 bash 要注意的地方。