参考

Linux 教程 | 爱编程的大丙

文件管理命令

相对路径和绝对路径

相对路径

  • ./:代表当前目前所在的目录,也可以使用.表示
  • ../:代表当前目前所在的上一级目录,也可以使用..表示
1
pwd # Print Working Directory

绝对路径

  • Linux: 起始结点为根目录,比如/root/home
  • Windows: 起始结点为某个盘符,比如C:\\Users

命令提示行

1
zwx@7049GP-TRT:~/learning$ whoami # 查看当前用户

其中的zwx为当前用户名;7049GP-TRT为主机名

  • ~为当前用户的home目录
1
2
zwx@7049GP-TRT:~$ pwd
/home/zwx
  • 使用cd命令不带参数,默认切换到~
1
2
3
zwx@7049GP-TRT:~/deeplearning$ cd
zwx@7049GP-TRT:~$ pwd
/home/zwx
  • $对应普通用户,#对应管理员用户

  • 可执行程序对应的目录

1
2
3
4
5
6
zwx@7049GP-TRT:~$ which pwd
/usr/bin/pwd
zwx@7049GP-TRT:~$ which whoami
/usr/bin/whoami
zwx@7049GP-TRT:~$ echo $PATH
/opt/anaconda3/condabin:/home/zwx/.vscode-server/cli/servers/Stable-1e790d77f81672c49be070e04474901747115651/server/bin/remote-cli:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin

命令行快捷键

Ctrl+A: 移动至行首

文件管理命令

1
cd # change directory
1
2
3
4
5
6
7
8
ls       # list
ls -a # list all
ls -l # list
ls -F # list
ls -H # list
ls -alFH # list
ll = ls -l
ll = ls -laF

文件类型

  • -: 普通的文件, 在Linux终端中没有执行权限的为白色, 压缩包为红色, 可执行程序为绿色字体
  • d: 目录(directory), 在Linux终端中为蓝色字体, 如果目录的所有权限都是开放的, 有绿色的背景色
  • l: 软链接文件(link), 相当于windows中的快捷方式, 在Linux终端中为淡蓝色(青色)字体
  • c: 字符设备(char), 在Linux终端中为黄色字体
  • b: 块设备(block), 在Linux终端中为黄色字体
  • p: 管道文件(pipe), 在Linux终端中为棕黄色字体
  • s: 本地套接字文件(socket), 在Linux终端中为粉色字体

用户类型和权限

在Linux中有三大类用户: 文件所有者, 文件所属组用户, 其他人, 我们可以对同一个文件给这三种人设置不同的操作权限, 用于限制用户对文件的访问。

  • 读权限:使用r表示, 即: read
  • 写权限:使用w表示, 即: write
  • 执行权限:使用x表示, 即: excute
  • 没有任何权限:使用-表示
1
2
3
   -         rwx          rw-          r--
| | | |
文件类型 文件所有者权限 文件所属组权限 其他人权限

目录的创建和删除

1
2
3
mkdir dir1/dir2 -p
rmdir dir1 # 删除空目录
rm dir1 -r # 递归删除目录

tree 命令

文件拷贝和目录拷贝

