UNIX是一種多用戶、多工的作業系統,提供不同的使用者能夠同時在一台主機上進行各種項目服務。Linux是建構在UNIX上開發出來的核心,Ubuntu是以Linux為核心所發行的一套作業系統
可以想成UNIX是猩猩,Linux是演化後的智人(兩者能力不相同,有上下關係),而Ubuntu是白種人,Debian是黃種人,Redhat是黑種人(有相同基本能力,但是用不一樣的外觀或套件服務)
Application > Shell > Kernal
kernal: 核心,作業系統的最底層,負責和硬體溝通和真正執行我們的指令(更改記憶體,跟螢幕說要印出什麼東西)
shell: 負責將我們的輸入(也就是指令)轉換成kernal看得懂的語言,ex: gcc
,ls
,chmod
application:將這些指令包裝成一般的應用程式,如各種軟體、app,都是由一連串的指令或程式碼轉換成人容易操作的圖形界面
Workstation
系上的工作站大多使用Linux發行版之一的Debian,只要有電腦和網路,就能透過ssh連上工作站。SSH(Secure Shell Protocol),是一種安全的網路協定,提供我們遠端連到伺服器的服務
如何連到工作站
在Windows的cmd或是Mac/Ubuntu的terminal輸入
$ ssh <account>@<IP address>
比方說要連到meow1的話就是
$ ssh b09901133@meow1.csie.ntu.edu.tw
或$ ssh b09901133@meow1.csie.org
當然也可以更改ssh config,這樣的話只要打
$ ssh meow1
就能連上去了,或是寫一個shell script執行ssh的指令,這樣就不用每次連工作站都打一長串了
ssh key
注意到每次連工作站都要打密碼,如果不想打密碼的話可以按照以下步驟:
1.$ ssh-keygen
生成ssh key
2.之後terminal會跳出Enter file in which to save the key (~/.ssh/id_rsa)
問你key要存在哪裡,直接按enter會存在預設的位置
3.Enter passphrase (empty for no passphrase):
如果輸入的話,之後登入就要輸入passphrase,直接enter,就不用輸入
4.$ ssh-copy-id <account>@<IP address>
並且輸入你的密碼確認,這樣之後就可以用ssh key登入了
登出工作站的話,輸入$ exit
或$ logout
即可
Linux檔案路徑
~
: home,家目錄,也就是登入系統後進入的目錄
/
: root directory,根目錄,所有目錄的開始
.
: working directory,當前目錄
..
: parent directory,上一層
對於一個檔案系統,只有一個根目錄,對於一個使用者,只有一個家目錄(ex: b09901133的家目錄是/home/student/09/b09901133
)
絕對路徑: 以/
開頭,表示從根目錄開始
相對路徑: 以./
開頭,表示從當前目錄開始,而一般如果不寫的話就是預設從./
開始
以下介紹幾個常見的目錄
/bin
: 可執行檔
/dev
: 週邊設備
/lib
: 函式庫
/etc
: 系統設定
/home
: 家目錄
/usr
: 軟體資源
/tmp
: 暫存檔
/var
: 動態數據
以下介紹幾個常用的指令
pwd
: print working directory,印出現在所在的目錄
ls
: list,列出本目錄
常用參數有:
-a
(all) 列出包含隱藏檔案的所有檔案(隱藏檔案檔名開頭會有.
)-l
(long listing) 用清單格式列出,可以看到檔案的權限、時間戳、檔名、大小-t
(time) 依照最後編輯時間列出-h
(human readable) 用好讀的方式印出$ ls dir/ 列出./dir下的所有檔案 $ ls -al 列出當前目錄的所有檔案,用清單方式列出,包含隱藏檔
cd
: change directory,前往指定的目錄$ cd 回到家目錄 $ cd ~ 回到家目錄 $ cd /home/student/10 到/home/student/10這個目錄 $ cd .. 到上一層目錄 $ cd / 到根目錄
上傳/下載檔案
sftp
ssh file transfer protocol
$ sftp b09901133@linux1.csie.ntu.edu.tw
登入之後:
$ get <remote-path> [local-path] 從remote-path下載到local-path
$ put <local-path> [remote-path] 從local-path上傳到remote-path
$ cd 移動遠端路徑
$ ls 查看遠端資料
如果要上傳或下載整個目錄的話,要加上-r
wget <URL>
World Wide Web get
$ wget http:example.com
$ wget -O hi.html http:example.com
下載檔案,檔名為hi.html
$ wget -O - http:example.com
下載檔案,並且當作文字檔案輸出到terminal
相似的指令有curl
,預設是把檔案內容直接輸出到terminal:
$ curl <url>
產生的結果類似 $wget -O - <url>
Terminal小技巧
tab鍵
按tab可以自動補足指令或目錄或檔案名稱,但是遇到多個可能會停在分岔點,連按兩次可以列出所有可能性
上下鍵
可以回到上一個指令/下一個指令
萬用字元(*)
代表零或不限個數個任何字元
ex: abc.c
跟aabbcc
都是*c
複製/貼上/刪除
在terminal中,複製是 ctrl+shift+C
,貼上是ctrl+shift+V
,刪除的話是ctrl+W
(刪除一個字)和ctrl+U
(整行刪除)
clear
: 清空目前畫面
ctrl+C
: 中止目前程式
ctrl+D
: 在stdin中代表EOF,windows中則是ctrl+Z
exit
: 離開terminal,包括ssh連上工作站或是sftp連上工作站或是自己開一個terminal的時候都可以這樣離開terminal
alias
: 設定或印出指令的別名,如果自己想要個人化一些指令的話可以使用這個
$ alias ll 告訴你執行ll的時候實際上執行什麼
$ alias md="mkdir -p" 設定執行md是執行mkdir -p
cheat.sh
: 用$ curl cheat.sh/<command name>
可以看到command的常見用法,個人認為比man好用一點
man <command name>
: manual,可以看到指令的詳細用法
檔案管理與操作
cp
: copy,複製檔案,被複製的在前,複製出的在後,可以用路徑指定複製出的東西的位置,要複製整個目錄要-r
$ cp <file1> <file2> 在當前目錄將file1另存新檔為file2
$ cp <file> dir/ 將file複製到某個目錄當中
$ cp -r dir1/ dir2/ 將dir1內的所有東西複製到dir2
mv
: move,移動或重新命名一個檔案或目錄
$ mv dir1/ dir2/ 如果dir2不存在就將dir1重新命名為dir2,否則將整個dir1移動到dir2裡面
$ mv <file1> dir1/ 將檔案file移動到目錄dir裡面
$ mv <file1> <file2> 將檔案file1重新命名為file2
rm
: remove,永久移除檔案
常用參數:
-r
: 遞迴的移除某個目錄以及其底下的所有檔案目錄-f
: 強制移除,系統不會一一詢問(預設是系統會一一詢問是否要移除掉這個檔案)-d
: 移除掉空的目錄$ rm <file> 將file移除 $ rm -f *.c 將當前目錄以.c為結尾的所有檔案移除 $ rm -rf dir/ 將dir目錄下所有檔案移除 $ rm -rf * 將當前目錄所有檔案移除
mkdir
: make directory,建立新目錄
常用參數-p
: (parent),如果需要的話,將parent directory一起新增$ mkdir dir/ 新增dir目錄 $ mkdir -p dir1/ dir2/ 在dir1裡新增dir2目錄,如果dir1不存在,就順便新增dir1
rmdir
: 刪除空的目錄,跟$ rm -d
一樣
touch
: 點擊/戳一個檔案,如果不存在的話就建立它,可以用來改變時間戳
$ touch <file> 新增file,或是改變file的時間戳
檔案與目錄權限
因為Linux是一個多人、多工的作業系統,因此對於一個檔案或目錄,需要去規定不同使用者知簽的權限。而在Unix-Like的作業系統中,我們會將一個檔案/目錄的權限針對擁有者(user)、同群組使用者(group)、和其他用戶(group)分為以下三種:
r
(read),讀取檔案,讀取目錄內部的檔案條目(ls
)
w
(write),修改檔案,修改目錄屬性(ex: 名稱),並新增、刪除、更名目錄內的檔案
x
(execute),執行檔案,進入該目錄內部(cd
)
chmod
: change mode,改變檔案/目錄的權限
$ chmod [ugo][+-][rwx] <file|dir/> 通式: 將[人]對file|dir [增減] [某權限]
$ chmod +rw <file> 將全部人對file新增讀寫權
$ chmod u+x <file> 新增自己對file的執行權
$ chmod go-r <file> 移除同群組和其他人對file的讀取權
將rwx想成二進位,r = 4, w = 2, x = 1,沒有該權限為0
$ chmod 700 dir/ 目錄權限: drwx------,d代表這是一個directory
$ chmod 644 <file> 檔案權限: -rw-r--r--,因為不是一個directory,所以沒有d這個參數
find [path] [option] [expression]
搜尋指令,只是要花比較久的時間,可以依照權限、擁有者、群組、檔案類型、日期與大小等條件來搜尋
常用參數:
-name
: 指定檔名搜尋-perm <mode>
: 搜尋檔案權限為mode的檔案-exec <command>
: 將搜尋出的結果,使用其他指令再處理$ find ~ -name lost 在~下搜尋lost,預設為當前目錄 $ find -perm 777 -exec chmod 755 {} + 將權限為777的檔案都設為755
本地相關指令
passwd
: password,變更密碼,一般是可以用GUI設密碼的,但如果沒有GUI的話,這個指令其實還不錯好
sudo
: superdoer,以superuser的權限執行指令,在工作站上不能用,有些跟安全性或系統內部的指令需要有superdoer的權限才能進行動作
$ sudo apt-get install vim 安裝vim
#apt-get是一個安裝套件的指令
工作管理
process簡介
process是程序,又稱行程、進程,是執行中的程式,每個程序會有一些屬性:
- PID 程序獨特的識別碼
- UID 產生這個程序的使用者
- NICE 一個程序的友好程度,介在-20跟19之間,值越大,代表這個程序的執行優先度越低,越不會跟別人搶系統資源
ps
: process status,查看程序的狀態
常用參數:
-l
: 詳細列出程序的資訊aux
: 查看系統上的所有程序$ ps -l $ ps aux
kill
: 可以結束指定PID的程序
常用參數:
-9
: 強制結束
$ kill 204 結束pid為204的程序
htop
: 圖形化界面的程序管理員,可以查看執行中的程序,系統資源用量
CPU
htop最上方會列出各CPU的使用率,這邊顯示的是CPU的邏輯核心數(我也看不懂),譬如電腦有四核心八執行緒,意思是可以同時執行八個thread,那這邊就會顯示八個CPU
而這個使用率的bar會有三種顏色,每個顏色有各自代表的意義
- 紅色: 代表kernal thread佔用的CPU,像是系統需要自動做process scheduling、memory management等等,是系統中最重要、優先權最高的任務
- 綠色: 代表normal priority thread,優先度比kernal thread低,一般使用者的程式沒有特別調優先權的話,會被歸在這一類
- 藍色: 代表low priority thread,優先權比較低,分配到的CPU也比較少,如果CPU很滿或是memory真的不夠用了,第一個kill掉的也是這類程序
Memory & Swp
它的顏色也是有意義的
- 綠色: 被process佔用的記憶體,比方說瀏覽器、terminal、htop
- 藍色: buffer pages,譬如說當你第一次
ls -l
的時候系統會去硬碟撈這個資料夾有哪些檔案、每個檔案的權限,然後存在buffer pages,這樣短時間再ls -l
的時候就不用再進入硬碟(因為進入硬碟比較慢),直接從buffer拿即可 - 橘色: cache pages,跟buffer很像,只不過buffer存metadata,cache存檔案內容,像第一次下
cat index.js
就會把內容讀取到cache pages,如果cat之後發現檔案太長,只要看前十行就好,那再下head -n 10 index.js
就會從cache pages直接讀取
記憶體使用量並非越低越好,畢竟閒在那邊也沒什麼用,不如讓系統把閒置的部份拿去當buffer跟cache,這樣就可以盡量不碰硬碟,執行速度更快
swap的機制跟buffer還有cache相反,如果memory快不夠了,系統會把記憶體裡面一些東西swap到硬碟上,等真的需要再拿回來,缺點是程式速度會比較慢
Load Average
首先Tasks欄位的488, 1994 thr; 3 running
代表目前總共有488個process、1994個thread,其中3個thread正在執行
Load Average是用來判斷目前系統有多忙,三個數字代表系統在最近一分鐘、五分鐘、十五分鐘內,平均有多少個thread需要CPU
PID/USER
PID是每個process的ID,可以用kill -KILL <pid>
來殺掉某個process,或用kill -STOP
來暫停process然後用kill -CONT
讓它繼續執行
USER就是把這個process跑起來的人,不管程式是誰寫的,只要是我把它跑起來,USER就會顯示我的名字
PRI & NI
Priority跟Nice都是跟優先權有關的指標,注意數字越小表示優先權越高,可以分配到更多CPU,PRI是由系統決定的,無法自行更改,Nice預設是0,可以用renice -n 19 -p <pid>
調整到最低優先權19,調高的話最高可以調到-20
雖然nice值可以自行調整,但系統不一定會根據nice來分配優先權,有些完全只根據PRI系統根本不在乎Nice
VIRT/RES/SHR
Virtual Memory,Resident,Shared Memory
Virtual Memory可以把它想成process可以存取到的memory總和,譬如說head -n index.js
運作的方式就是把index.js打開,然後讀取前十行,雖然只讀取前十行,但head process已經把檔案打開了,它其實有權限access到整個檔案,所以virtual memory會把整個檔案的大小算進去
Resident是物理上佔用了多少記憶體,如果只讀取前十行,那系統就只把前十行從硬碟讀進記憶體,Resident也只算那十行
因此在htop裡Resident一定遠小於Virtual Memory
Shared Memory是可以跟別人分享的memory,像程式時常用的glibc,或是在讀取read-only檔案時,這些東西只要讀進記憶體一次就好了,所以會被算進SHM裡面
State
- R: process正在跑或是在running queue裡等待CPU排程
- S: 目前正在睡覺,有事做才會醒來
- D: 這個也是在睡覺,只不過等待的一定是IO,譬如說讀取檔案、寫入資料庫等等
CPU%/MEM%
CPU%意思是在這段時間平均用了幾顆CPU,因為htop預設3秒更新一次,假如前1.5秒用了一顆,後1.5都沒用,那平均就是50%,如果這3秒用好用滿四個核心,那就是400%
因為CPU%是很短期的數據,所以當電腦當當的時候,看CPU%就可以知道是誰在霸佔CPU
MEM%也很類似,是使用記憶體的比例,並且使用Resident來計算,所以如電腦配有4GB的記憶體,某個process的Resident是1GB,那就是用掉實體記憶體的25%
Time+
代表的並不是程式從啟動到現在總共經過了多久,而是這個程式總共佔用了多少CPU Time
因此如果想知道長期而言哪個程式最佔CPU的話,就看Time+的數值,如果是看短期、目前正在暴衝的程式,就看之前提到的CPU%
常用參數:
-u
只顯示特定使用者的程序-p
只顯示特定的程序-s
將程序按照特定資訊欄排序
$ htop -u b09901133 查看b09901133的程序資訊
$ htop -s USER 將程序照使用者排序
ctrl+Z
: 暫停目前的程序
jobs
: 列出目前terminal中的程序,包含在背景執行或暫停的
$ jobs -l 列出這個terminal裡面的程序,並且附上PID
文字/輸出處理
cat
: Concatenate,串接並輸出一個以上的檔案的內容。參數-n
可以在每一行加上行號
$ cat <file1> <file2> <file3> 串接file1、file2、和file3輸出
$ cat -n <file> 將file每行前都加入行號輸出
$ cat *.c 將所有.c檔都串接在一起輸出
less
: 跟cat類似,不過比較像是閱讀器的功能,可以一頁一頁讀(空白鍵)或是一行一行讀(上下鍵),可以按q
離開或是/
或?
搜尋
head / tail
: 顯示檔案的前面幾行或最後幾行,預設是10行,可以用-n num
或-num
指定行數
$ head *.c -n 5 顯示檔案結尾為.c的前5行
$ tail file[1-5] -13 顯示file1-file5的末13行
wc
: word count,計算一個檔案內的行數(line)/字數(word)/字元數(char),不加參數就是分別顯示以上三者,如果加上一個以上的參數則輸出指定的內容
$ wc <file> 顯示三種資訊(line/word/char)
$ wc -l <file> 顯示行數
$ wc -wc <file> 顯示字數與字元數
管線命令 pipeline
對於每個參數,都會有一個標準輸入(STDIN)、標準輸出(STDOUT)、標準錯誤輸出(STDERR),代表的數字分別是0,1,2
redirect: output(>, >>), pipe(|), input(<)
>
把STDOUT(如指令、程式結果)寫入新檔案(如果檔案名稱已經存在就覆蓋)
>&
把STDOUT+STDERR寫入新檔案(如果檔案名稱已經存在就覆蓋)
2>
把STDERR寫到檔案(如果檔案名稱已經存在就覆蓋)
>>
把STDOUT結果接續在檔案的尾端(如果檔案不存在就建立)
$ ./a.out > hello
$ ./a.out >> hello
|
管線字元可以將左邊指令或程式的輸出(stdout)變成右邊指令的輸入(stdin) 可以很方便的將不同指令寫在同一行
$ ./a.out | less
注意這個跟>
不同的地方在於>
是將output寫到檔案,而|
則是將output當作另一個指令的stdin
兩者左邊都是接受一個指令或程式,但>
右邊一定是檔案,|
右邊則是另一個指令或程式
<
相較於>
是把右邊檔案當作左邊指令的標準輸出(stdout),<
則是把右邊檔案當作左邊指令的標準輸入(stdin),兩者可以連用
$ ./a.out < input > output
echo
: 輸出文字,不搭配重導向使用就會直接輸出到stdout
$ echo Welcome to Foresight Camp 2021 \OWO/
$ echo hello judgegirl > hello
$ echo hello world >> hello
diff
: difference,比較兩個檔案不同的地方,如果前面有pipe的話可以把一個設成-
代表該檔案
$ diff sample_output my_output
$ ./a.out | diff sample_output -
$ diff < (./a.out < in.txt) out.txt
sort
: 將檔案內容以行為單位根據字典序排序並輸出(不會更改檔案本身)
常用參數:
-r
: reverse,反向排序-f
fold lower case to upper case,忽略大小寫差異-n
numerical value,按照數值大小排序
$ sort data
$ sort data > sorted_data
uniq
: unique,以行為單位,將檔案中相鄰且重複的內容刪除到只剩一行並輸出(例如有連續五行內容完全一樣,就把四行刪掉),並不會更改檔案本身,常搭配sort使用
常用參數:
-c
: count,進行計數-i
: ignore case,忽略大小寫差異-u
: unique,只輸出完全沒有相鄰重複的
$ sort data | uniq > unique_file
$ sort data | uniq -u > uniq_file
簡易正規表達式(Regular Exxpression, Regex)
主要是拿來match一個字串有沒有符合特定規則
*
: 前面的字出現任意次數(包含0次)
+
: 前面的字出現一次以上
?
: 前面的字出現0次或1次
.
: 一個任意字元
\
: 跳脫字元,把接在後面的字當作一般字元使用
[]
: 代表任一括號內的字元
^
: 代表字串的開始位置
$
: 代表字串的結束位置
ex:
AC\.c
AC.c (前後還可以加東西)
AC?\.c
AC.c以及A.c (前後還可以加東西)
AC*\.c
A.c, AC.c, ACC.c ... (前後還可以加東西)
AC[1-3]\.c
AC1.c、AC2.c、AC3.c (前後還可以加東西)
^AC\.c
AC.c AC.cpp AC.csv ... (後面還可以加東西)
AC\.c$
AC.c, AAC.c, BAC.c ... (前面還可以加東西)
AC_.*\.c
.*
可以是任何內容,可以代表AC_123.c, AC_ac.c等等
Shell中的萬用字元*
在正規表達式中相當於.*
,也就是任意字元出現任意次數的意思
grep
: global regular expression print,從檔案中(沒有檔案就是stdin)找出符合指定字串的那些行並輸出,字串可以不用加引號,或是用regex的語法加引號(只是記得加上-E)
$ grep A+ student_grades | wc -l 從student_grades中計算A+的人數
$ grep B10902* workstation_usage | sort | unique -c 從workstation_usage中,找出B10的使用者,在排序後輸出每人使用次數
$ ls -l /nfs/undergrad/10 | grep -E "^d[rwx]r" 看家目錄有開可以讀的權限的B10
sed
: stream editor,文字串流編輯器,語法是s/origin/replace/g
,一個斜線都不能少(s代表substitute,g代表global,不加g代表取代遇到的第一個origin)
$ cat letter > sed 's/love/hate/g' 把love用hate取代
$ car spaces > sed 's/^ *//g' 去除行首空白
壓縮/解壓縮
- zip 檔
- 加上
-e
代表加密壓縮$ zip -r <name.zip> dir/ -r 把dir裡面所有檔案壓縮成name.zip $ unzip <name.zip> -d dir/ 把name.zip的檔案解壓丟到dir $ zip -r 2021.zip 2021_code/ -r -e $ unzip 2021.zip
- tar 檔: 只有打包,沒有壓縮
$ tar cvf <FileName.tar> dir/ 打包 $ tar xvf <FileName.tar> 解包
- tar.gz 檔
$ tar zcvf <FileName.tar.gz> dir/ 壓縮 $ tar zxvf <FileName.tar.gz> 解壓縮
gcc
: GNU Compiler Collection,Unix-like作業系統的標準編譯器,在工作站上寫C的程式可以用gcc
將原始碼編譯成執行檔
常用參數:
-o name
: 自訂執行檔名字 預設為a.out-g
讓產生的執行檔可以用GDB debug-Dxxx
可以定義程式裡的xxx(關鍵字: ifdef endif)-O[n]
可以做出不同等級的優化,n = 0 ~ 3, 常用是-O2
-Wall
顯示所有警告訊息(沒有初始化的變數、重複宣告的變數、沒被使用的變數等等),debug比較容易知道錯在理-std=c99
等號後面為指定編譯器標準
$ gcc 12345.c
$ gcc problemA.c -o AA -O2 -Wall -std=c11
$ gcc defpractice.c -Ddef
執行檔案
在Linux系統,對於檔案或目錄名稱沒有特殊要求,所以不用像在Windows終需要.exe副檔名代表它的檔案格式,如果想要執行名為filename的檔案,只要在前面打./
即可
$ ./filename
可執行的檔案在用ls
列出時,檔名會呈現綠色且檔名後面顯示*
time
: 替某個指令/程式計時,會有三種時間(real/user/sys),評估程式效率是看user time,real time可能因為工作站忙碌而被拉長
- real time: 程式從執行開始到執行結束在錶上相差的時間
- user time: 程式碼不需要消耗系統資源的部份所使用的CPU時間
- system time: 程式碼需要消耗系統資源的部份所使用的CPU時間
- user time + system time: 不一定會小於/等於/大於real time
$ time wc problem[1-9].c
$ time ./a.out < sample_input
make
: 搭配makefile使用
$ make
$ make clear
tmux
: 終端機的多工器,可以同時跑好幾個程式,也可以把程式丟到背景跑,輸入tmux
就可以開始使用了,如果tmux不用了,exit
即可,否則ctrl+B+D
可以回到原本的terminal
常用的有:
tmux ls
看現在有哪幾個在跑
tmux attach -t x
其中x是session編號,可以直接進去那個session,而attach可以直接打a就好