河北seo技術(shù)東莞百度seo
acwing-Linux課上的筆記
acwing-Linux網(wǎng)址
文章目錄
- 1.1常用文件管理命令
- homework作業(yè)測評命令
- 2.1 簡單的介紹tmux與vim
- vim
- homework
- tmux教程
- vim教程
- homework中的一些操作
- 3 shell語法
- 概論
- 注釋
- 變量
- 默認(rèn)變量
- 數(shù)組
- expr命令
- read命令
- echo命令
- printf命令
- test命令與判斷符號[]
- 邏輯運算符&&和||
- test命令
- 文件類型判斷
- 文件權(quán)限判斷
- 整數(shù)間的比較
- 字符串比較
- 多重條件判定
- 判斷符號[]
- 判斷語句
- 循環(huán)語句
- 函數(shù)
- exit命令
- 文件重定向
- 引入外部腳本
- 4.1 ssh登錄
- 基本用法
- 配置文件
- 密鑰登錄
- 執(zhí)行命令
- 關(guān)于ssh遠(yuǎn)程執(zhí)行命令中單引號與雙引號的問題
- ssh遠(yuǎn)程執(zhí)行命令
- shell命令變量中的空格問題(用ssh執(zhí)行)
- 4.2scp傳文件
- 基本用法
- 一次復(fù)制多個文件:
- 復(fù)制文件夾:
- 指定服務(wù)器的端口號:
- 使用`scp`配置其他服務(wù)器的`vim`和`tmux`
- 5.1 git
- 1.git教程
- 1.1. git基本概念
- 1.2 git常用命令
- 2.創(chuàng)建作業(yè) & 測試作業(yè)的正確性
- 3.git命令分類整理
- 全局設(shè)置
- 常用命令
- 查看命令
- 刪除命令
- 代碼回滾
- 遠(yuǎn)程倉庫
- 分支命令
- stash暫存
- 一些問題
- 關(guān)于 git restore
- 關(guān)于 git rm
- 6. thrift-rpc框架
- 匹配系統(tǒng)項目實現(xiàn)
- 接口實現(xiàn)
- 實現(xiàn)match_server
- 客戶端實現(xiàn)
- server端實現(xiàn)
- 實現(xiàn)數(shù)據(jù)存儲功能
- 升級匹配系統(tǒng)
- 看一下為什么Calculator修改為Match/Save
- 知識補充
- c++ mutex鎖
- c++ 條件變量
- c++ 多線程
- 7. 管道、環(huán)境變量與常用命令
- 管道
- 概念
- 要點
- 與文件重定向的區(qū)別
- 舉例
- 環(huán)境變量
- 概念
- 查看
- 修改
- 常見環(huán)境變量
- 常用命令
- 系統(tǒng)狀況
- 文件權(quán)限
- 文件檢索
- 查看文件內(nèi)容
- 用戶相關(guān)
- 工具
- 安裝軟件
- 補充
- 8. 租云服務(wù)器及配docker環(huán)境
- 概述
- 租云服務(wù)器及安裝docker
- 阿里云
- 騰訊云
- 華為云
- docker教程
1.1常用文件管理命令
homework作業(yè)測評命令
homework num(作業(yè)號) show/create/test
homework 1 create #創(chuàng)建第一節(jié)課的作業(yè) 生成lesson_1文件夾
homework 1 test #測試第一節(jié)課的作業(yè)是不是對的
home下面的用戶文件目錄是家目錄
-
常用命令介紹
(1) ctrl c: 取消命令,并且換行
(2) ctrl u: 清空本行命令
(3) tab鍵:可以補全命令和文件名,如果補全不了快速按兩下tab鍵,可以顯示備選選項
(4) ls: 列出當(dāng)前目錄下所有文件,藍(lán)色的是文件夾,白色的是普通文件,綠色的是可執(zhí)行文件 ls -l==詳細(xì)信息 ls -lh文件大小可以轉(zhuǎn)成kb ls -a展示隱藏文件(以.開頭的文件)
(5) pwd: 顯示當(dāng)前路徑
(6) cd XXX: 進(jìn)入XXX目錄下, cd … 返回上層目錄 cd -返回上一個呆過的目錄
(7) cp XXX YYY: 將XXX文件復(fù)制成YYY,XXX和YYY可以是一個路徑,比如…/dir_c/a.txt,表示上層目錄下的dir_c文件夾下的文件a.txt cp=復(fù)制+粘貼+重命名 cp tmp/a.txt b/a1.txt 復(fù)制文件夾需要在命令后加-r
(8) mkdir XXX: 創(chuàng)建目錄XXX
(9) rm XXX: 刪除普通文件; rm XXX -r: 刪除文件夾
(10) mv XXX YYY: 將XXX文件移動到Y(jié)YY,和cp命令一樣,XXX和YYY可以是一個路徑;重命名也是用這個命令
(11) touch XXX: 創(chuàng)建一個文件
(12) cat XXX: 展示文件XXX中的內(nèi)容(15)刪除本目錄下所有文件: rm -f * 刪除某類型的文件 rm *.txt *和文件類型之間沒有空格
(13) 復(fù)制文本
windows/Linux下:Ctrl + insert,Mac下:command + c
(14) 粘貼文本
windows/Linux下:Shift + insert,Mac下:command + v
2.1 簡單的介紹tmux與vim
簡單的介紹tmux與vim
開發(fā)項目時的兩個編輯環(huán)境,此為開發(fā)項目時所必備
tmux
作用
1.分屏:可以在一個開發(fā)框里分屏
2.允許terminal在連接斷開之后可以繼續(xù)運行,讓進(jìn)程不會因為斷開連接而中斷
結(jié)構(gòu)
一個tmux可以有一堆session
每個sesion可開很多的window
每個window可以開很多pane
每個pane可以打開一個shell交互
如圖所示:
常規(guī)操作
前言:tmux創(chuàng)建一個session,session中包含一個window,一個界面就是一個window
1).切分:
豎直切分:先按ctrl+A松開,輸入%,也就是按下shift+5
當(dāng)按下ctrl+d,可以關(guān)閉tmux
水平切分:先按ctrl+A,再按”,即 shift+’
同樣的按下ctrl+d取消
對于切分來說,每一塊都可以繼續(xù)切分
2).退出:
ctrl+d 退出
當(dāng)window沒有pane時,自動退出
當(dāng)session沒有window時,自動退出
故一直ctrl+d下去會直接退出
3).選擇pane:鼠標(biāo)點擊即可或輸入ctrl+a,然后按方向鍵選擇相鄰的pane
4).調(diào)整分割線:選中并拖動即可或者ctrl+a同時(同時也不松開)按方向鍵
5).全屏與取消全屏:某個窗口全屏:選中并按下ctrl+A再按z
同樣取消按ctrl+A再按z
6).掛起窗口:ctrl+a然后按d,此為從session中退出
輸入tmux a 或tmux attach,再開啟session窗口
7).選擇其他的session:先進(jìn)入tmux,然后在tmux里輸入ctrl+a再按s
再session里的方向鍵操作:
→展開,→再按一次是展開所有pane ←按下是合上所有pane
←合上
↑↓選擇session
如下所示:一共9個session,點開展開是一系列window,再展開window是pane
8).session中創(chuàng)建window與選擇window:ctrl+a再按c:創(chuàng)建window
ctrl+a再按w:選擇其他window也可以展開合上每個window
注:ctrl+a+s與ctrl+a+w的區(qū)別:前者打開只展開session一級,展示session級中所有的window如圖一,后者打開默認(rèn)是w一級,展開window級中所有的pane,如圖二
9).翻閱內(nèi)容:↑滾輪向上
如果沒有鼠標(biāo):ctrl+a再按Pageup向上翻,按PageUp向下翻
按PageUp也可以喚醒
10).從tmux中復(fù)制文本:
按住shift鍵選擇文本
ctrl+insert復(fù)制
shift+insert粘貼
mac電腦:command+c復(fù)制
command+v粘貼
1、先列出所有的session及每個窗口的個數(shù):
tmux ls
2、找到自己的session并刪除不響應(yīng)的窗口:
tmux kill-window -t 2
關(guān)閉當(dāng)前tmux的第2個窗口
vim
功能
1.命令行模式下的文本編輯器
2.根據(jù)擴(kuò)展名判別編程語言,實現(xiàn)代碼縮進(jìn)、代碼高亮
使用
vim filename
如果有該文件則打開
沒有則打開一個新的文件,命名為filename
模式
1.一般命令模式/默認(rèn)模式:無法編寫,輸入命令,每一個命令對應(yīng)一個字母,支持復(fù)制粘貼刪除文本
2.編輯模式:在默認(rèn)模式下按i,進(jìn)入編輯模式,按esc退出
3.命令行模式:默認(rèn)模式下按:/?三個中任意一個進(jìn)入命令行模式,命令行在最下面(個人建議用:)支持查找、替換、保存、退出、配置編輯器等
輸入:wq,保存并退出
操作
1.i:進(jìn)入編輯模式
2.esc:進(jìn)入一般命令模式
3.小鍵盤可以操作前后左右
注:在命令模式下:vim會卡在最后一個字符前面,編輯模式會卡在最后一個字符,不像win,移動到最后會直接換行
同樣的,無論是什么模式,往左移動到開頭就會停下
4.光標(biāo)的移動操作:n n是數(shù)字,光標(biāo)會自動右移n個字符
一般命令模式下:0/home 將光標(biāo)移動到本行開頭
$/End 將光標(biāo)移動到本行結(jié)尾
G:光標(biāo)移動到最后一行
5.具體到哪一行的操作:
1).n/nG:表示想去具體到哪一行(n是到某一行的下面,nG是直達(dá))
2).gg:到達(dá)第一行
3).n 向下跳n行
6.查找與修改字符串的操作:
1)./word:在命令行模式下,光標(biāo)之下尋找第一個值為word的字符串
2).?word:在光標(biāo)之上第一個值為word的字符串
3).n:重復(fù)前一個查找操作 數(shù)字+n重復(fù)前一個查找動作n次
4).N:反向查找,也就是說前一個命令向前找,此命令下向后找
5).:n1,n2s/word1/word2/g:n1,n2為數(shù)字,在第n1與n2之間找word1,并替換為word2
:1,$s/word1/word2/g: 將全文的word1換成word2
:1,$s/word1/word2/gc:在每一次替換的時候都會讓用戶進(jìn)行確認(rèn)
7.:noh 關(guān)閉所查找的關(guān)鍵詞的高亮
8.選中與刪除
v:選中文本,按兩下esc取消
d:刪除選中文本(其實有剪切的特性)
dd:刪除整行
9.復(fù)制與粘貼:
y:復(fù)制(文本)
p:在光標(biāo)所處位置的下一行或下一個位置(通常當(dāng)光標(biāo)在兩邊時)粘貼
yy:復(fù)制當(dāng)前行
10.撤銷:u:撤銷
ctrl+r:取消撤銷
注:在windows里,ctrl+z撤銷,ctrl+shift+z取消撤銷
11.> 將選中的文本整體向右移動
< 將選中的文本整體向左移動
12.保存與退出:
:w保存
:w! 強制保存
一般命令模式下:按下ESC,按q退出
:q! 強制退出(不保存)
:wq 保存并退出
:wq! 強制保存退出
13.行號的顯示與隱藏:
:set nonu 隱藏行號
:set nu 顯示行號
14.paste模式:
為什么:當(dāng)要粘貼過來的代碼很長時,命令可能會失效,占用很大帶寬,導(dǎo)致出現(xiàn)多重縮進(jìn)
:set paste取消代碼縮進(jìn),設(shè)置成粘貼模式
:set nopaste開啟代碼縮進(jìn)
要粘貼代碼的時候先 :set paste
15.其他與gg有關(guān)的
gg+d+5G
gg+d+G 刪除全部內(nèi)容
gg=G 將全文格式化
16.vim的卡死處理
ctrl+q:當(dāng)vim卡死時,可取消當(dāng)前正在執(zhí)行的命令
17.異常處理:當(dāng)前進(jìn)程出現(xiàn)沖突時,會出現(xiàn)異常
解決方法:1).找到正在多個打開的文件程序,并關(guān)掉,保證同一個進(jìn)程只有同一個文件能打開
2).問題:當(dāng)一個進(jìn)程不小心被其他進(jìn)程殺掉,當(dāng)再打開main.cpp時,此時如果出現(xiàn)一個.swp緩存文件時會報錯
解決:在沒有任何一個進(jìn)程打開該文件時,將.swp文件刪掉即可
作業(yè)
homework(0).
cd homework/lesson_2/homework_0/
touch names.txt
vim names.txt
輸入i進(jìn)入編輯模式
AcWing
yxc
Bob
張強
李明
Alice
按Esc
進(jìn)入一般命令模式
:wq
保存并退出
homework
homework(1).
1).
cd …/homework_1
vim problem.txt
G // 進(jìn)入最后一行
101 //進(jìn)入編輯模式
i進(jìn)入編輯模式
2).
3G //進(jìn)入編輯模式
8 //第8個字符
i進(jìn)入編輯模式
3).
gg //進(jìn)入第一行
30 //找到第30個字符
i //進(jìn)入編輯模式
4).
:16//進(jìn)入第16行
55 //找到第55個字符
i //進(jìn)入編輯模式
5).
:9//進(jìn)入第9行
80 //找到第80個字符
i//進(jìn)入編輯模式
:wq//保存并退出
homework(2).
cd homework/lesson_2/homework_2
vim problem.txt
gg//先到第1行
然后輸入 /two,回車
i進(jìn)入編輯模式
1).在第一個two后面輸入 “abc”
2).在第二個two前面輸入def
3).在第三個two,刪除12個字符
4).定位到第四個two,退出編輯模式輸入dd,刪除該行
homework(3).
cd …/homework_3
vim problem.txt
1).:5,15/of/OF/g //將在5行和第15行之間的of全部換成OF
2).:1,$s/the/THE/g //將所有的the換成THE
3):1,$s/is/IS/gc 然后ny交替按即可//將所有偶數(shù)個is換成IS
homework(4).
cd …/homework_4
1).11G dd//刪除第11行
2).Gp //先到最后一行,然后按p粘貼
3).5Gyy//將第5行復(fù)制
4).Gp//先到最后一行,然后按p粘貼
:wq //保存并退出
homework(5).
cd …/homework_5
1).11G14//跳到第11行第14個單詞
v//選中文本
13G5//到第13行第5個單詞
d//刪除選中文本
2).G$//到達(dá)最后一行的最后一個位置
p//粘貼文本
3).5G87//跳到第5行第87個單詞(因為第88個單詞要保留)
v//選中文本
7G6//跳到第7行第6個單詞(因為第7個要保留)
y//復(fù)制文本
4).G$p
:wq //保存并退出
homework(6).
此題的難點在于復(fù)制內(nèi)容與粘貼內(nèi)容到第二個文件
cd …/homework_6
1).gg+d+G//刪除全部文本
2).ctrl+a shift+" //打開一個新的pane
vim source1.cpp
:set nonu //隱藏行號
shift //選中前3行
ctrl+insert //復(fù)制選中內(nèi)容
在source0.cpp中
:set paste //進(jìn)入粘貼模式
i進(jìn)入編輯模式
shift+insert //進(jìn)行粘貼
同理操作12-24行
source0.cpp :wq//保存并退出
source1.cpp :q//退出
復(fù)制后可能會一定概率有一些小空格,需要把多余空格刪掉
注意,在復(fù)制粘貼時,被復(fù)制的文件最好在左邊或下邊,且周圍沒有新的pane影響,如下圖所示
homework(7).
cd …/homework_7
vim source.cpp
gg=G //將全部內(nèi)容格式化
:wq //保存并退出
homework(8).
cd …/homework_8
vim source.cpp
下面兩行操作重復(fù)兩次
15Gv21G //選中15-21行
//向右縮進(jìn)
22Gv23G //選中22-23行
< //向左縮進(jìn)1次
:wq
homework(9)
格局小了hh
vim source.cpp
#include
using namespace std;
int main(){
int a, b;
cin >> a >> b;
cout << a + b < <endl;
return 0;
}
//輸入以上代碼即可
最終結(jié)果
│homework_0 is Right!
│homework_1 is Right!
│homework_2 is Right!
│homework_3 is Right!
│homework_4 is Right!
│homework_5 is Right!
│homework_6 is Right!
│homework_7 is Right!
│homework_8 is Right!
│homework_9 is Right!
score: 100/100
tmux教程
功能:
(1) 分屏。
(2) 允許斷開Terminal連接后,繼續(xù)運行進(jìn)程。
結(jié)構(gòu):
一個tmux可以包含多個session,一個session可以包含多個window,一個window可以包含多個pane。
實例:
tmux:
session 0:
window 0:
pane 0
pane 1
pane 2
…
window 1
window 2
…
session 1
session 2
…
操作:
(1) tmux:新建一個session,其中包含一個window,window中包含一個pane,pane里打開了一個shell對話框。
(2) 按下Ctrl + a后手指松開,然后按%:將當(dāng)前pane左右平分成兩個pane。
(3) 按下Ctrl + a后手指松開,然后按"(注意是雙引號"):將當(dāng)前pane上下平分成兩個pane。
(4) Ctrl + d:關(guān)閉當(dāng)前pane;如果當(dāng)前window的所有pane均已關(guān)閉,則自動關(guān)閉window;如果當(dāng)前session的所有window均已關(guān)閉,則自動關(guān)閉session。
(5) 鼠標(biāo)點擊可以選pane。
(6) 按下ctrl + a后手指松開,然后按方向鍵:選擇相鄰的pane。
(7) 鼠標(biāo)拖動pane之間的分割線,可以調(diào)整分割線的位置。
(8) 按住ctrl + a的同時按方向鍵,可以調(diào)整pane之間分割線的位置。
(9) 按下ctrl + a后手指松開,然后按z:將當(dāng)前pane全屏/取消全屏。
(10) 按下ctrl + a后手指松開,然后按d:掛起當(dāng)前session。
(11) tmux a:打開之前掛起的session。
(12) 按下ctrl + a后手指松開,然后按s:選擇其它session。
方向鍵 —— 上:選擇上一項 session/window/pane
方向鍵 —— 下:選擇下一項 session/window/pane
方向鍵 —— 右:展開當(dāng)前項 session/window
方向鍵 —— 左:閉合當(dāng)前項 session/window
(13) 按下Ctrl + a后手指松開,然后按c:在當(dāng)前session中創(chuàng)建一個新的window。
(14) 按下Ctrl + a后手指松開,然后按w:選擇其他window,操作方法與(12)完全相同。
(15) 按下Ctrl + a后手指松開,然后按PageUp:翻閱當(dāng)前pane內(nèi)的內(nèi)容。
(16) 鼠標(biāo)滾輪:翻閱當(dāng)前pane內(nèi)的內(nèi)容。
(17) 在tmux中選中文本時,需要按住shift鍵。(僅支持Windows和Linux,不支持Mac,不過該操作并不是必須的,因此影響不大)
(18) tmux中復(fù)制/粘貼文本的通用方式:
(1) 按下Ctrl + a后松開手指,然后按[
(2) 用鼠標(biāo)選中文本,被選中的文本會被自動復(fù)制到tmux的剪貼板
(3) 按下Ctrl + a后松開手指,然后按],會將剪貼板中的內(nèi)容粘貼到光標(biāo)處
vim教程
功能:
(1) 命令行模式下的文本編輯器。
(2) 根據(jù)文件擴(kuò)展名自動判別編程語言。支持代碼縮進(jìn)、代碼高亮等功能。
(3) 使用方式:vim filename
如果已有該文件,則打開它。
如果沒有該文件,則打開個一個新的文件,并命名為filename
模式:
(1) 一般命令模式
默認(rèn)模式。命令輸入方式:類似于打游戲放技能,按不同字符,即可進(jìn)行不同操作??梢詮?fù)制、粘貼、刪除文本等。
(2) 編輯模式
在一般命令模式里按下i,會進(jìn)入編輯模式。
按下ESC會退出編輯模式,返回到一般命令模式。
(3) 命令行模式
在一般命令模式里按下:/?三個字母中的任意一個,會進(jìn)入命令行模式。命令行在最下面。
可以查找、替換、保存、退出、配置編輯器等。
操作:
(1) i:進(jìn)入編輯模式
(2) ESC:進(jìn)入一般命令模式
(3) h 或 左箭頭鍵:光標(biāo)向左移動一個字符
(4) j 或 向下箭頭:光標(biāo)向下移動一個字符
(5) k 或 向上箭頭:光標(biāo)向上移動一個字符
(6) l 或 向右箭頭:光標(biāo)向右移動一個字符
(7) n:n表示數(shù)字,按下數(shù)字后再按空格,光標(biāo)會向右移動這一行的n個字符
(8) 0 或 功能鍵[Home]:光標(biāo)移動到本行開頭
(9) $ 或 功能鍵[End]:光標(biāo)移動到本行末尾
(10) G:光標(biāo)移動到最后一行
(11) :n 或 nG:n為數(shù)字,光標(biāo)移動到第n行
(12) gg:光標(biāo)移動到第一行,相當(dāng)于1G
(13) n:n為數(shù)字,光標(biāo)向下移動n行
(14) /word:向光標(biāo)之下尋找第一個值為word的字符串。
(15) ?word:向光標(biāo)之上尋找第一個值為word的字符串。
(16) n:重復(fù)前一個查找操作
(17) N:反向重復(fù)前一個查找操作
(18) :n1,n2s/word1/word2/g:n1與n2為數(shù)字,在第n1行與n2行之間尋找word1這個字符串,并將該字符串替換為word2
(19) :1, s / w o r d 1 / w o r d 2 / g :將全文的 w o r d 1 替換為 w o r d 2 ( 20 ) : 1 , s/word1/word2/g:將全文的word1替換為word2 (20) :1, s/word1/word2/g:將全文的word1替換為word2(20):1,s/word1/word2/gc:將全文的word1替換為word2,且在替換前要求用戶確認(rèn)。
(21) v:選中文本
(22) d:刪除選中的文本
(23) dd: 刪除當(dāng)前行
(24) y:復(fù)制選中的文本
(25) yy: 復(fù)制當(dāng)前行
(26) p: 將復(fù)制的數(shù)據(jù)在光標(biāo)的下一行/下一個位置粘貼
(27) u:撤銷
(28) Ctrl + r:取消撤銷
(29) 大于號 >:將選中的文本整體向右縮進(jìn)一次
(30) 小于號 <:將選中的文本整體向左縮進(jìn)一次
(31) :w 保存
(32) :w! 強制保存
(33) :q 退出
(34) :q! 強制退出
(35) :wq 保存并退出
(36) :set paste 設(shè)置成粘貼模式,取消代碼自動縮進(jìn)(粘貼大量代碼的時候要用到)
(37) :set nopaste 取消粘貼模式,開啟代碼自動縮進(jìn)
(38) :set nu 顯示行號
(39) :set nonu 隱藏行號
(40) gg=G:將全文代碼格式化
(41) :noh 關(guān)閉查找關(guān)鍵詞高亮
(42) Ctrl + q:當(dāng)vim卡死時,可以取消當(dāng)前正在執(zhí)行的命令
異常處理:
每次用vim編輯文件時,會自動創(chuàng)建一個.filename.swp的臨時文件。
如果打開某個文件時,該文件的swp文件已存在,則會報錯。此時解決辦法有兩種:
(1) 找到正在打開該文件的程序,并退出
(2) 直接刪掉該swp文件即可
homework中的一些操作
/word 通過光標(biāo)查看某個單詞在全文中所有位置 ,按顯示光標(biāo)之下第一個值為word的字符串,按往下查找
在esc模式下按是向后刪除 在編輯模式下是向前刪除
dd: 刪除當(dāng)前行
:n1,n2s/word1/word2/g:n1與n2為數(shù)字,在第n1行與n2行之間尋找word1這個字符串,并將該字符串替換為word2
:1, s / w o r d 1 / w o r d 2 / g :將全文的 w o r d 1 替換為 w o r d 2 : 1 , s/word1/word2/g:將全文的word1替換為word2 :1, s/word1/word2/g:將全文的word1替換為word2:1,s/word1/word2/gc:將全文的word1替換為word2,且在替換前要求用戶確認(rèn)。
dd后按p可將刪除的行復(fù)制回來
v:選中文本
$ 或 功能鍵[End]:光標(biāo)移動到本行末尾
y:復(fù)制選中的文本
yy: 復(fù)制當(dāng)前行
p: 將復(fù)制的數(shù)據(jù)在光標(biāo)的下一行/下一個位置粘貼
gg=G:將全文代碼格式化
大于號 >:將選中的文本整體向右縮進(jìn)一次
小于號 <:將選中的文本整體向左縮進(jìn)一次
3 shell語法
概論
shell是我們通過命令行與操作系統(tǒng)溝通的語言。
shell腳本可以直接在命令行中執(zhí)行,也可以將一套邏輯組織成一個文件,方便復(fù)用。
AC Terminal中的命令行可以看成是一個“shell腳本在逐行執(zhí)行”。
Linux中常見的shell腳本有很多種,常見的有:
-
Bourne Shell(
/usr/bin/sh
或/bin/sh
) -
Bourne Again Shell(
/bin/bash
) -
C Shell(
/usr/bin/csh
) -
K Shell(
/usr/bin/ksh
) -
zsh
-
…
Linux系統(tǒng)中一般默認(rèn)使用bash,所以接下來講解bash中的語法。
文件開頭需要寫#! /bin/bash
,指明bash為腳本解釋器。
學(xué)習(xí)技巧
不要死記硬背,遇到含糊不清的地方,可以在AC Terminal里實際運行一遍。
腳本示例
新建一個test.sh
文件,內(nèi)容如下:
#! /bin/bash
echo "Hello World!"
運行方式
作為可執(zhí)行文件
acs@9e0ebfcd82d7:~$ chmod +x test.sh # 使腳本具有可執(zhí)行權(quán)限
acs@9e0ebfcd82d7:~$ ./test.sh # 當(dāng)前路徑下執(zhí)行
Hello World! # 腳本輸出
acs@9e0ebfcd82d7:~$ /home/acs/test.sh # 絕對路徑下執(zhí)行
Hello World! # 腳本輸出
acs@9e0ebfcd82d7:~$ ~/test.sh # 家目錄路徑下執(zhí)行
Hello World! # 腳本輸出
用解釋器執(zhí)行
acs@9e0ebfcd82d7:~$ bash test.sh
Hello World! # 腳本輸出
注釋
單行注釋
每行中#
之后的內(nèi)容均是注釋。
# 這是一行注釋
echo 'Hello World' # 這也是注釋
多行注釋
格式:
:<<EOF
第一行注釋
第二行注釋
第三行注釋
EOF
其中 EOF
可以換成其它任意字符串。例如:
:<<abc
第一行注釋
第二行注釋
第三行注釋
abc:<<!
第一行注釋
第二行注釋
第三行注釋
!
變量
1、定義變量時,等號兩邊不能有空格
2、定義變量的時候變量都是字符串,但當(dāng)變量需要是整數(shù)時,會自動把變量轉(zhuǎn)換成整數(shù)
3、type+命令可以解釋該命令的來源(內(nèi)嵌命令。第三方命令等)
如type readonly #readonly is a shell builtin(shell內(nèi)部命令)
type ls # ls is aliased to ‘ls –color+auto’
4、被聲明為只讀的變量無法被unset刪除
5、bash可以用來開一個新的進(jìn)程,exit或Ctrl+d退出新的bash
6、字符串中,不加引號和雙引號效果相同
7、如果一個變量不存在的話,他的值是空字符串
定義變量
定義變量,不需要加$
符號,例如:
name1='yxc' # 單引號定義字符串
name2="yxc" # 雙引號定義字符串
name3=yxc # 也可以不加引號,同樣表示字符串
使用變量
使用變量,需要加上$
符號,或者${}
符號。花括號是可選的,主要為了幫助解釋器識別變量邊界。
name=yxc
echo $name # 輸出yxc
echo ${name} # 輸出yxc
echo ${name}acwing # 輸出yxcacwing
只讀變量
使用 readonly
或者declare
可以將變量變?yōu)橹蛔x。
name=yxc
readonly name
declare -r name # 兩種寫法均可name=abc # 會報錯,因為此時name只讀
刪除變量
unset可以刪除變量。
name=yxc
unset name
echo $name # 輸出空行
變量類型
輸入bash后相當(dāng)于開了一個新的子進(jìn)程 exit
相當(dāng)于退出該子進(jìn)程
-
自定義變量(局部變量)
-
子進(jìn)程不能訪問的變量
環(huán)境變量(全局變量)
-
子進(jìn)程可以訪問的變量
自定義變量改成環(huán)境變量:
acs@9e0ebfcd82d7:~$ name=yxc # 定義變量 acs@9e0ebfcd82d7:~$ export name # 第一種方法 acs@9e0ebfcd82d7:~$ declare -x name # 第二種方法
環(huán)境變量改為自定義變量:
acs@9e0ebfcd82d7:~$ export name=yxc # 定義環(huán)境變量 acs@9e0ebfcd82d7:~$ declare +x name # 改為自定義變量
字符串
字符串可以用單引號,也可以用雙引號,也可以不用引號。
單引號與雙引號的區(qū)別:
-
單引號中的內(nèi)容會原樣輸出,不會執(zhí)行、不會取變量;
-
雙引號中的內(nèi)容可以執(zhí)行、可以取變量;
name=yxc # 不用引號 echo 'hello, $name \"hh\"' # 單引號字符串,輸出 hello, $name \"hh\" echo "hello, $name \"hh\"" # 雙引號字符串,輸出 hello, yxc "hh"
獲取字符串長度
name="yxc"
echo ${#name} # 輸出3
提取子串
name="hello, yxc"
echo ${name:0:5} # 提取從0開始的5個字符
默認(rèn)變量
文件參數(shù)變量
在執(zhí)行shell腳本時,可以向腳本傳遞參數(shù)。$1
是第一個參數(shù),$2
是第二個參數(shù),以此類推。特殊的,$0
是文件名(包含路徑)。例如:
創(chuàng)建文件test.sh
:
#! /bin/bashecho "文件名:"$0
echo "第一個參數(shù):"$1
echo "第二個參數(shù):"$2
echo "第三個參數(shù):"$3
echo "第四個參數(shù):"$4
然后執(zhí)行該腳本:
acs@9e0ebfcd82d7:~$ chmod +x test.sh
acs@9e0ebfcd82d7:~$ ./test.sh 1 2 3 4
文件名:./test.sh
第一個參數(shù):1
第二個參數(shù):2
第三個參數(shù):3
第四個參數(shù):4
其它參數(shù)相關(guān)變量
參數(shù) | 說明 |
---|---|
$# | 代表文件傳入的參數(shù)個數(shù),如上例中值為4 |
$* | 由所有參數(shù)構(gòu)成的用空格隔開的字符串,如上例中值為"$1 $2 $3 $4" |
$@ | 每個參數(shù)分別用雙引號括起來的字符串,如上例中值為"$1" “$2” “$3” “$4” |
$$ | 腳本當(dāng)前運行的進(jìn)程ID |
$? | 上一條命令的退出狀態(tài)(注意不是stdout,而是exit code)。0表示正常退出,其他值表示錯誤 |
$(command) | 返回command這條命令的stdout(可嵌套) |
command | 返回command這條命令的stdout(不可嵌套) |
最后兩個的例子
數(shù)組
數(shù)組中可以存放多個不同類型的值,只支持一維數(shù)組,初始化時不需要指明數(shù)組大小。
數(shù)組下標(biāo)從0開始。
定義
數(shù)組用小括號表示,元素之間用空格隔開。例如:
array=(1 abc "def" yxc)
也可以直接定義數(shù)組中某個元素的值:
array[0]=1
array[1]=abc
array[2]="def"
array[3]=yxc
讀取數(shù)組中某個元素的值
格式:
${array[index]}
例如:
array=(1 abc "def" yxc)
echo ${array[0]}
echo ${array[1]}
echo ${array[2]}
echo ${array[3]}
讀取整個數(shù)組
格式:
${array[@]} # 第一種寫法
${array[*]} # 第二種寫法
例如:
array=(1 abc "def" yxc)echo ${array[@]} # 第一種寫法
echo ${array[*]} # 第二種寫法
數(shù)組長度
類似于字符串
${#array[@]} # 第一種寫法
${#array[*]} # 第二種寫法
例如:
array=(1 abc "def" yxc)
echo ${#array[@]} # 第一種寫法
echo ${#array[*]} # 第二種寫法
expr命令
expr
命令用于求表達(dá)式的值,格式為:
expr 表達(dá)式
表達(dá)式說明:
-
用空格隔開每一項
-
用反斜杠放在shell特定的字符前面(發(fā)現(xiàn)表達(dá)式運行錯誤時,可以試試轉(zhuǎn)義)
-
對包含空格和其他特殊字符的字符串要用引號括起來
-
expr會在stdout中輸出結(jié)果也就是需要通過`` 或$()進(jìn)行輸出結(jié)果。如果為邏輯關(guān)系表達(dá)式,則結(jié)果為真,stdout為1,否則為0。
-
expr的exit code:如果為邏輯關(guān)系表達(dá)式,則結(jié)果為真,exit code為0,否則為1。
字符串表達(dá)式
length STRING
返回STRING
的長度index STRING CHARSET
CHARSET中
任意單個字符在STRING
中最前面的字符位置,下標(biāo)從1開始。如果在STRING
中完全不存在CHARSET中
的字符,則返回0。substr STRING POSITION LENGTH
返回STRING
字符串中從POSITION
開始,長度最大為LENGTH
的子串。如果POSITION
或LENGTH
為負(fù)數(shù),0或非數(shù)值,則返回空字符串。
示例:
str="Hello World!"echo `expr length "$str"` # ``不是單引號,表示執(zhí)行該命令,輸出12
echo `expr index "$str" aWd` # 輸出7,下標(biāo)從1開始
echo `expr substr "$str" 2 3` # 輸出 ell
整數(shù)表達(dá)式
expr
支持普通的算術(shù)操作,算術(shù)表達(dá)式優(yōu)先級低于字符串表達(dá)式,高于邏輯關(guān)系表達(dá)式。
+ -
加減運算。兩端參數(shù)會轉(zhuǎn)換為整數(shù),如果轉(zhuǎn)換失敗則報錯。
* / %
乘,除,取模運算。兩端參數(shù)會轉(zhuǎn)換為整數(shù),如果轉(zhuǎn)換失敗則報錯。()
可以改變優(yōu)先級,但需要用反斜杠轉(zhuǎn)義
示例:
a=3
b=4echo `expr $a + $b` # 輸出7
echo `expr $a - $b` # 輸出-1
echo `expr $a \* $b` # 輸出12,*需要轉(zhuǎn)義
echo `expr $a / $b` # 輸出0,整除
echo `expr $a % $b` # 輸出3
echo `expr \( $a + 1 \) \* \( $b + 1 \)` # 輸出20,值為(a + 1) * (b + 1)
邏輯關(guān)系表達(dá)式
|
如果第一個參數(shù)非空且非0,則返回第一個參數(shù)的值,否則返回第二個參數(shù)的值,但要求第二個參數(shù)的值也是非空或非0,否則返回0。如果第一個參數(shù)是非空或非0時,不會計算第二個參數(shù)。&
如果兩個參數(shù)都非空且非0,則返回第一個參數(shù),否則返回0。如果第一個參為0或為空,則不會計算第二個參數(shù)。< <= = == != >= >
比較兩端的參數(shù),如果為true,則返回1,否則返回0。”==”是”=”的同義詞?!眅xpr”首先嘗試將兩端參數(shù)轉(zhuǎn)換為整數(shù),并做算術(shù)比較,如果轉(zhuǎn)換失敗,則按字符集排序規(guī)則做字符比較。()
可以改變優(yōu)先級,但需要用反斜杠轉(zhuǎn)義
示例:
a=3
b=4echo `expr $a \> $b` # 輸出0,>需要轉(zhuǎn)義
echo `expr $a '<' $b` # 輸出1,也可以將特殊字符用引號引起來
echo `expr $a '>=' $b` # 輸出0
echo `expr $a \<\= $b` # 輸出1c=0
d=5echo `expr $c \& $d` # 輸出0
echo `expr $a \& $b` # 輸出3
echo `expr $c \| $d` # 輸出5
echo `expr $a \| $b` # 輸出3
乘法運算的 * 的使用除轉(zhuǎn)義外,還有直接加單引號這種方式也可以,如
echo `expr $a '*' $b`
這幾個運算之間不管需不需要轉(zhuǎn)義都可以直接加上’',這個作用應(yīng)該是告訴解釋器我和你們之前定義的不一樣吧,原來是什么意思就按什么意思來。那些需要轉(zhuǎn)義的應(yīng)該是解釋器賦予了他們新的功能,一旦我們加上",就意味著不是按解釋器賦予的新的意思執(zhí)行?;貧w到最原始的意義.
read命令
read
命令用于從標(biāo)準(zhǔn)輸入中讀取單行數(shù)據(jù)。當(dāng)讀到文件結(jié)束符時,exit code為1,否則為0。
參數(shù)說明
-
-p
: 后面可以接提示信息 -
-t
:后面跟秒數(shù),定義輸入字符的等待時間,超過等待時間后會自動忽略此命令實例:
acs@9e0ebfcd82d7:~$ read name # 讀入name的值
acwing yxc # 標(biāo)準(zhǔn)輸入
acs@9e0ebfcd82d7:~$ echo $name # 輸出name的值
acwing yxc #標(biāo)準(zhǔn)輸出
acs@9e0ebfcd82d7:~$ read -p "Please input your name: " -t 30 name # 讀入name的值,等待時間30秒
Please input your name: acwing yxc # 標(biāo)準(zhǔn)輸入
acs@9e0ebfcd82d7:~$ echo $name # 輸出name的值
acwing yxc # 標(biāo)準(zhǔn)輸出
echo命令
echo
用于輸出字符串。命令格式:
echo STRING
顯示普通字符串
echo "Hello AC Terminal"
echo Hello AC Terminal # 引號可以省略
顯示轉(zhuǎn)義字符
echo "\"Hello AC Terminal\"" # 注意只能使用雙引號,如果使用單引號,則不轉(zhuǎn)義
echo \"Hello AC Terminal\" # 也可以省略雙引號
顯示變量
name=yxc
echo "My name is $name" # 輸出 My name is yxc
顯示換行
echo -e "Hi\n" # -e 開啟轉(zhuǎn)義
echo "acwing"
輸出結(jié)果:
Hiacwing
顯示不換行
echo -e "Hi \c" # -e 開啟轉(zhuǎn)義 \c 不換行
echo "acwing"
輸出結(jié)果:
Hi acwing
顯示結(jié)果定向至文件
echo "Hello World" > output.txt # 將內(nèi)容以覆蓋的方式輸出到output.txt中
原樣輸出字符串,不進(jìn)行轉(zhuǎn)義或取變量(用單引號)
name=acwing
echo '$name\"'
輸出結(jié)果
$name\"
顯示命令的執(zhí)行結(jié)果
echo `date`
輸出結(jié)果:
Wed Sep 1 11:45:33 CST 2021
\\ \a \b \c \d \e \f \n \r \t \v
這些是要在有 - e 的時候才能起作用, 其他時候的轉(zhuǎn)義是不用- e也能轉(zhuǎn)義的。
help echo
printf命令
printf
命令用于格式化輸出,類似于C/C++
中的printf
函數(shù)。
默認(rèn)不會在字符串末尾添加換行符。
命令格式:
printf format-string [arguments...]
用法示例
腳本內(nèi)容:
printf "%10d.\n" 123 # 占10位,右對齊
printf "%-10.2f.\n" 123.123321 # 占10位,保留2位小數(shù),左對齊
printf "My name is %s\n" "yxc" # 格式化輸出字符串
printf "%d * %d = %d\n" 2 3 `expr 2 \* 3` # 表達(dá)式的值作為參數(shù)
輸出結(jié)果:
123.
123.12 .
My name is yxc
2 * 3 = 6
test命令與判斷符號[]
邏輯運算符&&和||
-
&& 表示與,|| 表示或
-
二者具有短路原則:
expr1 && expr2:當(dāng)expr1為假時,直接忽略expr2
expr1 || expr2:當(dāng)expr1為真時,直接忽略expr2 -
表達(dá)式的exit code為0,表示真;為非零,表示假。(與C/C++中的定義相反)
test命令
在命令行中輸入
help test
,可以查看test
命令的用法。
test
命令用于判斷文件類型,以及對變量做比較。
test
命令用exit code
返回結(jié)果,而不是使用stdout。0表示真,非0表示假。
例如:
test 2 -lt 3 # 為真,返回值為0
echo $? # 輸出上個命令的返回值,輸出0
acs@9e0ebfcd82d7:~$ ls # 列出當(dāng)前目錄下的所有文件
homework output.txt test.sh tmp
acs@9e0ebfcd82d7:~$ test -e test.sh && echo "exist" || echo "Not exist"
exist # test.sh 文件存在
acs@9e0ebfcd82d7:~$ test -e test2.sh && echo "exist" || echo "Not exist"
Not exist # testh2.sh 文件不存在
文件類型判斷
命令格式:
test -e filename # 判斷文件是否存在
測試參數(shù) | 代表意義 |
---|---|
-e | 文件是否存在 |
-f | 是否為文件 |
-d | 是否為目錄 |
文件權(quán)限判斷
命令格式:
test -r filename # 判斷文件是否可讀
測試參數(shù) | 代表意義 |
---|---|
-r | 文件是否可讀 |
-w | 文件是否可寫 |
-x | 文件是否可執(zhí)行 |
-s | 是否為非空文件 |
整數(shù)間的比較
命令格式:
test $a -eq $b # a是否等于b
測試參數(shù) | 代表意義 |
---|---|
-eq | a是否等于b |
-ne | a是否不等于b |
-gt | a是否大于b |
-lt | a是否小于b |
-ge | a是否大于等于b |
-le | a是否小于等于b |
字符串比較
測試參數(shù) | 代表意義 |
---|---|
test -z STRING | 判斷STRING是否為空,如果為空,則返回true |
test -n STRING | 判斷STRING是否非空,如果非空,則返回true(-n可以省略) |
test str1 == str2 | 判斷str1是否等于str2 |
test str1 != str2 | 判斷str1是否不等于str2 |
多重條件判定
命令格式:
test -r filename -a -x filename
and or
測試參數(shù) | 代表意義 |
---|---|
-a | 兩條件是否同時成立 |
-o | 兩條件是否至少一個成立 |
! | 取反。如 test ! -x file,當(dāng)file不可執(zhí)行時,返回true |
判斷符號[]
[]與test用法幾乎一模一樣,更常用于if語句中。另外[[]]是[]的加強版,支持的特性更多。
例如:
[ 2 -lt 3 ] # 為真,返回值為0
echo $? # 輸出上個命令的返回值,輸出0
acs@9e0ebfcd82d7:~$ ls # 列出當(dāng)前目錄下的所有文件
homework output.txt test.sh tmp
acs@9e0ebfcd82d7:~$ [ -e test.sh ] && echo "exist" || echo "Not exist"
exist # test.sh 文件存在
acs@9e0ebfcd82d7:~$ [ -e test2.sh ] && echo "exist" || echo "Not exist"
Not exist # testh2.sh 文件不存在
注意:
- []內(nèi)的每一項都要用空格隔開
- 中括號內(nèi)的變量,最好用雙引號括起來
- 中括號內(nèi)的常數(shù),最好用單或雙引號括起來
例如:
name="acwing yxc"
[ $name == "acwing yxc" ] # 錯誤,等價于 [ acwing yxc == "acwing yxc" ],參數(shù)太多
[ "$name" == "acwing yxc" ] # 正確
判斷語句
if…then形式
類似于C/C++
中的if-else
語句。
單層if
命令格式:
if condition
then語句1語句2...
fi
示例:
a=3
b=4if [ "$a" -lt "$b" ] && [ "$a" -gt 2 ]
thenecho ${a}在范圍內(nèi)
fi
輸出結(jié)果:
3在范圍內(nèi)
單層if-else
命令格式
if condition
then語句1語句2...
else語句1語句2...
fi
示例:
a=3
b=4if ! [ "$a" -lt "$b" ]
thenecho ${a}不小于$
elseecho ${a}小于$
fi
輸出結(jié)果:
3小于4
多層if-elif-elif-else
命令格式
if condition
then語句1語句2...
elif condition
then語句1語句2...
elif condition
then語句1語句2
else語句1語句2...
fi
示例:
a=4if [ $a -eq 1 ]
thenecho ${a}等于1
elif [ $a -eq 2 ]
thenecho ${a}等于2
elif [ $a -eq 3 ]
thenecho ${a}等于3
elseecho 其他
fi
輸出結(jié)果:
其他
case…esac
形式
類似于C/C++中的switch語句。
命令格式
case $變量名稱 in值1)語句1語句2...;; # 類似于C/C++中的break值2)語句1語句2...;;*) # 類似于C/C++中的default語句1語句2...;;
esac
示例:
a=4case $a in1)echo ${a}等于1;; 2)echo ${a}等于2;; 3) echo ${a}等于3;; *)echo 其他;;
esac
輸出結(jié)果:
其他
循環(huán)語句
for…in…do…done
命令格式:
for var in val1 val2 val3
do語句1語句2...
done
示例1,輸出a 2 cc,每個元素一行:
for i in a 2 cc
doecho $i
done
示例2,輸出當(dāng)前路徑下的所有文件名,每個文件名一行:
for file in `ls`
doecho $file
done
示例3,輸出1-10
for i in $(seq 1 10)
doecho $i
done
示例4,使用{1…10} 或者 {a…z}
for i in {a..z}
doecho $i
done
for ((…;…;…)) do…done
命令格式:
for ((expression; condition; expression))
do語句1語句2
done
示例,輸出1-10,每個數(shù)占一行:
for ((i=1; i<=10; i++))
doecho $i
done
while…do…done循環(huán)
命令格式:
while condition
do語句1語句2...
done
示例,文件結(jié)束符為Ctrl+d
,輸入文件結(jié)束符后read
指令返回false。
while read name
doecho $name
done
until…do…done循環(huán)
當(dāng)條件為真時結(jié)束。
命令格式:
until condition
do語句1語句2...
done
示例,當(dāng)用戶輸入yes
或者YES
時結(jié)束,否則一直等待讀入。
until [ "${word}" == "yes" ] || [ "${word}" == "YES" ]
doread -p "Please input yes/YES to stop this program: " word
done
break命令
跳出當(dāng)前一層循環(huán),注意與C/C++
不同的是:break
不能跳出case
語句。
示例
while read name
dofor ((i=1;i<=10;i++))docase $i in8)break;;*)echo $i;;esacdone
done
該示例每讀入非EOF的字符串,會輸出一遍1-7。
該程序可以輸入Ctrl+d
文件結(jié)束符來結(jié)束,也可以直接用Ctrl+c
殺掉該進(jìn)程。
continue命令
跳出當(dāng)前循環(huán)。
示例:
for ((i=1;i<=10;i++))
doif [ `expr $i % 2` -eq 0 ]thencontinuefiecho $i
done
該程序輸出1-10中的所有奇數(shù)。
死循環(huán)的處理方式
如果AC Terminal可以打開該程序,則輸入Ctrl+c即可。
否則可以直接關(guān)閉進(jìn)程:
-
使用
top
命令找到進(jìn)程的PID -
輸入
kill -9 PID
即可關(guān)掉此進(jìn)程
函數(shù)
bash
中的函數(shù)類似于C/C++
中的函數(shù),但return
的返回值與C/C++
不同,返回的是exit code
,取值為0-255
,0表示正常結(jié)束。
如果想獲取函數(shù)的輸出結(jié)果,可以通過echo
輸出到stdout
中,然后通過$(function_name)
來獲取stdout
中的結(jié)果。
函數(shù)的return
值可以通過$?來獲取。
命令格式:
[function] func_name() { # function關(guān)鍵字可以省略語句1語句2...
}
不獲取 return
值和stdout
值
示例
func() {name=yxcecho "Hello $name"
}func
輸出結(jié)果:
Hello yxc
獲取 return
值和stdout
值
不寫return
時,默認(rèn)return 0
。
示例
func() {name=yxcecho "Hello $name"return 123}output=$(func)
ret=$?echo "output = $output"
echo "return = $ret"
輸出結(jié)果:
output = Hello yxc
return = 123
函數(shù)的輸入?yún)?shù)
在函數(shù)內(nèi),$1
表示第一個輸入?yún)?shù),$2
表示第二個輸入?yún)?shù),依此類推。
注意:函數(shù)內(nèi)的$0
仍然是文件名,而不是函數(shù)名。
示例:
func() { # 遞歸計算 $1 + ($1 - 1) + ($1 - 2) + ... + 0word=""while [ "${word}" != 'y' ] && [ "${word}" != 'n' ]doread -p "要進(jìn)入func($1)函數(shù)嗎?請輸入y/n:" worddoneif [ "$word" == 'n' ]thenecho 0return 0fi if [ $1 -le 0 ] thenecho 0return 0fi sum=$(func $(expr $1 - 1))echo $(expr $sum + $1)
}echo $(func 10)
輸出結(jié)果:
55
函數(shù)內(nèi)的局部變量
可以在函數(shù)內(nèi)定義局部變量,作用范圍僅在當(dāng)前函數(shù)內(nèi)。
可以在遞歸函數(shù)中定義局部變量。
命令格式:
local 變量名=變量值
例如:
#! /bin/bashfunc() {local name=yxcecho $name
}
funcecho $name
輸出結(jié)果:
yxc
第一行為函數(shù)內(nèi)的name變量,第二行為函數(shù)外調(diào)用name變量,會發(fā)現(xiàn)此時該變量不存在。
exit命令
exit
命令用來退出當(dāng)前shell
進(jìn)程,并返回一個退出狀態(tài);使用$?
可以接收這個退出狀態(tài)。
exit
命令可以接受一個整數(shù)值作為參數(shù),代表退出狀態(tài)。如果不指定,默認(rèn)狀態(tài)值是 0。
exit
退出狀態(tài)只能是一個介于 0~255 之間的整數(shù),其中只有 0 表示成功,其它值都表示失敗。
示例:
創(chuàng)建腳本test.sh
,內(nèi)容如下:
#! /bin/bashif [ $# -ne 1 ] # 如果傳入?yún)?shù)個數(shù)等于1,則正常退出;否則非正常退出。
thenecho "arguments not valid"exit 1
elseecho "arguments valid"exit 0
fi
執(zhí)行該腳本:
acs@9e0ebfcd82d7:~$ chmod +x test.sh
acs@9e0ebfcd82d7:~$ ./test.sh acwing
arguments valid
acs@9e0ebfcd82d7:~$ echo $? # 傳入一個參數(shù),則正常退出,exit code為0
0
acs@9e0ebfcd82d7:~$ ./test.sh
arguments not valid
acs@9e0ebfcd82d7:~$ echo $? # 傳入?yún)?shù)個數(shù)不是1,則非正常退出,exit code為1
1
文件重定向
每個進(jìn)程默認(rèn)打開3個文件描述符:
stdin
標(biāo)準(zhǔn)輸入,從命令行讀取數(shù)據(jù),文件描述符為0stdout
標(biāo)準(zhǔn)輸出,向命令行輸出數(shù)據(jù),文件描述符為1stderr
標(biāo)準(zhǔn)錯誤輸出,向命令行輸出數(shù)據(jù),文件描述符為2
可以用文件重定向?qū)⑦@三個文件重定向到其他文件中。
重定向命令列表
命令 | 說明 |
---|---|
command > file | 將stdout重定向到file中 |
command < file | 將stdin重定向到file中 |
command >> file | 將stdout以追加方式重定向到file中 |
command n> file | 將文件描述符n重定向到file中 |
command n>> file | 將文件描述符n以追加方式重定向到file中 |
輸入和輸出重定向
echo -e "Hello \c" > output.txt # 將stdout重定向到output.txt中
echo "World" >> output.txt # 將字符串追加到output.txt中read str < output.txt # 從output.txt中讀取字符串echo $str # 輸出結(jié)果:Hello World
同時重定向stdin和stdout
創(chuàng)建bash腳本:
#! /bin/bashread a
read becho $(expr "$a" + "$b")
創(chuàng)建input.txt,里面的內(nèi)容為:
3
4
執(zhí)行命令:
acs@9e0ebfcd82d7:~$ chmod +x test.sh # 添加可執(zhí)行權(quán)限
acs@9e0ebfcd82d7:~$ ./test.sh < input.txt > output.txt # 從input.txt中讀取內(nèi)容,將輸出寫入output.txt中
acs@9e0ebfcd82d7:~$ cat output.txt # 查看output.txt中的內(nèi)容
7
引入外部腳本
類似于C/C++
中的include
操作,bash
也可以引入其他文件中的代碼。
語法格式:
. filename # 注意點和文件名之間有一個空格或source filename
示例
創(chuàng)建test1.sh
,內(nèi)容為:
#! /bin/bashname=yxc # 定義變量name
然后創(chuàng)建test2.sh
,內(nèi)容為:
#! /bin/bashsource test1.sh # 或 . test1.shecho My name is: $name # 可以使用test1.sh中的變量
執(zhí)行命令:
acs@9e0ebfcd82d7:~$ chmod +x test2.sh
acs@9e0ebfcd82d7:~$ ./test2.sh
My name is: yxc
4.1 ssh登錄
獲取ssh教程配套的遠(yuǎn)程服務(wù)器賬號的信息:
homework 4 getinfo
基本用法
遠(yuǎn)程登錄服務(wù)器:
ssh user@hostname
user
: 用戶名hostname
: IP地址或域名
第一次登錄時會提示:
The authenticity of host '123.57.47.211 (123.57.47.211)' can't be established.
ECDSA key fingerprint is SHA256:iy237yysfCe013/l+kpDGfEG9xxHxm0dnxnAbJTPpG8.
Are you sure you want to continue connecting (yes/no/[fingerprint])?
輸入yes
,然后回車即可。
這樣會將該服務(wù)器的信息記錄在~/.ssh/known_hosts
文件中。
然后輸入密碼即可登錄到遠(yuǎn)程服務(wù)器中。
默認(rèn)登錄端口號為22。如果想登錄某一特定端口:
ssh user@hostname -p 22
配置文件
創(chuàng)建文件 ~/.ssh/config
。
然后在文件中輸入:
Host myserver1HostName IP地址或域名User 用戶名Host myserver2HostName IP地址或域名User 用戶名
之后再使用服務(wù)器時,可以直接使用別名myserver1、myserver2。
密鑰登錄
創(chuàng)建密鑰:
ssh-keygen
然后一直回車即可。
執(zhí)行結(jié)束后,~/.ssh/
目錄下會多兩個文件:
id_rsa
:私鑰id_rsa.pub
:公鑰
之后想免密碼登錄哪個服務(wù)器,就將公鑰傳給哪個服務(wù)器即可。
例如,想免密登錄myserver
服務(wù)器。則將公鑰中的內(nèi)容,復(fù)制到myserver
中的~/.ssh/authorized_keys
文件里即可。
也可以使用如下命令一鍵添加公鑰:
ssh-copy-id myserver
執(zhí)行命令
命令格式:
ssh user@hostname command
例如:
ssh user@hostname ls -a
或者
# 單引號中的$i可以求值
ssh myserver 'for ((i = 0; i < 10; i ++ )) do echo $i; done'
或者
# 雙引號中的$i不可以求值
ssh myserver "for ((i = 0; i < 10; i ++ )) do echo $i; done"
單引號是原生字符串,雙引號在本地服務(wù)器直接解析
關(guān)于ssh遠(yuǎn)程執(zhí)行命令中單引號與雙引號的問題
遠(yuǎn)程執(zhí)行腳本:腳本中的內(nèi)容可視為是雙引號包含起來的。
遠(yuǎn)程執(zhí)行命令:例如:ssh user@remote_host "COMMOND"
:
- 使用單引號的時候,COMMAND中定義的命令字符都會在本地被去掉特殊意義,只是一串完全沒有解析引用的字符串傳過去遠(yuǎn)程主機(jī);
- 如果是使用雙引號時,COMMAND中定義的特殊命令字符都會在本地被解析引用,比如:COMMAND中的反引號、引號、EXTRACT_DIR變量、i變量。如果此時要在COMMAND中的特殊命令字符前加上轉(zhuǎn)義符號“\”,這樣就會去掉在本地的解析引用;但是如果COMMAND中變量有一個BAK_TIME變量引用前是不用加轉(zhuǎn)義符的,因為這個變量就是希望在本地引用的。(其中的變量名都是舉個例子)
總結(jié): ssh遠(yuǎn)程執(zhí)行的命令中使用單引號時,所有變量、特殊字符都不會在本地解析引用,會原封不動地傳過去遠(yuǎn)程主機(jī);如果在命令中有變量或特殊字符在本地進(jìn)行解析引用的,命令就得使用雙引號括起來,此時命令中不需要在本地解析引用的變量或特殊字符就需要在其前面加上轉(zhuǎn)義符\。
ssh遠(yuǎn)程執(zhí)行命令
ssh server "cd homework ; ls"
基本能完成常用的對于遠(yuǎn)程節(jié)點的管理了,幾個注意的點:
-
如果不加雙引號,第二個ls命令在本地執(zhí)行
-
分號,兩個命令之間用分號隔開
整條ssh命令用引號包圍
a=1
ssh myserver echo $a # 正確
ssh myserver "echo $a" # 正確
ssh myserver 'echo $a' # 錯誤
雙引號在本地進(jìn)行解析,所以傳過去命令不是echo $a
,而是echo 1
單引號在服務(wù)器進(jìn)行解析,傳過去的是echo $a
,服務(wù)器不知道$a
的值,解析為空
ssh myserver "for ((i = 0; i < 10; i ++ )) do echo $i; done" # 錯誤
ssh myserver 'for ((i = 0; i < 10; i ++ )) do echo $i; done' # 正確
雙引號在本地進(jìn)行解析,本地不知道$i
的值,解析為空
單引號在服務(wù)器進(jìn)行解析,$i
的值在服務(wù)器隨循環(huán)變化
shell命令變量中的空格問題(用ssh執(zhí)行)
ssh ser mkdir homework/lesson_4/homework_4/\"$1\" # 正確
ssh ser mkdir homework/lesson_4/homework_4/"'$1'" # 正確
ssh ser mkdir homework/lesson_4/homework_4/'"$1"' # 錯誤
-
如果shell命令(用ssh執(zhí)行)中有空格,變量用雙引號引起來
-
最外層是雙引號,內(nèi)嵌單引號,$等特殊符號依舊可以識別
-
最外層是單引號,內(nèi)嵌雙引號,$等特殊符號無法識別
-
mkdir “my dir” -> mkdir my dir ->創(chuàng)建my和dir文件夾
-
mkdir"'my dir'" ->mkdir 'my dir'->創(chuàng)建my dir文件夾
4.2scp傳文件
服務(wù)器和服務(wù)器之間傳數(shù)據(jù),可以:服務(wù)器->本地->服務(wù)器,免去服務(wù)器和服務(wù)器之間的授權(quán)過程
基本用法
命令格式:
scp source destination
將source
路徑下的文件復(fù)制到destination
中
一次復(fù)制多個文件:
scp source1 source2 destination
復(fù)制文件夾:
scp -r ~/tmp myserver:/home/acs/
將本地家目錄中的tmp
文件夾復(fù)制到myserver
服務(wù)器中的/home/acs/
目錄下。
scp -r ~/tmp myserver:homework/
將本地家目錄中的tmp
文件夾復(fù)制到myserver
服務(wù)器中的~/homework/
目錄下。
scp -r myserver:homework .
將myserver
服務(wù)器中的~/homework/
文件夾復(fù)制到本地的當(dāng)前路徑下。
指定服務(wù)器的端口號:
scp -P 22 source1 source2 destination
注意: scp
的-r -P
等參數(shù)盡量加在source
和destination
之前。
使用scp
配置其他服務(wù)器的vim
和tmux
scp ~/.vimrc ~/.tmux.conf myserver:
.vimrc配置文件
" An example for a vimrc file.
"
" To use it, copy it to
" for Unix and OS/2: ~/.vimrc
" for Amiga: s:.vimrc
" for MS-DOS and Win32: $VIM\_vimrc
" for OpenVMS: sys$login:.vimrc" When started as "evim", evim.vim will already have done these settings.
if v:progname =~? "evim"finish
endif" Use Vim settings, rather then Vi settings (much better!).
" This must be first, because it changes other options as a side effect.
set nocompatible" allow backspacing over everything in insert mode
set backspace=indent,eol,startif has("vms")set nobackup " do not keep a backup file, use versions instead
elseset backup " keep a backup file
endif
set history=50 " keep 50 lines of command line history
set ruler " show the cursor position all the time
set showcmd " display incomplete commands
set incsearch " do incremental searching
"==========================================================================
"My Setting-sunshanlu
"==========================================================================
vmap <leader>y :w! /tmp/vitmp<CR>
nmap <leader>p :r! cat /tmp/vitmp<CR>"語法高亮
syntax enable
syntax on
"顯示行號
set nu"修改默認(rèn)注釋顏色
"hi Comment ctermfg=DarkCyan
"允許退格鍵刪除
"set backspace=2
"啟用鼠標(biāo)
set mouse=a
set selection=exclusive
set selectmode=mouse,key
"按C語言格式縮進(jìn)
set cindent
set autoindent
set smartindent
set shiftwidth=4" 允許在有未保存的修改時切換緩沖區(qū)
"set hidden" 設(shè)置無備份文件
set writebackup
set nobackup"顯示括號匹配
set showmatch
"括號匹配顯示時間為1(單位是十分之一秒)
set matchtime=5
"顯示當(dāng)前的行號列號:
set ruler
"在狀態(tài)欄顯示正在輸入的命令
set showcmdset foldmethod=syntax
"默認(rèn)情況下不折疊
set foldlevel=100
" 開啟狀態(tài)欄信息
set laststatus=2
" 命令行的高度,默認(rèn)為1,這里設(shè)為2
set cmdheight=2" 顯示Tab符,使用一高亮豎線代替
set list
"set listchars=tab:\|\ ,
set listchars=tab:>-,trail:-"偵測文件類型
filetype on
"載入文件類型插件
filetype plugin on
"為特定文件類型載入相關(guān)縮進(jìn)文件
filetype indent on
" 啟用自動補全
filetype plugin indent on "設(shè)置編碼自動識別, 中文引號顯示
filetype on "打開文件類型檢測
"set fileencodings=euc-cn,ucs-bom,utf-8,cp936,gb2312,gb18030,gbk,big5,euc-jp,euc-kr,latin1
set fileencodings=utf-8,gb2312,gbk,gb18030
"這個用能很給勁,不管encoding是什么編碼,都能將文本顯示漢字
"set termencoding=gb2312
set termencoding=utf-8
"新建文件使用的編碼
set fileencoding=utf-8
"set fileencoding=gb2312
"用于顯示的編碼,僅僅是顯示
set encoding=utf-8
"set encoding=utf-8
"set encoding=euc-cn
"set encoding=gbk
"set encoding=gb2312
"set ambiwidth=double
set fileformat=unix"設(shè)置高亮搜索
set hlsearch
"在搜索時,輸入的詞句的逐字符高亮
set incsearch" 著色模式
set t_Co=256
"colorscheme wombat256mod
"colorscheme gardener
"colorscheme elflord
colorscheme desert
"colorscheme evening
"colorscheme darkblue
"colorscheme torte
"colorscheme default" 字體 && 字號
set guifont=Monaco:h10
"set guifont=Consolas:h10" :LoadTemplate 根據(jù)文件后綴自動加載模板
"let g:template_path='/home/ruchee/.vim/template/'" :AuthorInfoDetect 自動添加作者、時間等信息,本質(zhì)是NERD_commenter && authorinfo的結(jié)合
""let g:vimrc_author='sunshanlu'
""let g:vimrc_email='sunshanlu@baidu.com'
""let g:vimrc_homepage='http://www.sunshanlu.com'
"
"
" Ctrl + E 一步加載語法模板和作者、時間信息
""map <c-e> <ESC>:AuthorInfoDetect<CR><ESC>Gi
""imap <c-e> <ESC>:AuthorInfoDetect<CR><ESC>Gi
""vmap <c-e> <ESC>:AuthorInfoDetect<CR><ESC>Gi" ======= 引號 && 括號自動匹配 ======= "
"
":inoremap ( ()<ESC>i":inoremap ) <c-r>=ClosePair(')')<CR>
"
":inoremap { {}<ESC>i
"
":inoremap } <c-r>=ClosePair('}')<CR>
"
":inoremap [ []<ESC>i
"
":inoremap ] <c-r>=ClosePair(']')<CR>
"
":inoremap < <><ESC>i
"
":inoremap > <c-r>=ClosePair('>')<CR>
"
"":inoremap " ""<ESC>i
"
":inoremap ' ''<ESC>i
"
":inoremap ` ``<ESC>i
"
":inoremap * **<ESC>i" 每行超過80個的字符用下劃線標(biāo)示
""au BufRead,BufNewFile *.s,*.asm,*.h,*.c,*.cpp,*.java,*.cs,*.lisp,*.el,*.erl,*.tex,*.sh,*.lua,*.pl,*.php,*.tpl,*.py,*.rb,*.erb,*.vim,*.js,*.jade,*.coffee,*.css,*.xml,*.html,*.shtml,*.xhtml Underlined /.\%81v/
"
"
" For Win32 GUI: remove 't' flag from 'guioptions': no tearoff menu entries
" let &guioptions = substitute(&guioptions, "t", "", "g")" Don't use Ex mode, use Q for formatting
map Q gq" This is an alternative that also works in block mode, but the deleted
" text is lost and it only works for putting the current register.
"vnoremap p "_dp" Switch syntax highlighting on, when the terminal has colors
" Also switch on highlighting the last used search pattern.
if &t_Co > 2 || has("gui_running")syntax onset hlsearch
endif" Only do this part when compiled with support for autocommands.
if has("autocmd")" Enable file type detection." Use the default filetype settings, so that mail gets 'tw' set to 72," 'cindent' is on in C files, etc." Also load indent files, to automatically do language-dependent indenting.filetype plugin indent on" Put these in an autocmd group, so that we can delete them easily.augroup vimrcExau!" For all text files set 'textwidth' to 80 characters.autocmd FileType text setlocal textwidth=80" When editing a file, always jump to the last known cursor position." Don't do it when the position is invalid or when inside an event handler" (happens when dropping a file on gvim).autocmd BufReadPost *\ if line("'\"") > 0 && line("'\"") <= line("$") |\ exe "normal g`\"" |\ endifaugroup ENDelseset autoindent " always set autoindenting onendif " has("autocmd")" 增加標(biāo)行高亮
set cursorline
hi CursorLine cterm=NONE ctermbg=darkred ctermfg=white" 設(shè)置tab是四個空格
set ts=4
set expandtab" 主要給Tlist使用
let Tlist_Exit_OnlyWindow = 1
let Tlist_Auto_Open = 1
.tmux.config配置文件:
set-option -g status-keys vi
setw -g mode-keys visetw -g monitor-activity on# setw -g c0-change-trigger 10
# setw -g c0-change-interval 100# setw -g c0-change-interval 50
# setw -g c0-change-trigger 75set-window-option -g automatic-rename on
set-option -g set-titles on
set -g history-limit 100000#set-window-option -g utf8 on# set command prefix
set-option -g prefix C-a
unbind-key C-b
bind-key C-a send-prefixbind h select-pane -L
bind j select-pane -D
bind k select-pane -U
bind l select-pane -Rbind -n M-Left select-pane -L
bind -n M-Right select-pane -R
bind -n M-Up select-pane -U
bind -n M-Down select-pane -Dbind < resize-pane -L 7
bind > resize-pane -R 7
bind - resize-pane -D 7
bind + resize-pane -U 7bind-key -n M-l next-window
bind-key -n M-h previous-windowset -g status-interval 1
# status bar
set -g status-bg black
set -g status-fg blue#set -g status-utf8 on
set -g status-justify centre
set -g status-bg default
set -g status-left " #[fg=green]#S@#H #[default]"
set -g status-left-length 20# mouse support
# for tmux 2.1
# set -g mouse-utf8 on
set -g mouse on
#
# for previous version
#set -g mode-mouse on
#set -g mouse-resize-pane on
#set -g mouse-select-pane on
#set -g mouse-select-window on#set -g status-right-length 25
set -g status-right "#[fg=green]%H:%M:%S #[fg=magenta]%a %m-%d #[default]"# fix for tmux 1.9
bind '"' split-window -vc "#{pane_current_path}"
bind '%' split-window -hc "#{pane_current_path}"
bind 'c' new-window -c "#{pane_current_path}"# run-shell "powerline-daemon -q"# vim: ft=conf
5.1 git
1.git教程
代碼托管平臺:git.acwing.com
暫存區(qū)的內(nèi)容放到新的節(jié)點里面,HEAD后移一位
當(dāng)在其他分支修改后,回到master
分支,修改文件并創(chuàng)建新的節(jié)點(commit
),執(zhí)行merge
命令會有沖突(如git merge dev2
),此時vim 修改的文件,會有兩次修改的記錄,按自己需求修改后,git add.
-> git commit -m "xxxx"
,會在master
新創(chuàng)建一個節(jié)點,并把修改后的內(nèi)容和HEAD移到當(dāng)前節(jié)點,再刪掉分支(git branch -d dev2
)
將云端的分支拉下來,先創(chuàng)建和云端同名的分支(git checkout -b dev4
),然后執(zhí)行命令:git branch --set-upstream-to=origin/dev4 dev4
,將本地分支和云端分支對應(yīng)起,再執(zhí)行git pull
,將遠(yuǎn)程倉庫的當(dāng)前分支與本地倉庫的當(dāng)前分支合并
然后可以git checkout master
,將dev4合并到master,git merge dev4
,刪掉本地和云端的dev4git branch -d dev4
,git push -d origin dev4
,再用git push
同步到云端
暫存區(qū)有修改內(nèi)容,本地工作區(qū)也有修改內(nèi)容,如果服務(wù)器掛了,我們需要去修改,但是不想將當(dāng)前的內(nèi)容提交到日志(版本庫)里面,可以用git stash
,將當(dāng)前的修改存到一個棧里
分支:云端合并到云端:在分支中點擊“創(chuàng)建合并請求”,審核人改成leader,title去掉Draft,點擊“create 合并請求”,在“合并請求”里面點擊合并,則當(dāng)前分支會合并到master
1.1. git基本概念
-
工作區(qū):倉庫的目錄。工作區(qū)是獨立于各個分支的。
-
暫存區(qū):數(shù)據(jù)暫時存放的區(qū)域,類似于工作區(qū)寫入版本庫前的緩存區(qū)。暫存區(qū)是獨立于各
個分支的。
-
版本庫:存放所有已經(jīng)提交到本地倉庫的代碼版本
-
版本結(jié)構(gòu):樹結(jié)構(gòu),樹中每個節(jié)點代表一個代碼版本。
git add
:工作區(qū)代碼放到暫存區(qū)里,git commit -m "xxx"
最后提交到版本庫里
1.2 git常用命令
-
git config --global user.name xxx
:設(shè)置全局用戶名,信息記錄在~/.gitconfig
文件中 -
git config --global user.email xxx@xxx.com
:設(shè)置全局郵箱地址,信息記錄在~/.gitconfig
文件中 -
git init
:將當(dāng)前目錄配置成git倉庫,信息記錄在隱藏的.git文件夾中 -
git remote add origin git@git.acwing.com:xxx/XXX.git
:第一次連接遠(yuǎn)程git倉庫 -
git remote set-url origin git@git.acwing.com:xxx/XXX.git
:更換git倉庫 -
git add XX
:將XX文件添加到暫存區(qū)- git add .`:將所有待加入暫存區(qū)的文件加入暫存區(qū)
-
git rm --cached XX
:將文件從倉庫索引目錄中刪掉( 刪除暫存區(qū)中的某個文件) -
git commit -m "給自己看的備注信息"
:將暫存區(qū)的內(nèi)容提交到當(dāng)前分支 -
git status
:查看倉庫狀態(tài) -
git diff XX
:查看XX文件相對于暫存區(qū)修改了哪些內(nèi)容git diff
:當(dāng)工作區(qū)有改動,臨時區(qū)為空,diff的對比是“工作區(qū)與最后一次commit提交的倉庫的共同文件”;當(dāng)工作區(qū)有改動,臨時區(qū)不為空,diff對比的是“工作區(qū)與暫存區(qū)的共同文件”。
-
git log
:查看當(dāng)前分支的所有版本(按q退出)git log --pretty=oneline
:放在一行顯示
-
git reflog
:查看HEAD指針的移動歷史(包括被回滾的版本) -
git reset --hard HEAD^
或git reset --hard HEAD~
:將代碼庫回滾到上一個版本-
git reset --hard HEAD^^
:往上回滾兩次,以此類推 -
git reset --hard HEAD~100
:往上回滾100個版本 -
git reset --hard 版本號
:回滾到某一特定版本 -
git reset .
: 撤銷上一次提交暫存區(qū)的操作 -
git reset
: 保留工作目錄,并清空暫存區(qū)。也就是說,工作目錄的修改、暫存區(qū)的內(nèi)容以及由 reset 所導(dǎo)致的新的文件差異,都會被放進(jìn)工作目錄。簡而言之,就是「把所有差異都混合(mixed)放在工作目錄中」
-
-
git checkout — XX
或git restore XX
:將XX文件尚未加入暫存區(qū)的修改全部撤銷 -
git remote add origin git@git.acwing.com:xxx/XXX.git
:將本地倉庫關(guān)聯(lián)到遠(yuǎn)程倉庫 -
git push -u (第一次需要-u以后不需要)
:將當(dāng)前分支推送到遠(yuǎn)程倉庫(-u 參數(shù)相當(dāng)于是讓你本地的倉庫和遠(yuǎn)程倉庫進(jìn)行了關(guān)聯(lián),加了參數(shù)-u后,以后即可直接用git push 代替git push origin master)git push origin branch_name
:將本地的某個分支推送到遠(yuǎn)程倉庫
-
git clone git@git.acwing.com:xxx/XXX.git
:將遠(yuǎn)程倉庫XXX下載到當(dāng)前目錄下 -
git checkout -- .
:撤銷本地全部沒有g(shù)it add過的修改 -
git checkout -b branch_name
:創(chuàng)建并切換到branch_name
這個分支 -
git branch
:查看所有分支和當(dāng)前所處分支 -
git checkout branch_name
:切換到branch_name
這個分支 -
git merge branch_name
:將分支branch_name
合并到當(dāng)前分支上 -
git branch -d branch_name
:刪除本地倉庫的branch_name
分支 -
git branch branch_name
:創(chuàng)建新分支 -
git push --set-upstream origin branch_name
:設(shè)置本地的branch_name
分支對應(yīng)遠(yuǎn)程倉庫的branch_name
分支 -
git push -d origin branch_name
:刪除遠(yuǎn)程倉庫的branch_name
分支 -
git pull
:將遠(yuǎn)程倉庫的當(dāng)前分支與本地倉庫的當(dāng)前分支合并git pull origin branch_name
:將遠(yuǎn)程倉庫的branch_name
分支與本地倉庫的當(dāng)前分支合并
-
git branch --set-upstream-to=origin/branch_name1 branch_name2
:將遠(yuǎn)程的branch_name1
分支與本地的branch_name2
分支對應(yīng) -
git checkout -t origin/branch_name
將遠(yuǎn)程的branch_name
分支拉取到本地 -
git stash
:將工作區(qū)和暫存區(qū)中尚未提交的修改存入棧中 -
git stash apply
:將棧頂存儲的修改恢復(fù)到當(dāng)前分支,但不刪除棧頂元素 -
git stash drop
:刪除棧頂存儲的修改 -
git stash pop
:將棧頂存儲的修改恢復(fù)到當(dāng)前分支,同時刪除棧頂元素 -
git stash list
:查看棧中所有元素
2.創(chuàng)建作業(yè) & 測試作業(yè)的正確性
homework 5 create # 可以重新創(chuàng)建所有l(wèi)esson_5的作業(yè)
homework 5 test # 可以評測lesson_5的所有作業(yè)
3.git命令分類整理
全局設(shè)置
- git config --global user.name xxx:設(shè)置全局用戶名,信息記錄在~/.gitconfig文件中
- git config --global user.email xxx@xxx.com:設(shè)置全局郵箱地址,信息記錄在~/.gitconfig文件中
- git init:將當(dāng)前目錄配置成git倉庫,信息記錄在隱藏的.git文件夾中
常用命令
- git add XX :將XX文件添加到暫存區(qū)
- git commit -m “給自己看的備注信息”:將暫存區(qū)的內(nèi)容提交到當(dāng)前分支
- git status:查看倉庫狀態(tài)
- git log:查看當(dāng)前分支的所有版本
- git push -u (第一次需要-u以后不需要) :將當(dāng)前分支推送到遠(yuǎn)程倉庫
- git clone git@git.acwing.com:xxx/XXX.git:將遠(yuǎn)程倉庫XXX下載到當(dāng)前目錄下
- git branch:查看所有分支和當(dāng)前所處分支
查看命令
- git diff XX:查看XX文件相對于暫存區(qū)修改了哪些內(nèi)容
- git status:查看倉庫狀態(tài)
- git log:查看當(dāng)前分支的所有版本
- git log --pretty=oneline:用一行來顯示
- git reflog:查看HEAD指針的移動歷史(包括被回滾的版本)
- git branch:查看所有分支和當(dāng)前所處分支
- git pull :將遠(yuǎn)程倉庫的當(dāng)前分支與本地倉庫的當(dāng)前分支合并
刪除命令
- git rm --cached XX:將文件從倉庫索引目錄中刪掉,不希望管理這個文件
- git restore --staged xx:將xx從暫存區(qū)里移除
- git checkout — XX或git restore XX:將XX文件尚未加入暫存區(qū)的修改全部撤銷
代碼回滾
- git reset --hard HEAD^ 或git reset --hard HEAD~ :將代碼庫回滾到上一個版本
- git reset --hard HEAD^^:往上回滾兩次,以此類推
- git reset --hard HEAD~100:往上回滾100個版本
- git reset --hard 版本號:回滾到某一特定版本
遠(yuǎn)程倉庫
-
git remote add origin git@git.acwing.com:xxx/XXX.git:將本地倉庫關(guān)聯(lián)到遠(yuǎn)程倉庫
-
git push -u (第一次需要-u以后不需要) :將當(dāng)前分支推送到遠(yuǎn)程倉庫
-
git push origin branch_name:將本地的某個分支推送到遠(yuǎn)程倉庫
-
git clone git@git.acwing.com:xxx/XXX.git:將遠(yuǎn)程倉庫XXX下載到當(dāng)前目錄下
-
git push --set-upstream origin branch_name:設(shè)置本地的branch_name分支對應(yīng)遠(yuǎn)程倉庫的branch_name分支
-
git push -d origin branch_name:刪除遠(yuǎn)程倉庫的branch_name分支
-
git checkout -t origin/branch_name 將遠(yuǎn)程的branch_name分支拉取到本地
-
git pull :將遠(yuǎn)程倉庫的當(dāng)前分支與本地倉庫的當(dāng)前分支合并
-
git pull origin branch_name:將遠(yuǎn)程倉庫的branch_name分支與本地倉庫的當(dāng)前分支合并
-
git branch --set-upstream-to=origin/branch_name1 branch_name2:將遠(yuǎn)程的branch_name1分支與本地的branch_name2分支對應(yīng)
分支命令
-
git branch branch_name:創(chuàng)建新分支
-
git branch:查看所有分支和當(dāng)前所處分支
-
git checkout -b branch_name:創(chuàng)建并切換到branch_name這個分支
-
git checkout branch_name:切換到branch_name這個分支
-
git merge branch_name:將分支branch_name合并到當(dāng)前分支上
-
git branch -d branch_name:刪除本地倉庫的branch_name分支
-
git push --set-upstream origin branch_name:設(shè)置本地的branch_name分支對應(yīng)遠(yuǎn)程倉庫的branch_name分支
-
git push -d origin branch_name:刪除遠(yuǎn)程倉庫的branch_name分支
-
git checkout -t origin/branch_name 將遠(yuǎn)程的branch_name分支拉取到本地
-
git pull :將遠(yuǎn)程倉庫的當(dāng)前分支與本地倉庫的當(dāng)前分支合并
-
git pull origin branch_name:將遠(yuǎn)程倉庫的branch_name分支與本地倉庫的當(dāng)前分支合并
-
git branch --set-upstream-to=origin/branch_name1 branch_name2:將遠(yuǎn)程的branch_name1分支與本地的branch_name2分支對應(yīng)
stash暫存
- git stash:將工作區(qū)和暫存區(qū)中尚未提交的修改存入棧中
- git stash apply:將棧頂存儲的修改恢復(fù)到當(dāng)前分支,但不刪除棧頂元素
- git stash drop:刪除棧頂存儲的修改
- git stash pop:將棧頂存儲的修改恢復(fù)到當(dāng)前分支,同時刪除棧頂元素
- git stash list:查看棧中所有元素
一些問題
解決git push -u origin master
后的:
The authenticity of host 'git.acwing.com (47.93.222.173)' can't be established.
ECDSA key fingerprint is SHA256:OxENYBI4n6Nd8yOqmEdMazWuvBldKlP6ZJnOAAbCaeM.
Are you sure you want to continue connecting (yes/no/[fingerprint])?
輸入yes,將git.acwing.com永久加入到已知主機(jī)列表中
Warning: Permanently added 'git.acwing.com,47.93.222.173' (ECDSA) to the list of known hosts.
Enumerating objects: 10, done.
Counting objects: 100% (10/10), done.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (10/10), 850 bytes | 850.00 KiB/s, done.
Total 10 (delta 0), reused 0 (delta 0)
To git.acwing.com:DrinkWater/project.git* [new branch] master -> master
Branch 'master' set up to track remote branch 'master' from 'origin'.
刷新git.acwing.com的項目可出現(xiàn)歷史文件與數(shù)據(jù)
git remote add origin git@git.acwing.com:xxx
時出現(xiàn)fatal:remote origin already exist
解決方案:刪除現(xiàn)有origin倉庫: git remote remove origin
,然后再輸入上面的命令,輸入git push -u origin master
,push本地內(nèi)容到云端
報錯:git錯誤 ! [rejected] master -> master (non-fast-forward)
解決:git pull --rebase origin master
關(guān)于 git restore
git restore 命令用于恢復(fù),恢復(fù)有兩種:從暫存區(qū)恢復(fù)到工作區(qū)(即暫存區(qū)內(nèi)容copy還原工作區(qū))、從HEAD所指版本庫恢復(fù)到暫存區(qū)(版本庫內(nèi)容copy還原暫存區(qū))
1. git restore -- filename # git restore指令使得在工作空間但是不在暫存區(qū)的文件撤銷更改(內(nèi)容恢復(fù)到?jīng)]修改之前的狀態(tài)) -- 可以不加
2. git restore --staged filename # 是將暫存區(qū)的文件從暫存區(qū)撤出,但不會更改文件的內(nèi)容。
另外,git checkout -- filename
作用與git restore -- filename
一致,都是將文件從暫存區(qū)恢復(fù)到工作區(qū)。
版本恢復(fù)中, git reset --hard HEAD^
是將上個版本的內(nèi)容copy到工作區(qū)以及暫存區(qū),效果應(yīng)該等同于順序執(zhí)行上述的 2、1 命令(即版本庫先copy到暫存區(qū),然后暫存區(qū)copy到工作區(qū))。
關(guān)于 git rm
git rm filename
用于刪除,如果工作區(qū)和暫存區(qū)都有名字為 filename 的文件,那么會給出提示是否要強制刪除該文件(同一執(zhí)行后工作區(qū)和暫存區(qū)該文件都會消失),如果工作區(qū)中該文件已經(jīng)刪除但暫存區(qū)還有,那么該命令直接執(zhí)行,將從暫存區(qū)中刪除該文件(此時效果等同于直接 git add .,將工作區(qū)更改應(yīng)用于暫存區(qū))。
另一方面,git rm --cached filename
僅僅是在暫存區(qū)中將該文件刪除,取消跟蹤(類似于工作區(qū)中剛創(chuàng)建該文件還沒有add到暫存區(qū)),工作區(qū)沒有任何變化。
綜上,git restore 用于恢復(fù),數(shù)據(jù)有兩種流向;git rm 用于刪除,主要是使用 –cached 參數(shù)來刪除暫存區(qū)的內(nèi)容。假如目前HEAD所指版本中沒有該文件,而 工作區(qū)和暫存區(qū)都有,那么 git restore --staged
將和git rm --cached
效果相同。
6. thrift-rpc框架
一個節(jié)點上的服務(wù)器進(jìn)程想調(diào)用另一個服務(wù)器上的進(jìn)程可以用thrift
不同的進(jìn)程可以用不同的語言來實現(xiàn)
thrift三步
1.定義接口
2.server
3.client
匹配系統(tǒng)項目實現(xiàn)
游戲節(jié)點需要實現(xiàn)match_client端,匹配系統(tǒng)需要實現(xiàn)match_server和save_client端
項目代碼和筆記
#最終項目的結(jié)構(gòu)樹
|-- game
| `-- src
| |-- client.py
| `-- match_client
| |-- __init__.py
| |-- __pycache__
| | `-- __init__.cpython-38.pyc
| `-- match
| |-- Match.py
| |-- __init__.py
| |-- __pycache__
| | |-- Match.cpython-38.pyc
| | |-- __init__.cpython-38.pyc
| | `-- ttypes.cpython-38.pyc
| |-- constants.py
| `-- ttypes.py
|-- match_system
| `-- src
| |-- Match.o
| |-- Save.o
| |-- main
| |-- main.cpp
| |-- main.o
| |-- maintmp.cpp
| |-- match_server
| | |-- Match.cpp
| | |-- Match.h
| | |-- match_types.cpp
| | `-- match_types.h
| |-- match_types.o
| `-- save_client
| |-- Save.cpp
| |-- Save.h
| `-- save_types.h
|-- readme.md
`-- thrift|-- match.thrift`-- save.thrift
//main.cpp 的所有頭文件
#include "match_server/Match.h"
#include "save_client/Save.h"
#include <thrift/concurrency/ThreadManager.h>
#include <thrift/concurrency/ThreadFactory.h>
#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/server/TSimpleServer.h>
#include <thrift/server/TThreadPoolServer.h>
#include <thrift/server/TThreadedServer.h>
#include <thrift/transport/TServerSocket.h>
#include <thrift/transport/TBufferTransports.h>
#include <thrift/transport/TTransportUtils.h>
#include <thrift/transport/TSocket.h>
#include <thrift/TToString.h>#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <vector>
#include <unistd.h>
接口實現(xiàn)
創(chuàng)建相關(guān)文件夾,編寫接口:/thrift/match.thrift
namespace cpp match_servicestruct User {1: i32 id,2: string name,3: i32 score
}service Match {i32 add_user(1: User user, 2: string info),i32 remove_user(1: User user, 2: string info),
}
實現(xiàn)match_server
通過thrift -r --gen cpp ../../thrift/match.thrift
,生成一個C++的服務(wù)器,里面包括了一個gen-cpp文件夾,所有的基礎(chǔ)c++代碼都通過上層命令自動生成,(類似gRPC的作用),實現(xiàn)接口的函數(shù)在Match_server.skeleton.cpp
文件中。
mv match_server/Match_server.skeleton.cpp main.cpp
,在main.cpp里修改Match.h頭文件的路徑:#include "match_server/Match.h"
然后輸入: g++ -c main.cpp match_server/*.cpp
(表示用match_server里面的.cpp文件來編譯main.cpp),然后用g++ *.o -o main -lthrift
進(jìn)行鏈接后就可以用./main
進(jìn)行起來了。每次修改c++文件后用g++ -c main.cpp
重新編譯,鏈接g++ *.o -o main -lthrift
,然后執(zhí)行./main
就能運行了。(Ctrl+c停止運行)
記得刪除skeleton.cpp函數(shù)再編譯鏈接
每完成一個文件或者階段記得git add .
,commit
,push
,保存記錄,一般來說.o
可執(zhí)行文件和編譯后的文件不上傳到云端,git add . 后記得用git restore --stage *.o
,git restore --stage main
把這些文件移出暫存區(qū)
良好習(xí)慣:每次進(jìn)入相關(guān)文件夾記得mkdir src
,在該目錄下生成代碼
客戶端實現(xiàn)
進(jìn)入到/game里面寫python代碼:
進(jìn)入src/,輸入thrift -r --gen py ../../thrift/match.thrift
,重命名為match_client,在match_client/match/
下有可執(zhí)行文件 Match-remote
,該文件是用來寫Python服務(wù)器端的,本項目只需要在這里實現(xiàn)客戶端,所以刪掉這個文件。
直接把上圖的client端的例子的代碼復(fù)制下來,進(jìn)行修改,vim client.py,前四行代碼刪掉,引入正確路徑from match_client.match import Match from match_client.match.ttypes import User
#client.py
from match_client.match import Match
from match_client.match.ttypes import Userfrom thrift import Thrift
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocoldef main():# Make sockettransport = TSocket.TSocket('127.0.0.1', 9090)# Buffering is critical. Raw sockets are very slowtransport = TTransport.TBufferedTransport(transport)# Wrap in a protocolprotocol = TBinaryProtocol.TBinaryProtocol(transport)# Create a client to use the protocol encoderclient = Match.Client(protocol)# Connect!transport.open()user = User(1,'zyt',1500)client.add_user(user,"")# Close!transport.close()if __name__ == "__main__":main()
將服務(wù)器開啟./main
然后在客戶端的src/下,運行.py文件,python3 client.py
,可以看到服務(wù)器輸出了一個add_user
,成功用python調(diào)用了一個c++的進(jìn)程的函數(shù)
在src/目錄下保存一下git add .
,.pyc文件不要上傳到云端,git restore --stage *.pyc
,git restore --stage *.swp
,git commit -m "add match client"
,git push
修改client.py為從命令行讀入用戶信息的形式:
from match_client.match import Match
from match_client.match.ttypes import Userfrom thrift import Thrift
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocolfrom sys import stdindef operate(op, user_id, username, score):# Make sockettransport = TSocket.TSocket('127.0.0.1', 9090)# Buffering is critical. Raw sockets are very slowtransport = TTransport.TBufferedTransport(transport)# Wrap in a protocolprotocol = TBinaryProtocol.TBinaryProtocol(transport)# Create a client to use the protocol encoderclient = Match.Client(protocol)# Connect!transport.open()user = User(user_id, username, score)if op == "add":client.add_user(user,"")elif op == "remove":client.remove_user(user,"")# Close!transport.close()def main():for line in stdin:op, user_id, username, score = line.split(' ')operate(op, int(user_id), username, int(score))if __name__ == "__main__":main()
記得user_id和score為int類型
client端代碼完成,如上所示,記得git add client.py
然后commit
,push
server端實現(xiàn)
(修改main.cpp代碼)
因為用戶的添加和用戶之間的匹配是并行的,所以給匹配單獨開一個線程,
生產(chǎn)者-消費者模型:要想實現(xiàn)生產(chǎn)者和消費者之間的通信可以使用消息隊列,需要用到mutex鎖,PV操作,實現(xiàn)互斥共享操作,實現(xiàn)的數(shù)據(jù)結(jié)構(gòu)如下所示:
struct Task
{User user;string type;
};
struct MessageQueue
{queue<Task> q;mutex m;condition_variable cv;
}message_queue;
開一個線程thread matching_thread(consume_task)
消息隊列每次加入用戶以及操作前都要鎖住,保證所有和隊列相關(guān)操作同一時間只有一個線程在操作它unique_lock<mutex> lck(message_queue.m);
,該做法能讓當(dāng)該變量被注銷時不需要顯示解鎖,它會自動解鎖。
這里表示每次只能有一個線程拿到鎖,另一個線程會停下來,直到前一個拿到鎖的線程執(zhí)行完它的函數(shù),此時才能釋放鎖,執(zhí)行該線程拿到鎖。
如果一個線程中消息隊列為空,那么應(yīng)該阻塞住線程,否則會一直消費者死循環(huán)下去浪費CPU資源,直到有新的玩家加入線程。阻塞線程:message_queue.cv.wait(lck);
,喚醒線程:message_queue.cv.notify_all();
,通知所有被cv卡住的線程,隨機(jī)執(zhí)行其中一個,因為這里只有一個線程,所以也可以用message_queue.cv.notify_one();
將所有用戶放到一個玩家池里面,相關(guān)數(shù)據(jù)結(jié)構(gòu)如下:記得池里的for操作要break
class Pool
{public:void save_result(int a, int b){//如果這里不加\n會導(dǎo)致在add 第三個用戶的時候同時輸出前兩個的id和add user字符串,不知道原因,可能是不加\n會被阻塞?printf("Match Result: %d %d\n", a, b);}void match(){while(users.size()>1){auto a = users[0],b = users[1];users.erase(users.begin());users.erase(users.begin());save_result(a.id, b.id);}}void add(User user){users.push_back(user);}void remove(User user){for(uint32_t i = 0; i < users.size(); i++ ){if(users[i].id == user.id){users.erase(users.begin() + i);}}}private:vector<User> users;
}pool;
每次執(zhí)行任務(wù)的時候,根據(jù)類型選擇匹配池的操作,并進(jìn)行匹配操作pool.match()
void consume_task(){while(true){unique_lock<mutex> lck(message_queue.m);if(message_queue.q.empty()){message_queue.cv.wait(lck);}-else{auto task = message_queue.q.front();message_queue.q.pop();lck.unlock();//remember to unlock//do taskif(task.type == "add") pool.add(task.user); else if(task.type == "remove")pool.remove(task.user);pool.match();}}
}
完成所有代碼后進(jìn)行編譯,鏈接,因為此時用到了線程,所以鏈接的時候的命令為:g++ *.o -o main -lthrift -pthread
記得git add main.cpp
然后commit
,git push
實現(xiàn)數(shù)據(jù)存儲功能
記得要加頭文件#include "save_client/Save.h"
命名空間:save_service
求一個字符串md5值:在命令行寫入md5sum
按回車鍵,輸入字符串,按ctrl+d就能出來它的md5值。
namespace cpp save_serviceservice Save {/*** username: myserver的名稱* password: myserver的密碼的md5sum的前8位* 用戶名密碼驗證成功會返回0,驗證失敗會返回1* 驗證成功后,結(jié)果會被保存到myserver:homework/lesson_6/result.txt中*/i32 save_data(1: string username, 2: string password, 3: i32 player1_id, 4: i32 player2_id)
}
在y總的git項目中把save.thrift
的代碼粘貼下來,寫入thrift/目錄,在match_system/src下使用thrift -r --gen cpp ../../thrift/save.thrift
生成相關(guān)實現(xiàn)接口的C++文件,重命名mv gen-cpp/ save_client
,因為我們只需要實現(xiàn)客戶端,所以刪除服務(wù)器端生成的文件rm Save_server.skeleton.cpp
編寫客戶端的代碼:在C++ Tutorial把代碼對著main.cpp改,沒有的頭文件要加上,將save_client里面的頭文件導(dǎo)入進(jìn)去#include "save_client/Save.h"
,因為save.thrift
里面使用了命名空間,因此也要加入main.cpp中using namespace ::save_service;
,把樣例文件中的main函數(shù)部分都復(fù)制下來,粘貼到save_result()函數(shù)中,進(jìn)行修改:
void save_result(int a, int b){printf("Match Result: %d %d\n", a, b);std::shared_ptr<TTransport> socket(new TSocket("123.57.47.211", 9090));std::shared_ptr<TTransport> transport(new TBufferedTransport(socket));std::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));SaveClient client(protocol);try {transport->open();client.save_data("myserver的用戶名","md5密碼前8位",a,b);transport->close();} catch (TException& tx) {cout << "ERROR: " << tx.what() << endl; }}
進(jìn)行編譯鏈接:g++ -c save_client/*.cpp
,g++ -c main.cpp
,g++ *.o -o main -lthrift -pthread
因為一直在服務(wù)器中看不到存儲的result.txt文件,反復(fù)檢查,發(fā)現(xiàn)是密碼的md5前八位寫錯了,第一次生成的應(yīng)該是因為多加了回車鍵,所以生成的md5是錯誤的,修改后就能看到保存的數(shù)據(jù)文件了。
記得git add
以下文件, git commit -m "implements save-client"
,git push
升級匹配系統(tǒng)
1.按分差來匹配,每一秒鐘匹配一次
if(message_queue.q.empty()){// message_queue.cv.wait(lck);lck.unlock();pool.match();sleep(1); }
void match(){while (users.size() > 1){sort(users.begin(),users.end(),[&](User& a, User b){return a.score < b.score;});bool flag = true;for (uint32_t i=1; i < users.size(); i++){auto a = users[i-1],b = users[i];if(b.score-a.score<=50){users.erase(users.begin()+i-1,users.begin()+i+1);save_result(a.id,b.id);flag = false;break;}}if(flag) break;}}
記得git add main.cpp
,git commit -m "match-server:3.0"
,git push
2.使用多線程服務(wù)器(2:02:16)
在該網(wǎng)頁的Server代碼樣例中,粘貼需要的頭文件和代碼,并進(jìn)行修改。
int main(int argc, char **argv) {TThreadedServer server(std::make_shared<MatchProcessorFactory>(std::make_shared<MatchCloneFactory>()),std::make_shared<TServerSocket>(9090), //portstd::make_shared<TBufferedTransportFactory>(),std::make_shared<TBinaryProtocolFactory>());---cout << "Start Match Server" << endl;thread matching_thread(consume_task);server.serve();return 0;
}
粘貼CloneFactory函數(shù),:1,$s/Calculator/Match/g
,替換所有Calculator的字,
class MatchCloneFactory : virtual public MatchIfFactory {public:~MatchCloneFactory() override = default;MatchIf* getHandler(const ::apache::thrift::TConnectionInfo& connInfo) override {std::shared_ptr<TSocket> sock = std::dynamic_pointer_cast<TSocket>(connInfo.transport);/*cout << "Incoming connection\n";cout << "\tSocketInfo: " << sock->getSocketInfo() << "\n";cout << "\tPeerHost: " << sock->getPeerHost() << "\n";cout << "\tPeerAddress: " << sock->getPeerAddress() << "\n";cout << "\tPeerPort: " << sock->getPeerPort() << "\n";*/return new MatchHandler;}void releaseHandler(MatchIf* handler) override {delete handler;}
};
記得push上去 git add main.cpp
,git commit -m "match-server:4.0
,git push
3.每隔1s增加搜索分?jǐn)?shù)的范圍,比如以50倍每秒增加:
bool check_match(uint32_t i, uint32_t j){auto a = users[i],b = users[j];int dt = abs(a.score - b.score);int a_max_dif = wt[i] * 50; int b_max_dif = wt[j] * 50; return dt<=a_max_dif && dt<=b_max_dif;}void match(){for(uint32_t i=0; i < wt.size(); i++) wt[i]++;while (users.size() > 1){ bool flag = true;for(uint32_t i=0; i < users.size(); i++){for(uint32_t j=i+1; j < users.size(); j++){if(check_match(i,j)){auto a = users[i],b = users[j]; //先刪除排序在后的,不然erase會亂掉users.erase(users.begin() + j); users.erase(users.begin() + i); wt.erase(wt.begin() + j);wt.erase(wt.begin() + i);save_result(a.id, b.id);flag = false;break;}}if(!flag) break;}if(flag) break;}}
void consume_task(){while(true){unique_lock<mutex> lck(message_queue.m);if(message_queue.q.empty()){// message_queue.cv.wait(lck);lck.unlock();pool.match();sleep(1);}-else{auto task = message_queue.q.front();message_queue.q.pop();lck.unlock();//remember to unlock//do taskif(task.type == "add") pool.add(task.user);else if(task.type == "remove")pool.remove(task.user);}}
}
記得提交git add main.cpp
,git commit -m "match-server:5.0"
,git push
class Pool
{public: void save_result(int a,int b){ printf("Match Result: %d %d\n", a, b); }bool check_match(uint32_t i, uint32_t j){ auto a= users[i], b = users[j];int dt = abs(a.score-b.score);int a_max_dif = wt[i] * 50; int b_max_dif = wt[j] * 50; return dt <= a_max_dif && dt <= b_max_dif;}void match(){for(uint32_t i=0; i < wt.size(); i++) wt[i]++;while(users.size() > 1){ bool flag = true;for(uint32_t i=0; i < users.size(); i++){for(uint32_t j=i+1; j < users.size();j++){if(check_match(i,j){auto a = users[i],b = users[j];users.erase(users.begin() + j); users.erase(users.begin() + i); wt.erase(wt.begin() + j); wt.erase(wt.begin() + i); save_result(a.id, b.id);flag=false;break;}}if(!flag)break;}if(flag)break;} }void add(User user){users.push_back(user);wt.push_back(0);}void remove(User user){for(uint32_t i=0; i < users.size(); i++){if(users[i].id == user.id){users.erase(users.begin() + i);wt.erase(wt.begin() + i);}}}private:vector<User> users;vector<int> wt;}pool;
重做一遍的時候發(fā)現(xiàn)大部分的錯誤都是因為在編譯的時候忘了先要用/match_server
下和/save-client
下的c++文件進(jìn)行編譯,其他邏輯上的問題還好,不過對生產(chǎn)者-消費者模型及其對應(yīng)實現(xiàn)還有鎖和多線程等都不太熟練,目前主要是靠背。
看一下為什么Calculator修改為Match/Save
首先判斷當(dāng)前函數(shù)是用來做什么功能的,client/server?對應(yīng)的方法在哪個thrift生成的頭文件下,官網(wǎng)中示例的Calculator
改成相應(yīng)的xxx.h
中的xxx
例如#include "save_client/Save.h"
在save_result的時候?qū)?yīng)的Calculator
就要改成Save
#include "match_server/Match.h"
其他大部分都是針對match_serve
r的,相應(yīng)改成Match
void releaseHandler(::shared::SharedServiceIf *handler) override {delete handler;}
改成:
void releaseHandler(MatchIf *handler) override {delete handler;}
在Match.cpp
文件中查到
所以在釋放handler這里類型應(yīng)該為Match。
在Match.h
頭文件中也看到和Handler相關(guān)的操作都是MatchIf類型的
知識補充
c++ mutex鎖
參考文檔1
鎖是由信號量來實現(xiàn)的,mutex->互斥量,信號量=1。
多個線程共享一個變量的時候會產(chǎn)生讀寫沖突,需要上鎖。鎖進(jìn)一步引入了條件變量這一概念。
在編程中,引入了對象互斥鎖的概念,來保證共享數(shù)據(jù)操作的完整性。每個對象都對應(yīng)于一個可稱為" 互斥鎖" 的標(biāo)記,這個標(biāo)記用來保證在任一時刻,只能有一個線程訪問該對象。
鎖有兩個操作。一個P操作(上鎖),一個V操作(解鎖)。 定義互斥鎖:mutex m; 鎖一般使用信號量來實現(xiàn)的,mutex其實就是一個信號量(它特殊也叫互斥量)。互斥量就是同一時間能夠分給一個人,即S=1。 信號量S:S=10表示可以將信號量分給10個人來用。
unique_lock<mutex> lck(message_queue.m)
定義互斥鎖,并完成“加鎖”過程
message_queue.cv.notify_all()
通知條件變量,所有被條件變量睡眠的線程通知一下,鎖已經(jīng)釋放掉了,可以繼續(xù)執(zhí)行了。
解鎖:lck.unlock()
對消息隊列要進(jìn)行某種操作前要解鎖
阻塞:message_queue.cv.wait(lck)
相當(dāng)于V操作,將鎖釋放掉,同時卡死這句話,知道其他程序喚醒(notify)它為止
上圖中沒有l(wèi)ck.unlock()是因為lck有一個析構(gòu)函數(shù),在這個函數(shù)執(zhí)行完的時候會自動解鎖。
類的析構(gòu)函數(shù)是類的一種特殊的成員函數(shù),它會在每次刪除所創(chuàng)建的對象時執(zhí)行。
析構(gòu)函數(shù)的名稱與類的名稱是完全相同的,只是在前面加了個波浪號(~)作為前綴,它不會返回任何值,也不能帶有任何參數(shù)。析構(gòu)函數(shù)有助于在跳出程序(比如關(guān)閉文件、釋放內(nèi)存等)前釋放資源。
P操作的主要動作是: ①S減1; ②若S減1后仍大于或等于0,則進(jìn)程繼續(xù)執(zhí)行;
③若S減1后小于0,則該進(jìn)程被阻塞后放入等待該信號量的等待隊列中,然后轉(zhuǎn)進(jìn)程調(diào)度。
V操作的主要動作是: ①S加1; ②若相加后結(jié)果大于0,則進(jìn)程繼續(xù)執(zhí)行; ③若相加后結(jié)果小于或等于0,則從該信號的等待隊列中釋放一個等待進(jìn)程,然后再返回原進(jìn)程繼續(xù)執(zhí)行或轉(zhuǎn)進(jìn)程調(diào)度。
對于P和V都是原子操作,就是在執(zhí)行P和V操作時,不會被插隊。從而實現(xiàn)對共享變量操作的原子性。 特殊:S=1表示互斥量,表示同一時間,信號量只能分配給一個線程。
std::unique_lock:方便線程對互斥量上鎖,但提供了更好的上鎖和解鎖控制。
c++ 條件變量
參考文檔1
參考文檔2
條件變量是利用線程間共享的全局變量進(jìn)行同步的一種機(jī)制,主要包括兩個動作:一個線程等待
條件變量的條件成立而掛起;另一個線程使條件成立(給出條件成立信號)。為了防止競爭,條件變量的使用總是和一個互斥量結(jié)合在一起。
條件變量是一個對象,能夠在通知恢復(fù)之前阻止調(diào)用線程。它使用在調(diào)用其等待函數(shù)之一時鎖定線程。線程將保持阻塞狀態(tài),直到被另一個調(diào)用同一對象上的通知函數(shù)的線程喚醒。
c++ 多線程
開啟一個線程:thread 線程名(線程函數(shù))
參考文檔1
參考文檔2
- 多線程并發(fā)
多線程并發(fā)指的是在同一個進(jìn)程中執(zhí)行多個線程。
優(yōu)點:有操作系統(tǒng)相關(guān)知識的應(yīng)該知道,線程是輕量級的進(jìn)程,每個線程可以獨立的運行不同的指令序列,但是線程不獨立的擁有資源,依賴于創(chuàng)建它的進(jìn)程而存在。也就是說,同一進(jìn)程中的多個線程共享相同的地址空間,可以訪問進(jìn)程中的大部分?jǐn)?shù)據(jù),指針和引用可以在線程間進(jìn)行傳遞。這樣,同一進(jìn)程內(nèi)的多個線程能夠很方便的進(jìn)行數(shù)據(jù)共享以及通信,也就比進(jìn)程更適用于并發(fā)操作。
缺點:由于缺少操作系統(tǒng)提供的保護(hù)機(jī)制,在多線程共享數(shù)據(jù)及通信時,就需要程序員做更多的工作以保證對共享數(shù)據(jù)段的操作是以預(yù)想的操作順序進(jìn)行的,并且要極力的避免死鎖(deadlock)。
-
thrift教程
-
thrift官網(wǎng)
-
上課代碼地址
-
可用的thrift tutorial地址
-
創(chuàng)建作業(yè) & 測試作業(yè)的正確性
homework 6 create # 可以重新創(chuàng)建所有l(wèi)esson_6的作業(yè)
homework 6 test # 可以評測lesson_6的所有作業(yè)
- 作業(yè)
本次作業(yè)為復(fù)現(xiàn)課上最后一個版本的內(nèi)容,課程視頻地址:https://www.acwing.com/video/3479/
注意:本次作業(yè)的2個題目采用整體評測,即如果兩個作業(yè)同時正確,則得100分;否則如果至少有一個作業(yè)錯誤,則得0分。
創(chuàng)建好作業(yè)后,先進(jìn)入文件夾/home/acs/homework/lesson_6/
,當(dāng)前目錄的文件結(jié)構(gòu)如下:
`-- thrift_lesson|-- game| `-- src|-- match_system| `-- src |-- readme.md`-- thrift|-- match.thrift`-- save.thrift
- (0) 進(jìn)入
thrift_lesson/match_system/src/
目錄,用cpp
實現(xiàn)課上的match-server
和save-client
邏輯。
接口文件在thrift_lesson/thrift/
中。
實現(xiàn)后啟動server,監(jiān)聽端口9090。 - (1) 進(jìn)入
thrift_lesson/game/src/
目錄,用python3實現(xiàn)課上的match-client
邏輯。
文件名和輸入格式與課上內(nèi)容相同。
7. 管道、環(huán)境變量與常用命令
管道
概念
管道類似于文件重定向,可以將前一個命令的stdout
重定向到下一個命令的stdin
。
要點
- 管道命令僅處理
stdout
,會忽略stderr
。 - 管道右邊的命令必須能接受
stdin
。 - 多個管道命令可以串聯(lián)。
與文件重定向的區(qū)別
- 文件重定向左邊為命令,右邊為文件。
- 管道左右兩邊均為命令,左邊有
stdout
,右邊有stdin
。
命令 | 命令
舉例
統(tǒng)計當(dāng)前目錄下所有python
文件的總行數(shù),其中find、xargs、wc
等命令可以參考常用命令這一節(jié)內(nèi)容。
find . -name '*.py' | xargs cat | wc -l
環(huán)境變量
概念
Linux系統(tǒng)中會用很多環(huán)境變量來記錄配置信息。
環(huán)境變量類似于全局變量,可以被各個進(jìn)程訪問到。我們可以通過修改環(huán)境變量來方便地修改系統(tǒng)配置。
查看
列出當(dāng)前環(huán)境下的所有環(huán)境變量:
env # 顯示當(dāng)前用戶的變量
set # 顯示當(dāng)前shell的變量,包括當(dāng)前用戶的變量;
export # 顯示當(dāng)前導(dǎo)出成用戶變量的shell變量
輸出某個環(huán)境變量的值:
echo $PATH
修改
環(huán)境變量的定義、修改、刪除操作可以參考3. shell語法——變量這一節(jié)的內(nèi)容。
例如:
export HOME=/home/acs/homework #修改HOME環(huán)境變量地址
為了將對環(huán)境變量的修改應(yīng)用到未來所有環(huán)境下,可以將修改命令放到~/.bashrc
文件中(最后一行)。
修改完~/.bashrc
文件后,記得執(zhí)行source ~/.bashrc
,來將修改應(yīng)用到當(dāng)前的bash
環(huán)境下。
為何將修改命令放到~/.bashrc
,就可以確保修改會影響未來所有的環(huán)境呢?
- 每次啟動
bash
,都會先執(zhí)行~/.bashrc
。 - 每次
ssh
登陸遠(yuǎn)程服務(wù)器,都會啟動一個bash
命令行給我們。 - 每次
tmux
新開一個pane
,都會啟動一個bash
命令行給我們。 - 所以未來所有新開的環(huán)境都會加載我們修改的內(nèi)容。
常見環(huán)境變量
-
HOME
:用戶的家目錄。 -
PATH
:可執(zhí)行文件(命令)的存儲路徑。路徑與路徑之間用:分隔。當(dāng)某個可執(zhí)行文件同時出現(xiàn)在多個路徑中時,會選擇從左到右數(shù)第一個路徑中的執(zhí)行。下列所有存儲路徑的環(huán)境變量,均采用從左到右的優(yōu)先順序。輸入該路徑下的可執(zhí)行文件名,就可以在任意路徑中啟用該可執(zhí)行文件,也就是變成了一個自定義的命令。
-
LD_LIBRARY_PATH
:用于指定動態(tài)鏈接庫(.so文件)的路徑,其內(nèi)容是以冒號分隔的路徑列表。 -
C_INCLUDE_PATH
:C語言的頭文件路徑,內(nèi)容是以冒號分隔的路徑列表。 -
CPLUS_INCLUDE_PATH
:CPP的頭文件路徑,內(nèi)容是以冒號分隔的路徑列表。 -
PYTHONPATH
:Python導(dǎo)入包的路徑,內(nèi)容是以冒號分隔的路徑列表。 -
JAVA_HOME
:jdk的安裝目錄。 -
CLASSPATH
:存放Java導(dǎo)入類的路徑,內(nèi)容是以冒號分隔的路徑列表。
常用命令
Linux命令非常多,本節(jié)講解幾個常用命令。其他命令依賴于大家根據(jù)實際操作環(huán)境,邊用邊查。
系統(tǒng)狀況
-
top
:查看所有進(jìn)程的信息(Linux的任務(wù)管理器)- 打開后,輸入M:按使用內(nèi)存排序
- 打開后,輸入P:按使用CPU排序
- 打開后,輸入q:退出
-
df -h
:查看硬盤使用情況 -
free -h
:查看內(nèi)存使用情況 -
du -sh
:查看當(dāng)前目錄占用的硬盤空間 -
ps aux
:查看所有進(jìn)程可以用來查找某個進(jìn)程:
ps aux | grep match-server(進(jìn)程名)
-
kill -9 pid
:殺死編號為pid的進(jìn)程- 傳遞某個具體的信號:
kill -s SIGTERM pid
- kill -9是立即關(guān)掉進(jìn)程,kill -15是完成善后工作再關(guān)掉,有時延
- 傳遞某個具體的信號:
-
netstat -nt
:查看所有網(wǎng)絡(luò)連接 -
w
:列出當(dāng)前登陸的用戶 -
ping www.baidu.com
:檢查是否連網(wǎng)
文件權(quán)限
文件權(quán)限有十位
第一位d文件夾 l鏈接文件 -代表沒權(quán)限
剩下的每三位一組,表示可讀可寫可執(zhí)行
chmod
:修改文件權(quán)限chmod +x xxx
:給xxx添加可執(zhí)行權(quán)限chmod -x xxx
:去掉xxx的可執(zhí)行權(quán)限chmod 777 xxx
:將xxx的權(quán)限改成777- 上面數(shù)字是0-7內(nèi)也就是三位二進(jìn)制,從前往后表示自己,同組,其他的權(quán)限,0表示有1表示沒有,777=111 111 111 表示所有權(quán)限都開啟
chmod 777 xxx -R
:遞歸修改整個文件夾的權(quán)限
文件檢索
-
find /path/to/directory/ -name '*.py'
:搜索某個文件路徑下的所有*.py
文件 -
grep xxx
:從stdin中
讀入若干行數(shù)據(jù),如果某行中包含xxx
,則輸出該行;否則忽略該行。查找該文件夾下的某內(nèi)容
-
wc
:統(tǒng)計行數(shù)、單詞數(shù)、字節(jié)數(shù)
既可以從stdin中直接讀入內(nèi)容;也可以在命令行參數(shù)中傳入文件名列表;某個文件行數(shù):
wc /文件夾/* 輸出該文件夾下所有文件的行數(shù)、單詞數(shù)、字節(jié)數(shù)
wc -l
:統(tǒng)計行數(shù)wc -w
:統(tǒng)計單詞數(shù)wc -c
:統(tǒng)計字節(jié)數(shù)
-
tree
:展示當(dāng)前目錄的文件結(jié)構(gòu)tree /path/to/directory/
:展示某個目錄的文件結(jié)構(gòu)tree -a
:展示隱藏文件
-
ag xxx
:搜索當(dāng)前目錄下的所有文件,檢索xxx字符串 -
cut
:分割一行內(nèi)容- 從
stdin
中讀入多行數(shù)據(jù) echo $PATH | cut -d ':' -f 3,5
:輸出PATH
用:
分割后第3、5列數(shù)據(jù)echo $PATH | cut -d ':' -f 3-5
:輸出PATH
用:
分割后第3-5列數(shù)據(jù)echo $PATH | cut -c 3,5
:輸出PATH
的第3、5個字符echo $PATH | cut -c 3-5
:輸出PATH
的第3-5個字符
- 從
-
sort
:將每行內(nèi)容按字典序排序- 可以從
stdin
中讀取多行數(shù)據(jù) - 可以從命令行參數(shù)中讀取文件名列表
- 可以從
-
xargs
:將stdin
中的數(shù)據(jù)用空格或回車分割成命令行參數(shù)find . -name '*.py' | xargs cat | wc -l
:統(tǒng)計當(dāng)前目錄下所有python文件的總行數(shù)
查看文件內(nèi)容
-
more
:瀏覽文件內(nèi)容- 回車:下一行
- 空格:下一頁
b
:上一頁q
:退出
-
less
:與more
類似,功能更全- 回車:下一行
y
:上一行Page Down
:下一頁Page Up
:上一頁q
:退出
-
head -3 xxx
:展示xxx
文件的前3行內(nèi)容- 同時支持從
stdin
讀入內(nèi)容
- 同時支持從
-
tail -3 xxx
:展示xxx
末尾3行內(nèi)容-
同時支持從
stdin
讀入內(nèi)容
-
用戶相關(guān)
history
:展示當(dāng)前用戶的歷史操作。內(nèi)容存放在~/.bash_history
中
工具
md5sum
:計算md5
哈希值- 可以從
stdin
讀入內(nèi)容,ctrl+d
退出 - 也可以在命令行參數(shù)中傳入文件名列表;
- 可以從
time command
:統(tǒng)計command
命令的執(zhí)行時間ipython3
:交互式python3
環(huán)境??梢援?dāng)做計算器,或者批量管理文件。! echo "Hello World"
:!
表示執(zhí)行shell
腳本
watch -n 0.1 command
:每0.1秒執(zhí)行一次command
命令tar
:壓縮文件tar -zcvf xxx.tar.gz /path/to/file/*
:壓縮tar -zxvf xxx.tar.gz
:解壓縮
diff xxx yyy
:查找文件xxx
與yyy
的不同點
安裝軟件
sudo command
:以root
身份執(zhí)行command
命令apt-get install xxx
:安裝軟件pip install xxx --user --upgrade
:安裝python包
補充
tar 解壓比較常用的寫法,tar -zxvf xxx.tar.gz -C yyy:可以將 xxx.tar.gz 解壓到指定目錄 yyy 中,x - extract。
tail -n 5 文件
:查看文件尾部5行內(nèi)容 (常用于日志)
tail -f 文件
:實時追蹤該文檔的所有更新 (常用于 flum 采集數(shù)據(jù))
updatadb
:更新locate
命令所使用的數(shù)據(jù)庫
locate xxx
:按索引查詢比find
快,支持模糊查詢
ps -aux
:查看進(jìn)程的CPU占用率和內(nèi)存占用率
ps -ef
:查看進(jìn)程的父進(jìn)程ID
netstat -nlp | grep 22
:查看22端口號是否被占用
rpm -qa | grep rpm
:查看自己安裝的壓縮包
sudo netstat -nltp
:檢測TCP/IP網(wǎng)絡(luò)連接的監(jiān)聽端口(網(wǎng)絡(luò)端口監(jiān)聽)
xargs
將stdin
的內(nèi)容用空行隔開,作為cat
的命令行參數(shù),傳給cat
cat a.txt b.txt
stdin
變成文件參數(shù)
find . -name “*.py | cat
:獲取為.py結(jié)尾的文件名
find . -name “*.py | xargs cat
:獲取.py文件的內(nèi)容
linux關(guān)于bashrc與profile的區(qū)別(轉(zhuǎn))
Linux命令查找
8. 租云服務(wù)器及配docker環(huán)境
概述
租到的服務(wù)器是毛坯,未來主要工作在docker上,方便遷移
云平臺的作用:
- 存放我們的docker容器,讓計算跑在云端。
- 獲得公網(wǎng)IP地址,讓每個人可以訪問到我們的服務(wù)。
任選一個云平臺即可,推薦配置:
- 1核 2GB(后期可以動態(tài)擴(kuò)容,前期配置低一些沒關(guān)系)
- 網(wǎng)絡(luò)帶寬采用按量付費,最大帶寬拉滿即可(費用取決于用量,與最大帶寬無關(guān))
- 系統(tǒng)版本:ubuntu 20.04 LTS(推薦用統(tǒng)一版本,避免后期出現(xiàn)配置不兼容的問題)
docker安裝教程地址:https://docs.docker.com/engine/install/ubuntu/
租云服務(wù)器及安裝docker
阿里云
阿里云地址:https://www.aliyun.com/
創(chuàng)建工作用戶acs
并賦予sudo
權(quán)限
登錄到新服務(wù)器。打開AC Terminal,然后:
ssh root@xxx.xxx.xxx.xxx # xxx.xxx.xxx.xxx替換成新服務(wù)器的公網(wǎng)IP 密碼
免費七個月云服務(wù)器
創(chuàng)建user1
用戶:(非根用戶,分配sudo權(quán)限)
adduser user1 # 創(chuàng)建用戶user1 密碼
usermod -aG sudo user1 # 給用戶user1分配sudo權(quán)限
配置免密登錄方式
退回AC Terminal,然后配置user1
用戶的別名和免密登錄,可以參考4. ssh——ssh登錄。
配置新服務(wù)器的工作環(huán)境
將AC Terminal的配置傳到新服務(wù)器上:
scp .bashrc .vimrc .tmux.conf server_name: # server_name需要換成自己配置的別名
安裝tmux
和docker
登錄自己的服務(wù)器,然后安裝tmux
:
sudo apt-get update
sudo apt-get install tmux
打開tmux
。(養(yǎng)成好習(xí)慣,所有工作都在tmux里進(jìn)行,防止意外關(guān)閉終端后,工作進(jìn)度丟失)
然后在tmux
中根據(jù)docker
安裝教程安裝docker
即可。
騰訊云
騰訊云地址:https://cloud.tencent.com/
創(chuàng)建工作用戶acs
并賦予sudo
權(quán)限
登錄到新服務(wù)器。打開AC Terminal,然后:
ssh ubuntu@xxx.xxx.xxx.xxx # 注意騰訊云登錄的用戶不是root,而是ubuntu
創(chuàng)建acs
用戶:
adduser acs # 創(chuàng)建用戶acs
usermod -aG sudo acs # 給用戶acs分配sudo權(quán)限
配置免密登錄方式
退回AC Terminal,然后配置acs用戶的別名和免密登錄,可以參考4. ssh——ssh登錄。
配置新服務(wù)器的工作環(huán)境
將AC Terminal的配置傳到新服務(wù)器上:
scp .bashrc .vimrc .tmux.conf server_name: # server_name需要換成自己配置的別名
安裝tmux
和docker
登錄自己的服務(wù)器,然后安裝tmux
:
sudo apt-get update
sudo apt-get install tmux
打開tmux
。(養(yǎng)成好習(xí)慣,所有工作都在tmux里進(jìn)行,防止意外關(guān)閉終端后,工作進(jìn)度丟失)
然后在tmux
中根據(jù)docker
安裝教程安裝docker
即可。
華為云
華為云地址:https://www.huaweicloud.com/
創(chuàng)建工作用戶user1
并賦予sudo
權(quán)限
登錄到新服務(wù)器。打開AC Terminal,然后:
ssh root@xxx.xxx.xxx.xxx # xxx.xxx.xxx.xxx替換成新服務(wù)器的公網(wǎng)IP
創(chuàng)建acs用戶:
adduser acs # 創(chuàng)建用戶acs
usermod -aG sudo acs # 給用戶acs分配sudo權(quán)限
配置免密登錄方式
退回AC Terminal,然后配置acs用戶的別名和免密登錄,可以參考4. ssh——ssh登錄。
配置新服務(wù)器的工作環(huán)境
將AC Terminal的配置傳到新服務(wù)器上:
scp .bashrc .vimrc .tmux.conf server_name: # server_name需要換成自己配置的別名
安裝tmux
和docker
登錄自己的服務(wù)器,然后安裝tmux:
sudo apt-get update
sudo apt-get install tmux
打開tmux
。(養(yǎng)成好習(xí)慣,所有工作都在tmux里進(jìn)行,防止意外關(guān)閉終端后,工作進(jìn)度丟失)
然后在tmux
中根據(jù)docker
安裝教程安裝docker
即可。
docker教程
將當(dāng)前用戶添加到docker
用戶組
為了避免每次使用docker
命令都需要加上sudo
權(quán)限,可以將當(dāng)前用戶加入安裝中自動創(chuàng)建的docker
用戶組(可以參考官方文檔):添加完后及的執(zhí)行newgrp docker
更新用戶組
sudo usermod -aG docker $USER
執(zhí)行完此操作后,需要退出服務(wù)器,再重新登錄回來,才可以省去sudo
權(quán)限。
鏡像和容器就像是印章和圖案
鏡像(images)
docker pull ubuntu:20.04
:拉取一個鏡像docker images
:列出本地所有鏡像docker image rm ubuntu:20.04
或docker rmi ubuntu:20.04
:刪除鏡像ubuntu:20.04
docker [container] commit CONTAINER IMAGE_NAME:TAG
:創(chuàng)建某個container
的鏡像docker save -o ubuntu_20_04.tar ubuntu:20.04
:將鏡像ubuntu:20.04
導(dǎo)出到本地文件ubuntu_20_04.tar
中,chmod +r ubuntu_20_04.tar
這個文件只有自己是可讀的所以設(shè)置一下權(quán)限。docker load -i ubuntu_20_04.tar
:將鏡像ubuntu:20.04
從本地文件ubuntu_20_04.tar
中加載出來
在不同云服務(wù)器之間傳鏡像:先打包成tar文件,然后利用scp命令下載到本地,再把本地的tar鏡像傳到需要的云服務(wù)器上。
容器(container)
docker [container] create -it ubuntu:20.04
:利用鏡像ubuntu:20.04
創(chuàng)建一個容器。docker ps -a
:查看本地的所有容器,docker ps
查看所有啟動的容器docker [container] start CONTAINER
:啟動容器,CONTAINER
可以是id或者namedocker [container] stop CONTAINER
:停止容器docker [container] restart CONTAINER
:重啟容器docker [contaienr] run -itd ubuntu:20.04
:創(chuàng)建并啟動一個容器docker [container] attach CONTAINER
:進(jìn)入容器- 先按
Ctrl-p
,再按Ctrl-q
可以掛起容器 Ctrl-d
退出容器 - 不建議
- 先按
docker [container] exec CONTAINER COMMAND
:在容器中執(zhí)行命令docker [container] rm CONTAINER
:刪除容器,刪除停止的容器docker container prune
:刪除所有已停止的容器docker export -o xxx.tar CONTAINER
:將容器CONTAINER
導(dǎo)出到本地文件xxx.tar
中docker import xxx.tar image_name:tag
:將本地文件xxx.tar
導(dǎo)入成鏡像,并將鏡像命名為image_name:tag
docker export/import與docker save/load
的區(qū)別:export/import
會丟棄歷史記錄和元數(shù)據(jù)信息,僅保存容器當(dāng)時的快照狀態(tài)save/load
會保存完整記錄,體積更大
docker top CONTAINER
:查看某個容器內(nèi)的所有進(jìn)程docker stats
:查看所有容器的統(tǒng)計信息,包括CPU、內(nèi)存、存儲、網(wǎng)絡(luò)等信息docker cp xxx CONTAINER:xxx
或docker cp CONTAINER:xxx xxx
:在本地和容器間復(fù)制文件,docker cp文件夾不用加-rdocker rename CONTAINER1 CONTAINER2
:重命名容器docker update CONTAINER --memory 500MB
:修改容器限制
實戰(zhàn)–實現(xiàn)在云服務(wù)器上搭建一個和AC Terminal一樣環(huán)境的云服務(wù)器
進(jìn)入AC Terminal,然后:
scp /var/lib/acwing/docker/images/docker_lesson_1_0.tar server_name: # 將鏡像上傳到自己租的云端服務(wù)器
ssh server_name # 登錄自己的云端服務(wù)器docker load -i docker_lesson_1_0.tar # 將鏡像加載到本地
docker run -p 20000:22 --name my_docker_server -itd docker_lesson:1.0 # 創(chuàng)建并運行docker_lesson:1.0鏡像 -p修改端口映射:將容器內(nèi)22端口映射到本地20000端口,名稱為my_docker_serverdocker attach my_docker_server # 進(jìn)入創(chuàng)建的docker容器
passwd # 設(shè)置root密碼
云平臺上修改root密碼:在實例中重置實例密碼,自己創(chuàng)建的服務(wù)中設(shè)置root密碼輸入:passwd
去云平臺控制臺中修改安全組配置,放行端口20000
。
返回AC Terminal,即可通過ssh
登錄自己的docker
容器:
ssh root@xxx.xxx.xxx.xxx -p 20000 # 將xxx.xxx.xxx.xxx替換成自己租的服務(wù)器的IP地址
然后,可以仿照上節(jié)課內(nèi)容,創(chuàng)建工作賬戶user1
。
最后,可以參考4. ssh——ssh登錄配置docker
容器的別名和免密登錄。裝tmux前先sudo apt-get update 再sudo apt-get install tmux
小Tips
如果apt-get
下載軟件速度較慢,可以參考清華大學(xué)開源軟件鏡像站中的內(nèi)容,修改軟件源。
將當(dāng)前用戶加入安裝中自動創(chuàng)建的docker用戶組后,仍然提示Got permission denied
, 可以運行 newgrp docker #更新用戶組
acs is not in the sudoers file. This incident will be reported.
輸入acs的密碼后出現(xiàn)上述內(nèi)容,解決方案:重新登錄root用戶,創(chuàng)建另一個用戶,重新設(shè)置免密登錄以及以后的內(nèi)容