1
cp sourcefile targetfile
1
2
cp sourcedir targetdir -r # 递归拷贝
cp sourcedir/* targetdir -r # 拷贝sourcedir/目录下的所有文件到targetdir中

文件移动和重命名

1
2
mv sourcefile targetdir/ # 移动文件
mv sourcedir/ targetdir/ # 移动目录
1
2
mv sourcefile newfilename # 重命名文件
mv sourcedir/ newdirname # 重命名目录

查看文件类容

1
cat filename # 显示文件的类容(仅限于小文件,否认不能全部显示)
  • head 和 tail
1
2
head -10 filename
tail -10 filename

创建软链接和硬链接

1
ln -s sourcefile targetdir/linkname

sourcefile建议使用绝对路径,这样创建的软链接可以移动位置

1
ln sourcefile linkname # 创建硬链接

改变文件权限

1
2
3
chmod who [+|-|=] mod filename
who: u|g|o|a
mod: r|w|x|- 4|2|1|0
1
chmod u+rwx [file_name]

修改文件所有者和所属组

1
2
3
4
# 修改文件所有者
sudo chown 新的所有者 文件名
# 修改文件所属组
sudo chown 新的所有者:新的组名 文件名
1
sudo chgrp 新的组 文件名

tree命令

1
2
ubuntu: sudo apt install tree
centos: sudo apt install tree
1
2
tree -L 2 # 只显示两层
tree -L 2 dirname/ # 指定目录

创建空文件

1
touch filename # 如果文件已存在会更新文件的时间
1
which command # 查看命令的位置

重定向操作

1
2
3
4
echo helloworld
echo helloworld > temp # 覆盖
echo helloworld >> temp # 追加
cat temp

用户管理命令

切换用户

1
2
su username   # 不切换工作目录
su - username # 切换当前工作目录
1
su - root # 切换到root用户

创建和删除用户

1
sudo adduser username
1
2
su - username # 验证用户是否创建成功
vim /etc/passwd # 是否能找到用户,用于验证用户是否创建成功
1
sudo userdel username -r # 删除用户

添加和删除用户组

1
2
sudo groupadd groupname # 添加组
sudo groupdel groupname # 删除组
1
vim etc/group # 查看组的相关信息

修改用户密码

1
2
passwd # 修改当前用户密码
sudo passwd username # 修改其它用户密码

压缩命令

Linux的常用压缩包格式

1
tar.gz | .tgz | .tar.bz2 | .zip | .rar | .tar.xz

打包+压缩

查找命令

Vim的使用

GCC/G++

  • 预处理: 在这个阶段主要做了三件事: 展开头文件 、宏替换 、去掉注释行

    这个阶段需要GCC调用预处理器来完成, 最终得到的还是源文件, 文本格式

  • 编译: 这个阶段需要GCC调用编译器对文件进行编译, 最终得到一个汇编文件
  • 汇编: 这个阶段需要GCC调用汇编器对文件进行汇编, 最终得到一个二进制文件
  • 链接: 这个阶段需要GCC调用链接器对程序需要调用的库进行链接, 最终得到一个可执行的二进制文件
1
2
3
4
5
6
g++ -E ./helloworld.cpp -o ./helloworld.i # 预处理
g++ -S ./helloworld.i -o ./helloworld.s # 编译
g++ -c ./helloworld.s -o ./helloworld.o # 汇编
g++ ./helloworld.o -o ./helloworld # 链接
./helloworld # 执行
hello, world!
1
g++ ./helloworld.cpp -o ./helloworld # (预处理+编译+汇编)链接->可执行文件

使用gcc编译cpp文件需要加参数-l stdc++,表示在链接时指定使用C++的动态链接库

1
gcc ./helloworld.cpp -o ./helloworld -l stdc++

静态库和动态库

静态库

  • 在Linux中静态库以lib作为前缀, 以.a作为后缀, 中间是库的名字自己指定即可, 即: libxxx.a
  • 在Windows中静态库一般以lib作为前缀, 以lib作为后缀, 中间是库的名字需要自己指定, 即: libxxx.lib

静态库的制作

1
2
3
4
5
6
7
# folder structure
libcalculate
├── add.cpp
├── calculate.h
├── div.cpp
├── mul.cpp
└── sub.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// calculate.h
double add(double, double);
double sub(double, double);
double mul(double, double);
double div(double, double);
// add.cpp
#include "calculate.h"
double add(double x, double y){return x + y;}
// sub.cpp
#include "calculate.h"
double sub(double x, double y){return x - y;}
// mul.cpp
#include "calculate.h"
double mul(double x, double y){return x * y;}
// div.cpp
#include "calculate.h"
double div(double x, double y){return x / y;}
1
2
3
4
# 编译不链接,生成.o中间文件,其中-I参数指明头文件的路径
g++ -c ./add.cpp ./sub.cpp ./mul.cpp ./div.cpp -I ./
# 进行打包,生成静态库文件libcalculate.a,其中rcs是ar命令的三个参数
ar rcs libcalculate.a *.o

静态库的使用

1
2
3
4
5
# folder structure
test
├── calculate.h # 静态库头文件
├── libcalculate.a # 静态库文件
└── main.cpp
1
2
# 进行编译,-L参数指明静态库文件的路径,-l参数指明静态库的名称(去掉前缀lib和后缀.a)
g++ main.cpp -o test -L ./ -l calculate

动态库

  • 在Linux中动态库以lib作为前缀, 以.so作为后缀, 中间是库的名字自己指定即可, 即: libxxx.so
  • 在Windows中动态库一般以lib作为前缀, 以dll作为后缀, 中间是库的名字需要自己指定, 即: libxxx.dll

动态库的制作

  • 将源文件进行汇编操作, 需要使用参数 -c, 还需要添加额外参数 -fpic-fPIC

    1
    g++ -c *.cpp -fpic -I ./path/to/head/
  • 将得到的*.o文件打包成动态库, 还是使用g++, 使用参数 -shared 指定生成动态库(位置没有要求)

    1
    g++ -shared *.o -o libxxx.so
  • 发布动态库和头文件
    提供头文件和动态库文件: xxx.hlibxxx.so

  • 示例

    1
    2
    3
    4
    5
    6
    7
    # folder structure
    libcalculate
    ├── add.cpp
    ├── calculate.h
    ├── div.cpp
    ├── mul.cpp
    └── sub.cpp
    1
    2
    g++ -c ./*.cpp -fpic -I ./
    g++ -shared ./*.o -o libcalculate.so

动态库的使用

1
2
3
4
5
# folder structure
test
├── calculate.h # 动态库头文件
├── libcalculate.so # 动态库文件
└── main.cpp
1
2
3
4
5
6
# 进行编译和链接
g++ ./main.cpp -o test -L ./ -l calculate
# 执行
./test
# 报错
./test: error while loading shared libraries: libcalculate.so: cannot open shared object file: No such file or directory

动态链接器

动态链接器的搜索顺序:

  • 可执行文件内部的 DT_RPATH
  • 系统的环境变量 LD_LIBRARY_PATH
  • 系统动态库的缓存文件 /etc/ld.so.cache
  • 存储动态库/静态库的系统目录 /lib/, /usr/lib

应用程序无法链接到动态链接库

1
2
3
echo $LD_LIBRARY_PATH
LD_LIBRARY_PATH=~/cudalearning/libcalculate:$LD_LIBRARY_PATH # 仅对当前终端生效
echo $LD_LIBRARY_PATH

修改用户目录下的~/.bashrc文件(仅对当前用户生效)

1
2
3
4
5
6
7
8
9
10
11
12
# 使用 vim 打开配置文件
$ vim ~/.bashrc
# 在结尾添加下面的代码,保存退出:wq,其中:后跟着的是动态库的绝对路径
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:~/cudalearning/libcalculate
# 查看~/.bashrc文件的最后一行
$ tail -1 ~/.bashrc
# 重新加载配置文件
$ source ~/.bashrc
# 使用ldd命令可以查看动态链接库是否能被检测到
$ ldd test
libcalculate.so (0x00007f2d071e3000) # <--
...

Makefile

  • 每条规则的语法格式
1
2
3
4
target1, target2, ... : depend1, depend2, ...
command1
command2
......

注意command前的缩进必须是真的Tab ,不可以是空格

  • 示例
1
2
3
add, sub : add.cpp, sub.cpp
g++ add.cpp -o add
g++ sub.cpp -o sub
  • 规则之间可以嵌套
1
2
3
4
5
6
test : main.cpp libcalculate.a
g++ main.cpp -o test -L ./ -l calculate
libcalculate.a : add.o, sub.o, mul.o div.o
ar rcs libcalculate.a add.o sub.o mul.o div.o
add.o, sub.o, mul.o, div.o : add.cpp sub.cpp mul.cpp div.cpp
g++ -c ./add.cpp ./sub.cpp ./mul.cpp ./div.cpp -I ./
  • 使用变量和匹配
1
2
3
4
5
6
7
8
9
10
target = test
lib = libcalculate.a
obj = add.o sub.o mul.o div.o

$(target) : main.cpp $(lib)
g++ main.cpp -o $(target) -L ./ -l calculate
$(lib) : $(obj)
ar rcs $(lib) $(obj)
%.o : %.cpp
g++ -c $^
  • 使用函数
1
2
3
4
5
6
7
8
9
10
11
12
13
target = test
lib = libcalculate.a
# 搜索当前目录下的*.cpp文件
src = $(wildcard ./*.cpp)
# 将src中的*.cpp替换为*.o (注意:只是替换变量字符串,并非修改磁盘文件的后缀)
obj = $(patsubst %.cpp, %.o, $(src))

$(target) : main.cpp $(lib)
g++ main.cpp -o $(target) -L ./ -l calculate
$(lib) : $(obj)
ar rcs $(lib) $(obj)
%.o : %.cpp
g++ -c $^
  • 伪目标的声明
1
2
3
4
...
.PHONY:clean # 声明伪目标
clean:
rm ./*.o ./*.a ./test
1
2
make clean # 调用makefile中伪目标clean对应的命令
make # 重新调用make
  • 完整的makefile示例
1
2
3
4
5
6
7
8
9
10
11
# folder structure
├── libcalculate
│ ├── add.cpp
│ ├── calculate.h
│ ├── div.cpp
│ ├── mul.cpp
│ └── sub.cpp
└── test
├── calculate.h
├── main.cpp
└── makefile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
target = test
dir = ../libcalculate
lib = libcalculate.a
# 搜索指定目录下的*.cpp文件
src = $(wildcard $(dir)/*.cpp)
# 将src中的*.cpp替换为*.o (注意:只是替换变量字符串,并非修改磁盘文件的后缀)
obj = $(patsubst %.cpp, %.o, $(src))

$(target) : main.cpp $(lib)
g++ main.cpp -o $(target) -L $(dir) -l calculate
$(lib) : $(obj)
ar rcs $(dir)/$(lib) $(obj)
%.o : %.cpp
g++ -c $^ -o $(dir)/$@

clean:
rm $(dir)/*.o $(dir)/*.a ./test
1
/test$ make

GDB调试