一、軟件包管理器
1、Linux下安裝軟件的常見方式:
? ? ? ? 1)源代碼安裝——不推薦。
? ? ? ? 2)rpm包安裝——不推薦。
? ? ? ? 3)包管理器安裝——推薦
2、安裝軟件命令
# Centos$ sudo yum install -y lrzsz# Ubuntu$ sudo apt install -y lrzsz
3、卸載軟件命令
# Centossudo yum remove [-y] lrzsz# Ubuntusudo apt remove [-y] lrzsz
? ? ? ? 任何評估一款操作系統的好壞?操作系統被設計出來之后,最重要的事情是什么?
? ? ? ? 答:操作系統形成使用圈子就會被更多的人使用,為了讓更多的人使用就必須讓圈子更完善;有人愿意在特定的os上編寫特定的軟件適應不同的群體,并且在各種圈子完善社區、文檔、論壇、資料。
二、編輯器 Vim
? ? ? ? ?IDE在Linux下的開發工具是獨立的!寫代碼——編輯器vim,編譯代碼——gcc/g++,調試——gdb/cgbd,構建工具——makefile/make/cmake。
? ? ? ? 進入vim的指令:vim + 文件。進入vim之后要寫內容按鍵盤 i 鍵。
? ? ? ? vimd的多模式:命令模式、插入模式、底行模式。
? ? ? ? 底行模式:set nu,是給內容加上行號,如:
?注意:如果想去掉行號在底行模式輸入:nonu。
命令模式下:
????????shift+g:光標進入文本末端。
? ? ? ? gg:光標進入文本的開始。
? ? ? ? n+shift+g:光標進入來到文本n行。
? ? ? ? shift+4:光標進入到當前行的末尾。
? ? ? ? shift+6:光標來到當前行的開始。
? ? ? ? h:光標往左移動。
? ? ? ? j:光標往下移動。
? ? ? ? k:光標往上移動。
? ? ? ? l:光標往右移動。
? ? ? ? w:按照單詞向右移動。注意:可以加上數字。
? ? ? ? b:按照單詞向左移動。注意:可以加上數字。
? ? ? ? yy:復制當前行的內容。n+yy復制前n行內容。
? ? ? ? p:粘貼。n+p可以粘貼n次。
? ? ? ? dd:刪除當前行。n+dd刪除前n行內容。
? ? ? ? u:撤銷操作。
? ? ? ? ctrl+r:對u的撤銷。
注意:任意模式下都可以進行撤銷操作,退出vim就不能撤銷了。
? ? ? ? shift+~:對光標的字母進行大小寫切換。
? ? ? ? r:替換光標所在位置的一個字符,n+r替換n個字符。
? ? ? ? shift+r:進入替換模式,忽視原來文本內容,可重新編寫。注意:進入替換模式之后要退出來就要按Esc鍵。
? ? ? ? x:刪除光標所在字符,向右刪除。
? ? ? ? shift+x:向左刪除光標所在字符。
? ? ? ? 批量化注釋:①ctrl+v,②hjkl選擇區域,③shift+i,④//,⑤Esc。
? ? ? ? 批量化去注釋:①ctrl+v,②hjkl選擇區域,③d,④Esc。
底行模式下:
? ? ? ? w!:保存。
? ? ? ? q!:退出。
? ? ? ? wq!:強制保存并退出。
注意:如果vim打開文件,突然終端退出,vim會形成臨時文件,默認在當前路徑的下一個.swp臨時ls -al。
? ? ? ? :/key+n:匹配搜索。
? ? ? ? :!cmp:不退出vim,直接對代碼進行編譯運行。
? ? ? ? :%s/dst/src/g:把文本內容所有的dst替換成src。
? ? ? ? :vs:分屏操作。ctrl+www,選中哪一個分屏。
注意:當vim退出光標在第n行,再次打開光標還在原來位置。那么我們Linux下可輸入vim +文件名+n,直接進入到第n行。在命令模式下退出vim操作:shift+zz。
配置炫酷的vim:
????????要配置炫酷的vim,原生的配置可能功能不全,可以選擇安裝插件來完善配置,保證用戶是你要配置的用戶,接下來:
? ? ? ? ①安裝TagList插件,下載taglist_xx.zip,解壓完成,將解壓出來的doc的內容放到~/.vim/doc,將解壓出來的plugin下的內容拷貝到~/.vim/plugin。
? ? ? ? ②在~/.vimrc中添加:let Tlist_Show_One_File=1?letTlist_Exit_OnlyWindow=1?let Tlist_Use_Right_Window=1
? ? ? ? ③安裝文件瀏覽器和窗口管理器插件:WinManager
? ? ? ? ④下載winmanager.zip,2.X版本以上的
? ? ? ? ⑤解壓winmanager.zip,將解壓出來的doc的內容放到~/.vim/doc,將解壓出來的plugin下的內容拷貝到~/.xim/plugin
? ? ? ? ⑥在~/.vimrc中添加 let g:winManagerwindowLayout=‘FileExplorer|TagListnmap wm :WMToggle<cr>
? ? ? ? ⑦然后重啟vim,打開~/XXX.c或~/XXX.cpp,在normal狀態下輸入"wm",你將看到上圖的效果。更具體移步:手把手教你把Vim改裝成一個IDE編程環境(圖文)_vim 打造成 ide-CSDN博客,其他手冊,請執行vimtutor 命令。
三、讓普通用戶暫時提權的方法
? ? ? ? 1、進入到root界面
? ? ? ? 2、指令:ls /etc/sudoers,查看sudoer是否存在。
? ? ? ? 3、指令:vim /etc/sudoers,進入sudoers
? ? ? ? 4、yy接著p一下
四、g++/gcc
1)區別
? ? ? ? gcc:C編譯器。只能用來進行編譯C語言。
? ? ? ? g++:C++/C語言編譯器。
2)四步生成可執行文件
? ? ? ? 預處理(頭文件展開,去注釋,宏替換,條件編譯):指令:gcc 文件名 -o 編譯后行的文件名(可自己寫)。由于gcc是一步到位(直接形成可執行文件),所以可以這么做:gcc -E 文件名 -o 預處理之后的文件名.i;
? ? ? ? 編譯:把C語言變成匯編語言,指令:gcc -S 文件名.i -o 文件名.s
? ? ? ? 匯編:把匯編語言翻譯成二進制文件,指令:gcc -c 文件名.s -o 文件名.o
? ? ? ? 鏈接:把二進制文件形成可執行文件,指令:gcc 文件名.o -o 文件名.exe
補充知識:為什么要把C語言翻譯成匯編?
答:翻譯語言的本質是轉成CPU能夠識別的指令集;匯編語言是用字母來對二進制指令進行包裝;
先有匯編語言還是先有用匯編語言寫的匯編編譯器?
答:先拿二進制寫出一個匯編編譯器,再寫出匯編語言,然后在拿匯編語言完善匯編編譯器,最后再用匯編語言編寫軟件(如C語言編譯器),最終再拿C語言編譯器來寫匯編編譯器(編譯器自舉),所以先有語言。
.o二進制文件能不能直接運行?
答:不能,原因:如果運行.o文件他會報出錯誤:可重定位目標二進制文件,因為我們用到的庫方法,只有說明,沒有定義。
注意:在Linux中靜態庫是以.a為后綴,動態庫是以.so為后綴;window的靜態庫是以.lib為后綴,動態庫是以.dll為后綴。? ? ? ??
動態鏈接優點:節省內存空間;缺點:慢,編譯完成依舊依賴動態庫;靜態庫的優點:不需要庫跳轉,一旦編譯完成不依賴庫;缺點:可執行程序體積較大(把庫實現的方法拷貝到程序里面),消耗內存資源。
注意:gcc默認編譯是采用動態鏈接的方式完成,如果想要強制進行靜態鏈接可以輸入指令:gcc 文件名 -o 文件名 -static。
3)靜態庫和動態庫
????????靜態庫是指編譯鏈接時,把庫文件的代碼全部加入到可執行文件中,因此生成的文件比較大,但在運行時也就不再需要庫文件了。其后綴名一般為“.a”
????????動態庫與之相反,在編譯鏈接時并沒有把庫文件的代碼加入到可執行文件中,而是在程序執行時由運行時鏈接文件加載庫,這樣可以節省系統的開銷。動態庫一般后綴名為“.so”,如前面所述的libc.so.6就是動態庫。
????????gcc在編譯時默認使用動態庫。完成了鏈接之后,gcc就可以生成可執行文件,如下所示。gcc hello.o-o hellogcc默認生成的二進制程序,是動態鏈接的,這點可以通過file 命令驗證。
五、自動化項目的構建(生成可執行文件)——make/Makefile
1)背景
????????會不會寫makefile,從一個側面說明了一個人是否具備完成大型工程的能力。
????????一個工程中的源文件不計數,其按類型、功能、模塊分別放在若干個目錄中,makefile定義了一系列的規則來指定,哪些文件需要先編譯,哪些文件需要后編譯,哪些文件需要重新編譯,甚至于進行更復雜的功能操作。
????????makefile帶來的好處就是—“自動化編譯”,一旦寫好,只需要一個make命令,整個工程完全自動編譯,極大的提高了軟件開發的效率。
????????make是一個命令工具,是一個解釋makefile中指令的命令工具,一般來說,大多數的IDE都有這個命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。可見,makefile都成為了一種在工程方面的編譯方法。
????????make是一條命令,makefile是一個文件,兩個搭配使用,完成項目自動化構建。
2)make/Makefile的執行原理
????????make會在當前目錄下找名字叫“Makefile”或“makefile”的文件。
????????如果找到,它會找文件中的第一個目標文件(target),在上面的例子中,他會找到myproc 這個文件,并把這個文件作為最終的目標文件。
????????如果myproc文件不存在,或是myproc所依賴的后面的myproc.o文件的文件修改時間要比 myproc 這個文件新(可以用touch 測試),那么,他就會執行后面所定義的命令來生成myproc這個文件。
????????如果myproc 所依賴的myproc.o文件不存在,那么make 會在當前文件中找目標為myproc.o文件的依賴性,如果找到則再根據那一個規則生成myproc.o文件。(這有點像一個堆棧的過程)
????????當然,你的C文件和H文件是存在的啦,于是 make 會生成 myproc.o 文件,然后再用myproc.o文件聲明make的終極任務,也就是執行文件 hello了。
????????這就是整個make的依賴性,make會一層又一層地去找文件的依賴關系,直到最終編譯出第一個目標文件。
????????在找尋的過程中,如果出現錯誤,比如最后被依賴的文件找不到,那么make就會直接退出,并報錯,而對于所定義的命令的錯誤,或是編譯不成功,make根本不理。
注意:gcc無法二次編譯老代碼的原因:源代碼的時間比可執行文件的要舊,如果修改源代碼那么的他的時間就會比可執行文件新,這時候就可以進行二次編譯。修改一個文件的時間可以使用touch 一個已經存在的源文件,這時候就可以進行二次編譯。
結論:判斷文件新舊是根據文件的Mod時間來判定;.PHONY為什么總是被執行的?原因:就是讓gcc或者對應的命令忽略Mod時間對比新舊。
注意:Modify是文件內容被修改的時間,change 是文件屬性被修改的時間;只要修改文件的內容Mod和change的時間也會被修改,原因:修改文件內容會影響文件大小,包括Mod時間也是屬性。Access是文件最近被訪問的時間,查看文件會跟新時間,相當于修改文件屬性,這時Linux就會刷新到磁盤,因為查看文件次數較多所以會增加磁盤的訪問次數,外設效率低下,導致os整體效率降低,故而訪問文件內容達到特定次數之后,才會更新一次時間。
?知識點補充:
使用 wildcard 函數,獲取當前所有.c文件名OBJ=$(SRC:.C=.0)//將SRC的所有同名.c替換成為.o形成目標文件列表$@:代表目標文件名。$^:代表依賴文件列表%.c展開當前目錄下所有的.c。%.o:同時展開同%<:對展開的依賴.c文件,一個一個的交給gcc。@:不回顯命令S(RM)·替換,用變量內容替換它
注意:?
?SRC=$(wildcard *.cc) #wildcard是make的一個函數,用來匹配文件名
#*.cc就是wildcard函數的參數
#用法$(wildcard pattern) ?參數 pattern 是一個文件名通配符模式
#文件名通配符模式是一種使用特殊字符來匹配一組文件名的語法
#特殊字符*表示匹配任意數量的字符(包括零個)
OBJ=$(SRC:.cc=.o)
這是 Makefile 中的 變量替換(模式替換) 語法,格式如下:
$(變量名:模式=替換)
它的意思是:把“變量名”中所有 符合“模式” 的部分,替換為“替換”。
?六、進度條原理和設計
main.c
#include "process.h"
#include <unistd.h>
#include <time.h>
#include <stdlib.h>double gtotal = 1024.0;
double speed = 1.0;// 函數指針類型
typedef void (*callback_t)(double, double);// 1.0 4.3
double SpeedFloat(double start, double range) // [1.0 3.0] -> [1.0, 4.0]
{int int_range = (int)range;return start + rand()%int_range + (range - int_range);
}// cb: 回調函數
void DownLoad(int total, callback_t cb)
{srand(time(NULL));double curr = 0.0;while(1){if(curr > total){curr = total; // 模擬下載完成cb(total, curr); // 更新進度, 按照下載進度,進行更新進度條break;}cb(total, curr); // 更新進度, 按照下載進度,進行更新進度條curr += SpeedFloat(speed, 20.3); // 模擬下載行為usleep(30000);}
}int main()
{printf("download: 20.0MB\n");DownLoad(20.0, FlushProcess);printf("download: 2000.0MB\n");DownLoad(2000.0, FlushProcess);printf("download: 100.0MB\n");DownLoad(100.0, FlushProcess);printf("download: 20000.0MB\n");DownLoad(20000.0, FlushProcess);return 0;
}
process.c
#include "process.h"
#include <string.h>
#include <unistd.h>#define SIZE 101
#define STYLE '='void FlushProcess(double total, double curr) // 更新進度, 按照下載進度,進行更新進度條
{if(curr > total)curr = total;double rate = curr / total * 100; // 1024.0 , 512.0 -> 0.5 -> 50.0int cnt = (int)rate; // 50.8 , 49.9 -> 50, 49char processbuff[SIZE];memset(processbuff, '\0', sizeof(processbuff));int i = 0;for(; i < cnt; i++)processbuff[i] = STYLE;static const char *lable = "|/-\\";static int index = 0;// 刷新printf("[%-100s][%.1lf%%][%c]\r", processbuff, rate, lable[index++]);index %= strlen(lable);fflush(stdout);if(curr >= total){printf("\n");}
}// version1: 能夠使用嗎??
// 說明原理
void Process()
{const char *lable = "|/-\\";int len = strlen(lable);char processbuff[SIZE];memset(processbuff, '\0', sizeof(processbuff));int cnt = 0;while(cnt <= 100){printf("[%-100s] [%d%%][%c]\r", processbuff, cnt, lable[cnt%len]);fflush(stdout);processbuff[cnt++] = STYLE;usleep(30000);}printf("\n");
}
process.h
#pragma once#include <stdio.h>// version1
void Process();
void FlushProcess(double total, double curr); // 更新進度, 按照下載進度,進行更新進度條
完!!