---
# System prepended metadata

title: 【教學筆記 02】Linux 指令介紹

---

# 【教學筆記 02】Linux 指令介紹
內容：Linux 指令介紹

---
[目錄](https://hackmd.io/Y7i9O4hCQu6xOJ94__PhNg)

[教學筆記 01：編碼、檔案、斷行字元、Excel、其他基礎知識介紹](https://hackmd.io/7-FajauqT62vXpxOViWzBw)
教學筆記 02：Linux 指令介紹
[教學筆記 03：awk 指令介紹](https://hackmd.io/PHZRjtQMRi2v9Z-u6bD6Tg)
[教學筆記 04：文件圖表表達方式的經驗分享](https://hackmd.io/xVM9lnFBSneA6uhIzdkYyA)
[教學筆記 05：以 C 語言開發資料庫存取程式 (ECPG)](https://hackmd.io/4jh_5A51TfieovVipQqoXA)
[推薦書籍](https://hackmd.io/t7T5FxfmT3Kih-b7PRUZrA)
[補充教材](https://hackmd.io/w-BNpl_TSuysG4_qaGtmFg)

---
## 一、建立 Linux 指令使用環境
- [ ] 1. 裝 Linux 作業系統 (含VM)
- [x] 2. 使用本案乙測環境的 Greenplum Server / Trinity Server
- [x] 3. 裝 git bash (on Windows)
- [ ] 4. 裝 Cygwin (on Windows)
- [ ] 5. 裝 WSL (on Windows)
- [ ] 6. 下載 UnxUtils 工具 (on Windows)

※ 一般 Windows 使用者推薦方法 3、4、5

---
## 二、基本指令
* pwd：顯示目前所在的絕對路徑
```shell script
$ pwd
/c/Users/cfchen
```

* cd：改變目前所在的路徑
```shell script
$ cd Desktop    #進入Desktop目錄
$ pwd
/c/Users/cfchen/Desktop
$ cd            #回到個人HOME目錄 (相當於「cd ~」、「cd $HOME」)
$ pwd
/c/Users/cfchen
```

* env：查看目前所有環境變數
```shell script
$ env
USERDOMAIN=cfchen-PC
OS=Windows_NT
COMMONPROGRAMFILES=C:\Program Files\Common Files
PROCESSOR_LEVEL=6
PSModulePath=C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules\
CommonProgramW6432=C:\Program Files\Common Files
CommonProgramFiles(x86)=C:\Program Files (x86)\Common Files
FP_NO_HOST_CHECK=NO
LANG=C.UTF-8
MSYSTEM_CARCH=x86_64
......(下略)......
```

```shell script
$ env | grep LANG
LANG=C.UTF-8

$ env | grep CLASSPATH
CLASSPATH=.;D:\eclipse\workspace\MyProject\apache-ant-1.7.1\lib\ant.jar;D:\eclipse\workspace\MyProject\commons-cli-1.4\commons-cli-1.4.jar;D:\eclipse\workspace\MyProject\jsch-0.1.48.jar

$ env | grep ^PATH
PATH=/c/Users/cfchen/bin:/mingw64/bin:/usr/local/bin:/usr/bin:/bin:/mingw64/bin:/usr/bin:/c/Users/cfchen/bin:/c/Program Files/AdoptOpenJDK/jdk-8.0.282.8-hotspot/bin
```

* alias：設定指令的別名
    * 若使用 git batch，可在 ~/.bashrc 或 ~/.bash_profile 中進行設定。
    * 若使用 Linux 作業系統，可在 ~/.bashrc 中進行設定。
```shell script
$ alias
alias ll='ls -al'
alias ls='ls -F --color=auto --show-control-chars'
alias wd='cd /d/work/FIA'

$ wd
$ pwd
/d/work/FIA

# 補充：透過 ${BASH_ALIASES} 陣列變數將 alias 作為參數
# 範例：
# 先建立一個 alias，其值為某路徑
$ alias | grep wd2
alias wd2='/d/work/FIA'
# alias 無法直接用來當作參數
$ cd wd2
bash: cd: wd2: No such file or directory
# 但透過 ${BASH_ALIASES} 陣列變數，就可以將 alias 當作參數
$ cd ${BASH_ALIASES[wd2]}
$ pwd
/d/work/FIA


# 範例：尋找當前目錄下的 csv 檔，並輸出到 ll (即 ls -al) 來查詢。
$ echo ${BASH_ALIASES[@]}  # 印出 BASH_ALIASES 陣列變數中的所有元素，功能與「echo ${BASH_ALIASES[*]}」相同
ls -al cd /d/work/FIA ls -F --color=auto --show-control-chars
$ echo ${BASH_ALIASES[ll]}  # 印出 ll 所代表的實際指令
ls -al
$ find . -name "*.csv" -exec ${BASH_ALIASES[ll]} {} \;
-rwxr-xr-x 1 cfchen None   0 十二  6  2017 ./test0n.csv
-rwxr-xr-x 1 cfchen None  11 十二  8  2017 ./test0t.csv
-rwxr-xr-x 1 cfchen None  32 十二 11  2017 ./test1n.csv
-rwxr-xr-x 1 cfchen None  45 十二  8  2017 ./test1t.csv
-rwxr-xr-x 1 cfchen None 308 十二 11  2017 ./test2n.csv
-rwxr-xr-x 1 cfchen None 321 十二  7  2017 ./test2t.csv
-rwxr-xr-x 1 cfchen None 321 十二 11  2017 ./testxt.csv
```

* man：線上說明文件
    * git bash無此功能 (可以改用：**指令名稱 --help**)
    * Linux 作業系統有

* type：顯示程式路徑 (由 $PATH 中尋找)
```shell script
$ type gcc
gcc is /c/Program Files (x86)/mingw-w64/i686-8.1.0-posix-dwarf-rt_v6-rev0/mingw32/bin/gcc

$ type -a gcc
gcc is /c/Program Files (x86)/mingw-w64/i686-8.1.0-posix-dwarf-rt_v6-rev0/mingw32/bin/gcc
gcc is /c/cygwin64/bin/gcc
```


---
## 三、檔案/目錄查詢指令： (檔案/目錄/權限)

| 指令 | 說明 |
| ---- | ---- |
| ls                  | 列出檔案清單 (只列出檔名) |
| ls -al              | 列出檔案清單 (列出所有檔名，並印出詳細資訊) |
| ls -alt \| more     | 列出檔案清單，依檔案修改時間排序(由新到舊)，並逐頁顯示<br>※ more只能往下翻頁<br>※ 目前 git bash 沒有 more 功能，請改用 less |
| ls -altr \| less    | 列出檔案清單，依檔案修改時間排序(由舊到新)，並逐頁顯示<br>※ less可以上下翻頁 |
| ls -al \| grep ^d   | 只列出目錄清單 |
| ls -al \| grep csv$ | 只列出「csv」結尾之檔名<br>※功能與「ls -al *csv」相同 |

參考網址：http://linux.vbird.org/linux_basic/0220filemanager.php#ls

---
## 四、檔案/目錄操作指令：

參考網址：http://linux.vbird.org/linux_basic/0220filemanager.php
| 指令 | 說明 |
| ---- | ---- |
| cp | 複製檔案或目錄<br>語法：cp 來源檔 目標檔 |
| mv | 移動檔案與目錄，或更名<br>語法：mv 來源檔 目標檔 |
| rm | 移除檔案<br>語法：rm 檔案 |
| rm -rf | 強制且遞迴移除檔案或目錄<br>語法：rm -rf 檔案或目錄 |
| mkdir | 建立新目錄<br>語法：mkdir 目錄名稱 |
| rmdir | 刪除「空的」目錄<br>語法：rmdir 目錄名稱 |
| touch | 建立新檔或修改檔案時間<br>語法：touch 檔案 |


* chmod：改變檔案或目錄的權限 (用八進位表示法來代表權限 ==> r:4 w:2 x:1)
    * 語法：chmod [-R] xyz 檔案或目錄
    * 選項與參數：
        * xyz : 數字類型的權限屬性，為 rwx 屬性數值的相加，x/y/z 分別為 owner/group/others 的權限。
        * -R : 進行遞迴(recursive)的持續變更，亦即連同次目錄下的所有檔案都會變更
    * 參考網址：http://linux.vbird.org/linux_basic/0210filepermission.php#chmod

* chown：改變檔案的擁有者
    * 語法：chown [-R] 帳號名稱 檔案或目錄
    * 語法：chown [-R] 帳號名稱:群組名稱 檔案或目錄
    * 選項與參數：
        * -R : 進行遞迴(recursive)的持續變更，亦即連同次目錄下的所有檔案都變更
    * 參考網址：http://linux.vbird.org/linux_basic/0210filepermission.php#chown

* chgrp：改變檔案的群組
    * 語法：chgrp [-R] 群組名稱 檔案或目錄
    * 選項與參數：
        * -R : 進行遞迴(recursive)的持續變更，亦即連同次目錄下的所有檔案、目錄 都更新成為這個群組之意。
    * 參考網址：http://linux.vbird.org/linux_basic/0210filepermission.php#chgrp

---
## 五、檔案描述元、輸出/輸入轉向、管線：
* 檔案描述元 (File Descriptors)
    執行某一指令時，一定會有三個檔案與這個指令有關係。在 Linux shell 中，這三個檔案會用一個整數來表示，我們稱為檔案描述元 (File Descriptors)。

| 名稱 | 說明 | File Descriptors |
| ---- | ---- | -------- |
| STDIN  | 標準輸入    | 0 |
| STDOUT | 標準輸出    | 1 |
| STDERR | 標準錯誤輸出 | 2 |

* 輸出/輸入轉向

| 符號 | 說明 |
| ---- | ---- |
| >  | 輸出轉向       |
| >> | 輸出轉向 (附加) |
| <  | 輸入轉向       |


| # | 指令 | 說明 |
| --| ---- | ---- |
|  1| cmd > file   | 將標準輸出導入檔案         |
|  2| cmd 1> file  | 同上                    |
|  3| cmd >> file  | 將標準輸出附加到檔案之後    |
|  4| cmd 1>> file | 同上                    |
|  5| cmd 2> file  | 將標準錯誤輸出導入檔案      |
|  6| cmd 2>> file | 將標準錯誤輸出附加到檔案之後 |
|  7| cmd < file   | 由檔案中讀取內容當成標準輸入 |
|  8| cmd 0< file  | 同上                    |
|  9| cmd 1> file1 2> file2  | 將標準輸出導入到file1，且標準錯誤輸出導入到file2 |
| 10| cmd > file1 2> file2  | 同上 |
| 11| cmd > file 2>&1  | 將標準輸出與標準錯誤輸出導入到同一檔案中 |
| 12| cmd >> file 2>&1  | 將標準輸出與標準錯誤輸出附加到同一檔案中 |


```shell script
#  有時候我們不想看到標準錯誤輸出，可以將其導向 /dev/null #
$ rm -rf tmp_dir > /dev/null 2>&1; mkdir tmp_dir
```


* 管線 (Pipeline)
    Linux 中大部分的指令，都可以用檔案作為處理的介質，也大部分都可以從標準輸入(STDIN)中讀取輸入值。我們可以利用這種特性，讓許多程式的輸出變成其他程式的輸入，這種將「某程式的輸出轉向變成某程式的輸入」的做法，是由一種稱為「管線」(Pipeline)的機制所達成。

    * 語法：cmd1 | cmd2 | ...
      將 cmd1 的輸出資料連結到 cmd2 的輸入...以此類推。

```shell script
$ cat file | less  #輸出檔案內容，並且分頁顯示
$ cat file | sort  #輸出檔案內容，並且排序
$ sort file | uniq #對檔案內容進行排序，並且輸出不重複的值
```

---
## 六、資料查詢/處理指令：

* cat：印出檔案的內容
    * 語法：cat 檔案1 檔案2 ...
    * 選項與參數：
        * -n ：印出列數
        * -b ：印出列數 (不計算空白列)
    * 參考網址：http://linux.vbird.org/linux_basic/0220filemanager.php#cat

* more (less)：印出檔案的內容，並可每頁閱讀
    * more 只能往下翻頁
    * less 可以上下翻頁
    * 參考網址：http://linux.vbird.org/linux_basic/0220filemanager.php#more
    * 參考網址：http://linux.vbird.org/linux_basic/0220filemanager.php#less

* head：取出檔案/資料前面幾列
    * 語法：head [-n number] 檔案
    * 參考網址：http://linux.vbird.org/linux_basic/0220filemanager.php#head
```shell script
# 產生序列 1~10，但只取出前 3 列 #
$ seq 10 | head -3
1
2
3
```

* tail：取出檔案/資料後面幾列
    * 語法：tail [-n number] [-f] 檔案
    * 選項與參數：
        * -f : 當檔案正在成長時(例如log檔)，輸出所增加的內容。
    * 參考網址：http://linux.vbird.org/linux_basic/0220filemanager.php#tail
    * 參考網址 ：https://linuxhint.com/sed-command-to-delete-a-line/   (利用 sed 限制列數)
```shell script
# 產生序列 1~10，但只取出後 3 列 #
$ seq 10 | tail -3
8
9
10
```

* 如果要取出檔案/資料中間幾列？ ==> 結合 head 與 tail
```shell script
# 產生序列 1~1000，但只取出第 601~603 列 #
$ seq 1000 | head -603 | tail -3
601
602
603
$ seq 1000 | tail -400 | head -3
601
602
603
```
* 如果「不要」取出檔案/資料前幾列？後幾列？
```shell script=
# 不取出第 1 列 (取 2~N 列) #
$ seq 5 | tail -n+2
2
3
4
5

# 不取出最後 1 列 (取 1~N-1列) #
$ seq 5 | head -n-1
1
2
3
4
```



* wc：計算檔案裡面的列數、字數、字元數
    * 語法：wc [-lwm] 檔案
    * 選項與參數：
        * -l ：印出列數
        * -w ：印出字數 (英文單字)
        * -m ：印出字元數
    * 參考網址：http://linux.vbird.org/linux_basic/0320bash.php#wc
```shell script
# 產生序列 2,4,6,8,...,1000，並計算筆數 #
$ seq 2 2 1000 | wc
500     500    1948
$ seq 2 2 1000 | wc -l
500
```

* grep：分析檔案中的每一列內容，若當中有我們所需要的資訊，就將該列印出
    * 語法：grep [-acinvo] '搜尋字串' 檔案
    * 選項與參數：
        * -a ：將 binary 檔案以 text 檔案的方式搜尋資料
        * -c ：計算找到 '搜尋字串' 的次數
        * -i ：忽略大小寫的不同，所以大小寫視為相同
        * -n ：輸出第幾列
        * -v ：反向選擇，亦即顯示出沒有 '搜尋字串' 內容的那一行
        * -o ：僅列印出符合搜尋字串的部分
    * 參考網址：http://linux.vbird.org/linux_basic/0320bash.php#grep
    * 【應用實例】Trinity Decoder + Regular Expression --> 程式碼品質管理制度。
```shell script
# 產生序列 1~50，取出數字中有 0 的 #
$ seq 50 | grep 0
10
20
30
40
50

# 產生序列 1~50，取出數字中不含 2~8 的 #
$ seq 50 | grep -v [2-8]
1
9
10
11
19

# 產生序列 1~50，取出數字為 5 開頭的 #
$ seq 50 | grep ^5
5
50

# 產生序列 1~50，取出數字為 9 結尾的 #
$ seq 50 | grep 9$
9
19
29
39
49

# 只列出目錄清單
$ ls -al | grep ^d

# 利用作業一的資料集 (下載：https://data.gov.tw/dataset/8355 )
# 找出所有「臺北市」的資料：
$ grep "臺北市" 8355.csv
2010,臺北市(Taipei City),164988,11655609954340,7115920545739,2246351110702,855771119711,1437640684350,99098220195,72775434842
2011,臺北市(Taipei City),167653,12163329809495,7493852428587,2316904340647,898202307119,1454240880040,102745610225,77387387579
2012,臺北市(Taipei City),170744,11919483513103,7562067682497,2183535147387,941534418304,1231551629607,101056813365,72488269402
2013,臺北市(Taipei City),173819,12058583782802,7711309282999,2209514369483,1041575123869,1095315637909,109963704927,67796384109
2014,臺北市(Taipei City),177899,12853462046481,8118659924524,2230937138751,1096429765948,1213701692172,128279585053,68245273882
2015,臺北市(Taipei City),182517,12465638326463,8071756625341,2091143638211,1118255119287,1184475629159,141330077594,59647343575
2016,臺北市(Taipei City),186220,12063519560310,7905146270308,1886443346412,977837497831,1222970886083,140988898158,51532820406
2017,臺北市(Taipei City),189965,12418125142973,8220427315333,1984925545837,1082783201286,1129117114195,144789241656,53372837362
2018,臺北市(Taipei City),193424,13081180006541,8603735949350,2055116511218,1151854754058,1270447562753,151066973273,56262153146
2019,臺北市(Taipei City),195736,13403192015313,8825927383860,2005407123013,1263834596392,1308367451511,158798125087,53110156940
2020,臺北市(Taipei City),196897,13672656761171,9152177840748,1897947463677,1313685509984,1308845946762,170324427435,52898866537
```

| 練習1 |
| ---- |
| 一、請先至網址下載資料：https://data.gov.tw/dataset/8355<br>二、利用 shell 指令解決下列問題：<br>(1).請問這個檔案總共有幾列資料？<br>(2).請取出檔案中，年度屬於2019年的資料列(不要合計) |

* cut：
    * 語法1：cut -c 字元區間
        * 適用於以「固定長度」區分欄位的資料格式
    * 語法2：cut -d '分隔字元' -f 指定欄位
        * 適用於以「分隔符號」區分欄位的資料格式
    * 範例1：取出檔案中每列位置 x1~x2 的內容
        * 語法：cut -c x1-x2 檔案
    * 範例2：取出檔案中每列位置 x1~x2 與 x3~x4 的內容
        * 語法：cut -c x1-x2,x3-x4 檔案
    * 範例3：以逗號分隔，取出檔案中每列的第 2 欄
        * 語法：cut -d , -f 2 檔案
    * 範例4：以逗號分隔，取出檔案中每列的第 1,3,4 欄
        * 語法：cut -d , -f 1,3-4 檔案
    * 範例5：以逗號分隔，取出檔案中每列的第 1,3-4 欄，輸出時以"||"分隔欄位
        * 語法：cut -d , -f 1,3-4 --output-delimiter="||" 檔案
    * 參考網址：http://linux.vbird.org/linux_basic/0320bash.php#cut
```shell script
# 範例1：取位置第 1~4 碼(年度)之資料 #
$ cut -c 1-4 8355.csv | tail -3
2020
2020
2020

# 範例2：取位置第 1~4 碼(年度), 6~14 碼(縣市別) 之資料 #
$ cut -c 1-4,6-14 8355.csv | tail -3
2020臺東縣
2020花蓮縣
2020澎湖縣

# 範例3：以逗號分隔，取出檔案中每列的第 2 欄 #
$ cut -d , -f 2 8355.csv | tail -3
臺東縣(Taitung County)
花蓮縣(Hualien County)
澎湖縣(Penghu County)

# 範例4：以逗號分隔，取出檔案中每列的第 1,3,4 欄 #
$ cut -d , -f 1,3-4 8355.csv | tail -3
2020,5406,72612405514
2020,10336,186887750438
2020,2731,32775116184

# 範例5：以逗號分隔，取出檔案中每列的第 1,3-4 欄，輸出時以"||"分隔欄位 #
$ cut -d , -f 1,3-4 --output-delimiter="||" 8355.csv | tail -3
2020||5406||72612405514
2020||10336||186887750438
2020||2731||32775116184
```

| 練習2 |
| ---- |
| 請繼續使用練習1的資料：<br>題目：請取出檔案中，屬於2019年內的所有縣市英文名稱(不要合計) |

* sort：將資料進行排序
    * 語法：sort [-bfnrtuk] 檔案
    * 選項與參數：
        * -b ：參數忽略空白
        * -f ：比較文字時，不分大小寫
        * -u ：將重複出現的資料刪除，只留下一筆
        * -r ：以反向方式排序
        * -t ：指定欄位的分隔字元（預設為空白或tab）
        * -k ：指定欄位的編號 (sort -t, -k2,3 file)
        * -n ：讓資料根據實際數值的大小來排序(但須該欄皆為數字)
    * 參考網址：http://linux.vbird.org/linux_basic/0320bash.php#sort
    * 參考網址：https://blog.gtwang.org/linux/linux-sort-command-tutorial-and-examples/

* uniq：取得不重複(或重複)的資料
    * 語法：uniq [-idDuc] 檔案
    * 選項與參數：
        * -i ：忽略大小寫字元的不同
        * -d ：只輸出重複文字列(重複列只留下一筆)
        * -D ：只輸出重複文字列(重複列維持原狀)
        * -u ：只輸出沒有重複的文字行
        * -c ：刪除重複文字行之後，標示出每一行的重複次數
    * 參考網址：http://linux.vbird.org/linux_basic/0320bash.php#uniq
    * 參考網址：https://blog.gtwang.org/linux/linux-uniq-command-tutorial/

```shell script
$ seq 1 5 > seq1
$ seq 3 7 > seq2
$ cat seq1 seq2 | sort | uniq -d > seq.dup
$ cat seq.dup
3
4
5
$ cat seq1 seq.dup | sort | uniq -u
1
2
$ cat seq2 seq.dup | sort | uniq -u
6
7
```


| 練習3 |
| ---- |
| 請繼續使用練習1的資料：<br>題目：請比較 2010 年與 2011 年的縣市別有什麼差異？ (何者相同？何者不同？) |

| 練習4 |
| ---- |
| 一、本題請先進入乙測 Linux 主機。<br>二、~/.bash_history 是 Linux 作業系統中用來隨時儲存歷史指令的檔案。<br>三、題目：請利用 ~/.bash_history 找出在最近使用的 Linux 指令中，最常被使用的 10 個指令與其次數，並以次數做降冪排序 (只統計指令名稱而不含後面的參數，例如：「ls -al \| grep ^d」則視為 ls 指令就好)<br> ※ 提示：<br>(1).先將 ~/.bash_history 複製到新的檔案(避免檔案一直被更新) <br>(2).先找出第一欄(指令名稱)<br>(3).排序<br>(4).計算次數<br>(5).依據次數+指令名稱再重新排序 |

* diff：比對兩個檔案之間的差異
    * 語法：diff [-bBi] 檔案1 檔案2
    * 選項與參數：
        * -b ：忽略一行當中，僅有多個空白的差異(例如 "about me" 與 "about     me" 視為相同
        * -B ：忽略空白行的差異。
        * -i ：忽略大小寫的不同。
    * 參考網址：http://linux.vbird.org/linux_basic/0330regularex.php#diff
    * 實例可參考 DDL generator 工具所產生的比對結果檔。

```shell script
$ seq 1 5 > seq1
$ seq 3 7 > seq2
$ diff seq1 seq2
1,2d0
< 1
< 2
5a4,5
> 6
> 7
```

* tr：用來替換文字，或是刪除資料中的文字
    * 語法：tr [-ds]... SET1 [SET2]
    * 選項與參數：
        * -d ：刪除訊息當中的 SET1 這個字串
        * -s ：取代掉重複的字元(只取代一次)
    * 參考網址：http://linux.vbird.org/linux_basic/0320bash.php#tr

```shell script
$ seq 8 12 | tr -d 1  #產生序列 8~12，並刪除有 1 的字元
8
9
0

2

$ seq 60 10 100 | tr -s 0 X  #產生序列 60, 70, ..., 100，並將 0 轉為 X
6X
7X
8X
9X
1X

# 注意：使用「tr -d ' '」指令會將資料內的空白都全部刪除。
# 如果只要刪除字串前後的空白，應該改用 sed 工具。
$ echo ' 1 2 3 ' | tr -d ' '
123

$ echo ' 1 2 3 ' | sed 's/^ *//g' | sed 's/ *$//g'
1 2 3

# tr 指令也能幫忙將DOS文件轉換為UNIX/Linux文件
$ cat file | tr -d '\r'

$ dos2unix file          #同上

$ unix2dos file          #將UNIX/Linux文件轉換為DOS文件
```

* od：閱讀非純文字檔 (或將文字轉為非純文字)
    * 範例：將一段文字，以16進位、且每個位元分開顯示。
    echo -n "Hello" | od -A n -t x1
    * 參考網址：http://linux.vbird.org/linux_basic/0220filemanager.php#od
    * 參考網址：https://stackoverflow.com/questions/6791798/convert-string-to-hexadecimal-on-command-line/6791875

```shell script
$ echo -n "Hello" | od -A n -t x1
 48 65 6c 6c 6f
```

---
## 七、vi 編輯器基本操作：

* 參考網址：http://linux.vbird.org/linux_basic/0310vi.php

![](https://i.imgur.com/2wNs40m.gif)


```shell script
搜尋：
於一般指令模式按「/」，輸入「\"」 (搜尋雙引號)

取代：
於一般指令模式按「:」，輸入「%s/,/|/g」(將,變成|)

刪除：
於一般指令模式按「:」，輸入「%s/\"//g」(刪除雙引號)
```

---
## 八、psql / pg_dump 工具介紹 (登入操作/匯出資料操作)
* **psql**：psql is the PostgreSQL interactive terminal.
    * 選項與參數：
        * -U ：database user name
        * -h ：database server host
        * -d ：database name
        * -p ：database server port (default: "5432")
        * -c ：run only single command (SQL or internal) and exit
        * -t ：print rows only
        * -A ：unaligned table output mode
        * -F ：field separator for unaligned output (default: "|")

    * 財稅案甲正環境 Greemplum：
        1. 執行 psql 程式，輸入密碼再進入，然後在裡面查詢與操作：
            語法：```psql -U ap_sbd -h 10.168.2.1 -d dwfdc```
        2. 直接在 shell 中利用 psql 工具匯出資料 (輸入密碼後，將查詢結果輸出至螢幕)：
            語法：```psql -U ap_sbd -h 10.168.2.1 -d dwfdc -c "SQL語法"```

    * 財稅案乙測環境 Greemplum：
        1. 執行 psql 程式，輸入密碼再進入，然後在裡面查詢與操作：
            語法：```psql -d dwfdc```
        2. 直接在 shell 中利用 psql 工具匯出資料 (輸入密碼後，將查詢結果輸出至螢幕)：
            語法：```psql -d dwfdc -c "SQL語法"```

* **pg_dump**：pg_dump dumps a database as a text file or to other formats.
    * 選項與參數：
        * -U：connect as specified database user
        * -d：database to dump
        * -x：do not dump privileges (grant/revoke)
        * -s：dump only the schema, no data
        * -t：dump the named table(s) only  (可使用萬用字元，例如 sbd_bamt\* 表示所有 sbd_bamt 開頭的表格)

    * 財稅案乙測環境 Greemplum：
        語法：```pg_dump dwfdc -x -s -t [schema].[table_name]```


* 於個人筆電的 PostgreSQL 中練習：
    * 先在 PostgreSQL 中建立資料庫：mydb，並於其中建立 schema：stage。
    * 練習之前，請先下載SQL，並在自己的資料庫中執行：https://drive.google.com/file/d/1Vf8tm8E7rk8ZqNjbKTqTNk4MxCpJNhHN/view?usp=sharing
    * 可先在環境變數中設定密碼：PGPASSWORD=xxx。

1. 進入 psql 工具中，就可以開始輸入欲查詢的 SQL：
```shell script
$ psql -h 127.0.0.1 -U postgres -d mydb -p 5432
或
$ psql -h 127.0.0.1 -U postgres -d mydb
# 進入之後，設定預設尋找的 schema 為 stage：
  set search_path = stage;
# 顯示目前預設的 schema：
  show search_path;
```


2. 直接在 shell 中利用 psql 工具匯出資料：
```shell script
$ psql -h 127.0.0.1 -U postgres -d mydb -c "select * from stage.sbd_bamt001_stage"
$ psql.exe -h 127.0.0.1 -U postgres -d mydb -c "select * from stage.sbd_bamt001_stage" > file
```


3. 尋找表格第 2 欄的內容：
```shell script
$ psql.exe -h 127.0.0.1 -U postgres -d mydb -c "select * from stage.sbd_bamt001_stage" | head -16 | tail -14 | cut -d '|' -f 2
```


4. 尋找表格第 2 欄的內容，並去除前後空白：
```shell script
$ psql.exe -h 127.0.0.1 -U postgres -d mydb -c "select * from stage.sbd_bamt001_stage" | head -16 | tail -14 | cut -d '|' -f 2 | tr -d ' '
$ psql.exe -h 127.0.0.1 -U postgres -d mydb -c "select * from stage.sbd_bamt001_stage" | head -16 | tail -14 | cut -d '|' -f 2 | sed 's/^ *//g' | sed 's/ *$//g'
```


5. 尋找表格第 2 欄名稱：
```shell script
$ psql.exe -h 127.0.0.1 -U postgres -d mydb -c "select * from stage.sbd_bamt001_stage" | head -1 | cut -d '|' -f 2
$ psql.exe -h 127.0.0.1 -U postgres -d mydb -c "select * from stage.sbd_bamt001_stage" | head -1 | awk -F '|' '{print $2}'
```


6. 尋找表格有幾欄：
```shell script
$ psql.exe -h 127.0.0.1 -U postgres -d mydb -c "select * from stage.sbd_bamt001_stage" | head -1 | awk -F '|' '{print NF}'
```


7. 控制輸出格式 (不輸出表頭，且以逗號分隔)：
```shell script
$ psql.exe -h 127.0.0.1 -U postgres -d mydb -t -A -F , -c "select * from stage.sbd_bamt001_stage"
```


8. 控制輸出格式，並尋找表格第 2 欄的內容：
```shell script
$ psql.exe -h 127.0.0.1 -U postgres -d mydb -t -A -F , -c "select * from stage.sbd_bamt001_stage" | cut -d , -f 2
```


9. 控制輸出格式，並找表格第 2 欄名稱：
```shell script
$ psql.exe -h 127.0.0.1 -U postgres -d mydb -A -F , -c "select * from stage.sbd_bamt001_stage" | head -1 | cut -d , -f 2
```


10. 控制輸出格式，並尋找表格有幾欄：
```shell script
$ psql.exe -h 127.0.0.1 -U postgres -d mydb -A -F , -c "select * from stage.sbd_bamt001_stage" | head -1 | awk -F ',' '{print NF}'
```

11. 尋找特定證號格式的資料：
在本專案中，對於證號的格式有一定的規範，例如：


| 類型 | 定義 | where clause in PostgreSQL | grep in Linux |
| -------- | -------- | -------- | -------- |
| 1   | 長度為10，第1碼為大小寫英文字母，第2碼為1,2，第3~10碼為數字 (例如：個人身分證號)     | ```~ '^[a-zA-Z][12][0-9]{8}$'```     | ```grep '^[a-zA-Z][12][0-9]\{8\}$'```     |
| 2   | 長度為10，第1 ~ 10碼皆為數字 (例如：大陸人士證號)     | ```~ '^[0-9]{10}$'```     | ```grep '^[0-9]\{10\}$'```     |
| 3   | 長度為7，第1 ~ 7碼皆為數字 (例如：大陸人士證號)     | ```~ '^[0-9]{7}$'```     | ```grep '^[0-9]\{7\}$'```     |
| 4   | 長度為10，第1碼為大小寫英文字母，第2碼為A,B,C,D，第3 ~ 10碼為數字 (例如：新版外僑證號)     | ```~ '^[a-zA-Z][ABCD][0-9]{8}$'```     | ```grep '^[a-zA-Z][ABCD][0-9]\{8\}$'```     |
| 5   | 長度為10，第1 ~ 8碼為數字，第9 ~ 10碼為大小寫英文字母 (例如：舊版外僑證號)     | ```~ '^[0-9]{8}[a-zA-Z]{2}$'```     | ```grep '^[0-9]\{8\}[a-zA-Z]\{2\}$'```     |
| 6   | 長度為10，第1碼為大小寫英文字母，第2碼為8,9，第3 ~ 10碼為數字     | ```~ '^[a-zA-Z][89][0-9]{8}$'```     | ```grep '^[a-zA-Z][89][0-9]\{8\}$'```     |
| 7   | 長度為8，第1 ~ 8碼皆為數字 (例如：公司營利事業登記證)     | ```~ '^[0-9]{8}$'```     | ```grep '^[0-9]\{8\}$'```     |

* 下面以類型 1 為例，尋找 stage.sbd_bamt001_stage 表格的 resp_idn 欄位 (第 21 欄) 中，格式符合「長度為10，第1碼為大小寫英文字母，第2碼為1,2，第3~10碼為數字」的資料：

```shell script
# 在 SQL 中利用 where 條件來尋找
$ psql.exe -h 127.0.0.1 -U postgres -d mydb -t -A -F , -c "select resp_idn from stage.sbd_bamt001_stage where resp_idn ~ '^[a-zA-Z][12][0-9]{8}$'"
A123456789
B246813579

# 在 Linux shell 中利用 grep 指令來尋找 (如果資料來源為檔案，也可以用這個方法)
$ psql.exe -h 127.0.0.1 -U postgres -d mydb -t -A -F , -c "select * from stage.sbd_bamt001_stage" | cut -d , -f 21 | grep '^[a-zA-Z][12][0-9]\{8\}$'
A123456789
B246813579
```


12. 利用 pg_dump 匯出 stage.sbd_bamt001_stage 的 DDL (不含資料)：
```shell script
$ pg_dump -U postgres -d mydb -x -s -t stage.sbd_bamt001_stage
```

| 練習5 |
| ---- |
| 請利用 psql + Linux shell 練習下面的題目：<br>在 stage.sbd_bamt001_stage 中，<br>1. 第 60 欄的欄位名稱為何？<br>2. 印出第 64 欄的欄位名稱、所有內容。<br>3. 請篩選出 resp_idn 欄位 (第 21 欄) 中，格式符合類型 2 的資料內容。<br>4. 請篩選出 resp_idn 欄位 (第 21 欄) 中，格式符合類型 3 的資料內容。<br>5. 請篩選出 resp_idn 欄位 (第 21 欄) 中，格式符合類型 4 的資料內容。<br>6. 請篩選出 resp_idn 欄位 (第 21 欄) 中，格式符合類型 5 的資料內容。<br>7. 請篩選出 resp_idn 欄位 (第 21 欄) 中，格式符合類型 6 的資料內容。<br>8. 請篩選出 resp_idn 欄位 (第 21 欄) 中，格式符合類型 7 的資料內容。<br>9. 利用 pg_dump 匯出 stage.sbd_bamt001_stage 的 DDL 與資料。  |

---

## 九、其他主題與工具

* find
    * 用來搜尋符合特定條件的檔案。
    * 語法：find [PATH] [option] [action]
    * 參考網址：http://linux.vbird.org/linux_basic/0220filemanager.php#find
```shell script
# 範例：尋找當前目錄下(含子目錄)的所有 txt 檔
$ find . -name '*.txt'
./a.txt
./b.txt
./dir/c.txt
./dir/d.txt
# 範例：尋找當前目錄下(含子目錄)的所有 txt 檔，找到之後使用 ls -al 指令查詢
$ find . -name '*.txt' -exec ls -al {} \;
-rw-r--r-- 1 cfchen 197121 0 Jan  3 00:42 ./a.txt
-rw-r--r-- 1 cfchen 197121 0 Jan  3 00:42 ./b.txt
-rw-r--r-- 1 cfchen 197121 0 Jan  3 00:43 ./dir/c.txt
-rw-r--r-- 1 cfchen 197121 0 Jan  3 00:43 ./dir/d.txt
```

* ssh
    * 用來登入遠端主機進行操作；或者是不登入，直接發送指令過去遠端主機。
    * 參考網址：http://linux.vbird.org/linux_server/0310telnetssh.php#ssh
    * 範例1：請遠端主機刪除某檔案
```ssh account@IP_address "rm -rf /path/file"```
    * 範例2：呼叫遠端主機的某支 shell script
```ssh account@IP_address "/path/cmd.sh"```

* sftp
    * 從遠端伺服器下載或上傳檔案
    * 參考網址：http://linux.vbird.org/linux_server/0310telnetssh.php#sftp

```shell script
# 範例1：手動連線
$ sftp cfchen@localhost
cfchen@localhost's password:
Connected to localhost.
sftp> pwd
Remote working directory: /c/Users/cfchen
sftp> lpwd
Local working directory: /c/Users/cfchen
sftp> cd /c/Users/cfchen/sftp/from
sftp> lcd /c/Users/cfchen/sftp/to
sftp> pwd
Remote working directory: /c/Users/cfchen/sftp/from
sftp> lpwd
Local working directory: /c/Users/cfchen/sftp/to
sftp> ls
a.txt  b.txt  dir
sftp> get -r *
Fetching /c/Users/cfchen/sftp/from/a.txt to a.txt
Fetching /c/Users/cfchen/sftp/from/b.txt to b.txt
Fetching /c/Users/cfchen/sftp/from/dir/ to dir
Retrieving /c/Users/cfchen/sftp/from/dir
sftp> lls
a.txt  b.txt  dir
sftp> bye

# 範例2：寫成 shell script (可直接於終端機畫面輸入，或寫成 shell script 檔案再執行皆可)
sftp cfchen@localhost <<END! 1>>sftp.log 2>>sftp.log
pwd
lpwd
cd /c/Users/cfchen/sftp/from
lcd /c/Users/cfchen/sftp/to
pwd
lpwd
ls
get -r *
lls
bye
END!

# 範例3：寫成設定檔 (config file) 再執行 (但本方法僅能在使用金鑰連線的SFTP模式下才能使用)
$ cat sftp.conf
pwd
lpwd
cd /c/Users/cfchen/sftp/from
lcd /c/Users/cfchen/sftp/to
pwd
lpwd
ls
get -r *
lls
bye
$ sftp -b sftp.conf cfchen@localhost 1>>sftp.log 2>>sftp.log
```

* date
    * 顯示或計算日期/時間
    * 語法：date [OPTION]... [+FORMAT]

```shell script
# 顯示目前日期 (西元格式 YYYYMMDD)
$ date '+%Y%m%d'
20211227

# 顯示目前日期 (西元格式 YYYY/MM/DD)
$ date '+%Y/%m/%d'
2021/12/27

# 顯示目前日期時間 (西元格式 YYYYMMDD hhmmss)
$ date '+%Y%m%d %H%M%S'
20211227 141112

# 顯示目前日期時間 (西元格式 YYYY/MM/DD hh:mm:ss)
$ date '+%Y/%m/%d %H:%M:%S'
2021/12/27 14:12:46

# 顯示目前日期的 1 日之前 (西元格式 YYYYMMDD)
$ date -d '-1 days' '+%Y%m%d'
20211226

# 顯示目前日期的 2 日之後 (西元格式 YYYYMMDD)
$ date -d '+2 days' '+%Y%m%d'
20211229

# 顯示目前日期的 1 月之前 (西元格式 YYYYMMDD)
$ date -d '-1 months' '+%Y%m%d'
20211127

# 顯示目前日期的 1 年之前 (西元格式 YYYYMMDD)
$ date -d '-1 years' '+%Y%m%d'
20201227

# 顯示 2021/01/01 的 10 天之前 (西元格式 YYYYMMDD)
$ date -d "20210101 -10 days" '+%Y%m%d'
20201222

# 顯示上個月月底 (西元格式 YYYYMMDD)
$ date -d "`date '+%Y%m01'`-1 days" '+%Y%m%d'
20211130

# 顯示本月月底 (西元格式 YYYYMMDD)
$ date -d "`date '+%Y%m01'`+1 months -1 days" '+%Y%m%d'
20211231

# 顯示目前民國日期 (民國格式 YYYMMDD)
$ expr `date '+%Y%m%d'` - 19110000
1101227

# 顯示目前日期的 1 日之前 (民國格式 YYYMMDD)
$ expr `date -d '-1 days' '+%Y%m%d'` - 19110000
1101226
```

* time
    * 當執行程式時，只要在指令前加上 time，就能計算該程式的執行時間。
    * real: 從開始到結束的總時間
    * user: CPU所花費的運算總時間
    * sys: CPU所花費的在系統(kernel)相關的時間 比如說配置記憶體

```shell script
$ time sleep 3
real    0m3.116s
user    0m0.000s
sys     0m0.061s
```

* iconv
    * 功能：編碼轉換。
    * 語法1：iconv [OPTION...] [-f ENCODING] [-t ENCODING] [INPUTFILE...]
    * 語法2：iconv -l
    * 選項與參數：
        * -l ：list the supported encodings
        * -f ：the encoding of the input
        * -t ：the encoding of the output
        * -c ：discard unconvertible characters

```shell script
# BIG-5 轉 UTF-8
$ iconv -f BIG-5 -t UTF-8 big5.txt > utf8.txt

# UTF-8 轉 BIG-5
$ iconv -f UTF-8 -t BIG-5 utf8.txt > big5.txt
```
| 練習6 |
| ---- |
| 1. 利用 iconv 工具，將練習1的檔案 (8355.csv) 編碼由 UTF-8 改為 BIG-5，再由 BIG-5 改回 UTF-8。 (下載連結：https://data.gov.tw/dataset/8355 )<br>2. 切換一下視窗的編碼設定，確認兩種檔案是否都能順利顯示於螢幕。 |


* nohup
    * 當執行程式時，只要在指令前加上 nohup，就可以讓程式避免因連線中斷而停止。
    * 使用時通常會將該程式設定於背景執行 (在指令的最後面加上「&」)
    * 因為 nohup 在運作時，可能不會輸出結果到螢幕 (因為程式於背景執行)，所以會需要一個檔案來承接程式的輸出訊息，如果我們沒有指定這個檔案的話，nohup 會預設將訊息寫到 nohup.out 檔案裡去。

```shell script
$ nohup ls -al &    # 輸出檔預設為 nohup.out
[1] 104
nohup: ignoring input and appending output to 'nohup.out'

$ nohup ls -al > result &    # 輸出檔為 result
[1] 20656
nohup: ignoring input and redirecting stderr to stdout
```
* ps
    * 顯示目前的程序 (process)。
    * 選項與參數：
        * -e ：所有的 process 均顯示出來。
        * -u ：顯示該使用者相關的 process。
        * -f ：更完整的輸出。
    * 參考網址：http://linux.vbird.org/linux_basic/0440processcontrol.php#ps

```shell script
# 顯示目前所有 process
$ ps -ef
     UID     PID    PPID  TTY        STIME COMMAND
  cfchen   19876   16984 pty0     17:36:32 /usr/bin/ps
  cfchen   16984   14552 pty0     11:47:48 /usr/bin/bash
  cfchen   14552       1 ?        11:47:47 /usr/bin/mintty
```

* kill
    * 刪除程序 (process)
    * 選項與參數：
        * -9 ：強制刪除 process。
    * 參考網址：http://linux.vbird.org/linux_basic/0440processcontrol.php#killjobs

```shell script
# 範例：開啟兩個 git bash 視窗
# 先在第 1 個視窗輸入：
$ sleep 100  #暫停 100 秒

# 然後在第 2 個視窗輸入：
$ ps -ef  # 查詢得知上述 sleep 指令所代表的 PID 為 17960
     UID     PID    PPID  TTY        STIME COMMAND
  cfchen   17960   16984 pty0     17:39:31 /usr/bin/sleep
  cfchen   16984   14552 pty0     11:47:48 /usr/bin/bash
  cfchen   17560   19208 pty1     17:37:47 /usr/bin/bash
  cfchen   19208       1 ?        17:37:47 /usr/bin/mintty
  cfchen    1524   17560 pty1     17:39:59 /usr/bin/ps
  cfchen   14552       1 ?        11:47:47 /usr/bin/mintty
  
$ kill 17960  # 接著刪除 sleep 指令的 process
```


* 單引號 (```'```)、雙引號 (```"```)的差異


| 字元 | 功能 |
| -------- | -------- |
| 單引號<br>(Single quote) | 所有夾在單引號之間的字元都會失去它們的特殊涵義     |
| 雙引號<br>(Double quote) | 大部分夾在單引號之間的字元會失去它們原先的特殊涵義，除了下列類型以外：<br>(1). ```$``` 符號 (作為變數替換)<br>(2). 作為指令替換的反引號(``` ` ```)<br>(3). ```\$``` (代表 ```$``` 本身)<br>(4). ``` \` ``` (代表 ``` ` ``` 本身)(反引號)<br>(5). ```\"``` (代表 ```"``` 本身)(雙引號)<br>(6). ```\\``` (代表 ```\``` 本身)    |
| 倒斜線<br>(Backslash) | 任何接在倒斜線之後的字元，會失去該字元原先的特殊涵義     |


* 反引號 (``` ` ```)
    * 用來做指令代換。
    * 可以容易地使用指令輸出，指定給 shell script 的變數。
    * 語法：``` `cmd` ```

```shell script
# 範例1：產生一個檔名具有目前日期的檔案
$ DATE=`date '+%Y%m%d'`
$ touch filename.${DATE}.txt
$ ls -al filename*
-rw-r--r-- 1 cfchen 197121 0 Dec 27 20:01 filename.20211227.txt

# 範例2：產生一個檔名具有筆數的檔案
$ COUNT=`psql.exe -h 127.0.0.1 -U postgres -d mydb -t -A -F , -c "select count(*) from stage.sbd_bamt001_stage"`
$ psql.exe -h 127.0.0.1 -U postgres -d mydb -t -A -F , -c "select * from stage.sbd_bamt001_stage" > sbd_bamt001_stage_${COUNT}.txt
$ ls -al sbd_bamt001_stage_*
-rw-r--r-- 1 cfchen 197121 10730 Jan  3 11:47 sbd_bamt001_stage_14.txt

# 小觀念：設定變數時，變數前面不用加 $，讀取時才要加 $ (讀取時有沒有加 {} 都可以)
$ MY_VAR=12345
$ echo ${MY_VAR}
12345
$ echo $MY_VAR
12345

```


| 練習7 |
| ---- |
| 一、請先至網址下載資料：https://data.gov.tw/dataset/120711 <br>(下載 csv 檔，並另存檔名為「cov19.csv」)。 <br>二、利用 shell 指令解決下列問題：<br>(1).請問這個檔案總共有幾列資料？(包含表頭與內容)<br>(2).請取出檔案中，屬於境外移入的資料列 (若為境外移入時，「縣市」與「鄉鎮」必為空值，「是否為境外移入」必為是)。<br>(3).請取出檔案中，縣市鄉鎮欄位為新北市永和區的資料列。<br>(4).請問至今有多少個縣市鄉鎮曾經有出現確定病例數？ (請先排除表頭與境外移入)<br>(5).請問至今為止的累計確定病例數。<br>※ 提示：利用 awk 指令協助數字的累計。<br>※ 語法：```awk -F ',' '{sum+=$8;} END{print sum;}'```<br>(6).請問至今為止，境外移入的累計確定病例數。<br>(7).請問至今為止，本土的累計確定病例數 (本土 = 非境外移入)。<br>(8).請問2021年5月期間，新北市永和區的累計確定病例數。<br>(9).請依照各縣市鄉鎮為單位，計算其累計確定病例數，並由高至低降冪排序。<br>※提示：利用 awk 指令做群組的累計。<br>※語法：```awk -F ',' '{sum[$3" "$4]+=$8} END{for(key in sum) print key, sum[key];}'```<br> |

---
## 作業四
* **作業檢討時間：預訂於 2022/01/21 (五)。**

![](https://i.imgur.com/dhfm9iG.png)

* 請開發一個乙測環境 Trinity 原始碼備份工具 (作為異地備援)
* 設計方法：
    * 需要使用時，先由個人電腦/筆電以 putty 工具連線至乙測 Trinity Server (192.168.32.107)，並執行備份程式 (backup_work.sh)。
    * 備份程式會做以下的工作：
        * 匯出 Trinity Job 原始碼備份檔，檔名為 [Category]_yyyymmdd.gz。
        * 請每個 Category 分別產生一個 gz 檔。須備份的 Category 包含：BASE_INIT, BASE, MULTI_TAX_INIT, MULTI_TAX, STAGE_INIT, STAGE, STS_INIT, STS, UT_BASE_INIT, UT_BASE, UT_MULTI_TAX_INIT, UT_MULTI_TAX, UT_STAGE_INIT, UT_STAGE, UT_STS_INIT, UT_STS。
        * sftp 至乙測 Greemplum Server (192.168.32.104)，並上傳備份檔 (密碼用手動輸入)。
        * 記錄執行資訊於log檔案中，包含：**執行起始日期時間、執行結束日期時間、備份檔名、本次備份檔案數量 (即 gz 檔的總數量)**。
        * 備份程式 (backup_work.sh) 請放置於乙測 Trinity Server 的「/home/trinity/homework4/個人目錄」路徑中。
        * 備份檔案請放置於乙測 Greemplum Server 的「/home/gpadmin/homework4/個人目錄」路徑中。
    * Trinity 原始碼匯出功能：
        * 參考文件「Trinity V4.1 JFDesigner User Guide.pdf」(p.102)，參考章節：Import/Export Util 使用說明。
        * 指令使用方式：
            * 語法：java -jar /home/trinity/tool/ImportExportCMD-4.1.1.244.jar -export -host 192.168.32.107 -port 18087 -u [帳號] -pwd [密碼] -b [business entity] -c [category]
            * 參數：
                * -host：uiap service ip address (default:127.0.0.1)
                * -port：uiap service port (default:19001)
                * -u：trinity user id
                * -pwd：trinity user password
                * -b：business entity name
                * -c：category name
* 對於非本專案，無法進入乙測環境之成員，請自行建立 Linux主機練習 (找家澤設定)：
![](https://i.imgur.com/IOtUdh5.png)
* shell script 參考範例：https://drive.google.com/file/d/1a4zxSYe_9QsVK2hBv5FEF07TvD5Eit8R/view?usp=sharing


---
## 練習解答

* 練習1(解答)：
```wc -l 8355.csv```
```grep ^2019 8355.csv | grep -v "合  計"```

* 練習2(解答)：
```grep ^2019 8355.csv | grep -v "合  計" | cut -d, -f2 | cut -d'(' -f2 | cut -d')' -f1```
```grep ^2019 8355.csv | grep -o "(.*)" | grep -v Total  #但會包含括號```
```grep ^2019 8355.csv | grep -o "(.*)" | grep -v Total | tr -d '(' | tr -d ')'```

* 練習3(解答)：
```grep ^2010 8355.csv | grep -v "合  計" | cut -d , -f 2 > 2010.txt```
```grep ^2011 8355.csv | grep -v "合  計" | cut -d , -f 2 > 2011.txt```
```sort 2010.txt 2011.txt | uniq -d > dup  #共同```
```cat 2010.txt dup | sort | uniq -u  #only 2010```
```cat 2011.txt dup | sort | uniq -u  #only 2011```

* 練習4(解答)：
```cut -d ' ' -f 1 .bash_history_new | sort | uniq -c | sort -n -k1,2 -r | head -10```
說明：1.找出第一欄(指令名稱) 2.排序 3.計算次數 4.依據次數+指令名稱再重新排序 5.取出前面10筆)

* 練習5(解答)：
1. 第 60 欄的欄位名稱為何？
```psql.exe -h 127.0.0.1 -U postgres -d mydb -A -F , -c "select * from stage.sbd_bamt001_stage" | head -1 | cut -d , -f 60```
2. 印出第 64 欄的欄位名稱、所有內容。
```psql.exe -h 127.0.0.1 -U postgres -d mydb -A -F , -c "select * from stage.sbd_bamt001_stage" | cut -d , -f 64```
3. 請篩選出 resp_idn 欄位 (第 21 欄) 中，格式符合類型 2 的資料內容。
```psql.exe -h 127.0.0.1 -U postgres -d mydb -t -A -F , -c "select * from stage.sbd_bamt001_stage" | cut -d , -f 21 | grep '^[0-9]\{10\}$'```
4. 請篩選出 resp_idn 欄位 (第 21 欄) 中，格式符合類型 3 的資料內容。
```psql.exe -h 127.0.0.1 -U postgres -d mydb -t -A -F , -c "select * from stage.sbd_bamt001_stage" | cut -d , -f 21 | grep '^[0-9]\{7\}$'```
5. 請篩選出 resp_idn 欄位 (第 21 欄) 中，格式符合類型 4 的資料內容。
```psql.exe -h 127.0.0.1 -U postgres -d mydb -t -A -F , -c "select * from stage.sbd_bamt001_stage" | cut -d , -f 21 | grep '^[a-zA-Z][ABCD][0-9]\{8\}$'```
6. 請篩選出 resp_idn 欄位 (第 21 欄) 中，格式符合類型 5 的資料內容。
```psql.exe -h 127.0.0.1 -U postgres -d mydb -t -A -F , -c "select * from stage.sbd_bamt001_stage" | cut -d , -f 21 | grep '^[0-9]\{8\}[a-zA-Z]\{2\}$'```
7. 請篩選出 resp_idn 欄位 (第 21 欄) 中，格式符合類型 6 的資料內容。
```psql.exe -h 127.0.0.1 -U postgres -d mydb -t -A -F , -c "select * from stage.sbd_bamt001_stage" | cut -d , -f 21 | grep '^[a-zA-Z][89][0-9]\{8\}$'```
8. 請篩選出 resp_idn 欄位 (第 21 欄) 中，格式符合類型 7 的資料內容。
```psql.exe -h 127.0.0.1 -U postgres -d mydb -t -A -F , -c "select * from stage.sbd_bamt001_stage" | cut -d , -f 21 | grep '^[0-9]\{8\}$'```
9. 利用 pg_dump 匯出 stage.sbd_bamt001_stage 的 DDL 與資料。
```pg_dump -U postgres -d mydb -x -t stage.sbd_bamt001_stage  # 不要寫 -s```

* 練習6(解答)：
```iconv -c -f UTF-8 -t BIG-5 8355.csv > 8355_big5.csv```
```iconv -c -f BIG-5 -t UTF-8 8355_big5.csv > 8355_utf8.csv```

* 練習7(解答)：
1. 請問這個檔案總共有幾列資料？
* ```wc -l cov19.csv```
2. 請取出檔案中，屬於境外移入的資料列。
* ```grep "空值" cov19.csv > 境外移入.txt```
* ```awk -F ',' '{if($6=="是") print $0}' cov19.csv > 境外移入.txt```
3. 請取出檔案中，縣市鄉鎮欄位為新北市永和區的資料列。
* ```grep "新北市,永和區" cov19.csv > 新北市永和區.txt```
* ```awk -F ',' '{if($3=="新北市" && $4=="永和區") print $0}' cov19.csv > 新北市永和區.txt```
4. 請問至今有多少個縣市鄉鎮曾經有出現確定病例數？ (請先排除表頭與境外移入)
* ```tail -n+2 cov19.csv | grep -v "空值" | cut -d , -f 3,4 | sort | uniq | wc -l```
5. 請問至今為止的累計確定病例數。
* ```awk -F ',' '{sum+=$8;} END{print sum;}' cov19.csv```
* ```tail -n+2 cov19.csv | awk -F ',' '{sum+=$8;} END{print sum;}'```
6. 請問至今為止，境外移入的累計確定病例數。
* ```tail -n+2 cov19.csv | grep "空值" | awk -F ',' '{sum+=$8;} END{print sum;}'```
* ```awk -F ',' '{if($6=="是") print $0}' cov19.csv | awk -F ',' '{sum+=$8;} END{print sum;}'```
7. 請問至今為止，本土的累計確定病例數。
* ```tail -n+2 cov19.csv | grep -v "空值" | awk -F ',' '{sum+=$8;} END{print sum;}'```
* ```awk -F ',' '{if($6=="否") print $0}' cov19.csv | awk -F ',' '{sum+=$8;} END{print sum;}'```
8. 請問2021年5月期間，新北市永和區的累計確定病例數。
* ```grep "新北市,永和區" cov19.csv | grep "2021/05" | awk -F ',' '{sum+=$8;} END{print sum;}'```
* ```awk -F ',' '{if($3=="新北市" && $4=="永和區" && substr($2,1,7)=="2021/05") print $0}' cov19.csv | awk -F ',' '{sum+=$8;} END{print sum;}'```
9. 請依照各縣市鄉鎮為單位，計算其累計確定病例數，並由高至低降冪排序。
* ```tail -n+2 cov19.csv | awk -F ',' '{sum[$3" "$4]+=$8} END{for(key in sum) print key, sum[key];}' | sort -n -r -k3```


---

* 補充1：date 日期計算功能 (如上)

* 補充2：Git bash 提供的工具：**bash.exe**
    * 位置：C:\Program Files\Git\bin\bash.exe
    * 功能：協助在 Windows 作業系統中執行 shell 檔案。
    * 語法：bash.exe [欲執行的shell檔案] [參數1] [參數2] ...


* 補充3：crontab
    * 功能：例行性工作排程工具。 (git bash 無此功能)
    * 語法：crontab [-l|-e|-r]
    * 選項與參數：
        * -e ：編輯 crontab 的工作內容。
        * -l ：查閱 crontab 的工作內容。
        * -r ：移除所有的 crontab 的工作內容，若僅要移除一項，請用 -e 去編輯。
    * 參考網址：https://linux.vbird.org/linux_basic/centos7/0430cron.php#cron

```shell script
# 範例：在每天的凌晨 1:00 執行 /home/trinity/backup_work.sh 作業
$ crontab -e
# 此時會進入 vi 的編輯畫面，每項工作都是一列
0  1  *  *  * /home/trinity/backup_work.sh

$ crontab -l
0  1  *  *  * /home/trinity/backup_work.sh
```

* 補充4：簡略查詢一下在彙總表SDM文件中，有哪些格式為「#XXXX#」的變數名稱？
```grep -o '#.*#' file | sort | uniq -c```

---
