Linux 杂乱学习笔记

前言

  • Uboot、根文件系统、Linux
  • Linux驱动分为三大类,字符设备驱动、块设备驱动、网络设备驱动

linux 入门

基础

user@machine: ~$

  • $ 代表当前用户是普通用户
  • # 代表当前用户是root

rootfs 根文件系统

/bin
存储一些二进制可执行命令文件,/usr/bin也存放了一些基于用户的命令文件。

在这里,我们可以找到准备执行的 Linux 命令,如ls、cp和echo ,以及bash和csh等 shell 。

/sbin
此目录页用户存放一些可执行文件,但是此目录下的文件或者说命令只有管理员才能使用。 /usr/sbin也存储了许多系统命令。

/root
超级用户 root的根目录文件。

/home
普通用户默认目录,在该目录下,每个用户都有一以本名命的文件夹。

/boot
存放 Ubuntu系统内核镜像和引导加载文件

/media
/media目录包含当我们将任何可移动媒体设备连接到系统时用作安装点的子目录。

/mnt
通常包括系统引导后被挂载的文件点。 通常包括系统引导后被挂载的文件点。

与/media不同,系统会自动挂载可移动媒体,而/mnt下我们需要手动挂载

/dev
dev 是 device 的缩写,所以此目录下的文件都是和设备有关的,此目录下的文件都是设备文件。在 Linux 下一切皆文件,即使是硬件设备,也是以文件的形式存在的。

/etc
保存系统管理所需的配置文件和目录。

/lib
lib 是 library 的简称,保存系统程序运行所需的库文件, /usr/lib下存放了一些用于普通用户的库文件。这些
库文件是共享库,命令和用户编写的应用程序要使用这些库文件。

/lost+found
一般为空,当系统非正常关机以后此文件夹会保存些零散文件。

/var (variable 可变动的)
存储一些不断变化的文件 ,比如日志文件 。

/usr (Unix Software Resource)
Unix 操作系统软件资源目录。包括与系统用户直接有关的文件和目录,比如应程序所需库。

/proc
虚拟目录,不实际存储在磁盘上通常用来保系统信息和进程。此目录一般是空的,当 Linux 系统启动以后会将此目录作为 proc 文件系统的挂载点,proc 是个虚拟文件系统,没有实际的存储设备。

/tmp
存储系统和用户的临时文件,该夹对所有都提供读写权限。

/opt
可选第三方程序的存放目录。

/sys
系统启动以后此目录作为 sysfs 文件系统的挂载点,sysfs 是一个类似于 proc 文件系统的特殊文件系统,sysfs 也是基于 ram 的文件系统,也就是说它也没有实际的存储设备。此目录是系统设备管理的重要目录,此目录通过一定的组织结构向用户提供详细的内核数据结构信息。

Shell 基本操作

快捷键

^x(Ctrl+x)

^C 终止前面运行程序

^D 退出exit

^L 清屏

^A 光标移到到最前面

^E 光标移到到最后面

^U 删除光标前面所有字符

^K 删除光标前面所有字符

Alt+Backspace 删除一个单词

^R 搜索历史命令

Alt+. 引用最后一个命令的参数等价于!$

Esc . 同上

历史命令

  • # history
  • 光标上下
  • ^R 搜索历史命令
  • !200 特定序号
  • !字符串 以某字符串开头的
  • !$ 引用最后一个命令的参数

Ctrl+R可以调出 bash中曾经的历史命令,

再次按Ctrl+R可以切换匹配的内容

光标会停留在 第一次被匹配的字符上, (即使后面你再输入被匹配的字符, 光标也不移动)

然后, 根据你的需要 来进行任何一次的操作, 都表示接受: (也就是说, 这个时候, 你就可以当作 你已经输入了这样的命令, 你就可以直接对该命令进行操作/编辑/修改了….)

如:
向前, 向后进行编辑: ctrl+F, ctrl+B
删除前面,后面的字符: ctrl+D,ctrl+H
移动到命令结尾,开头:ctrl+E, ctrl+A

初窥文件系统

在 Windows 下有 FAT、NTFS 和 exFAT 这样的文件系统,在 Linux 下的文件系统主要有 ext2、ext3、ext4 等文件系统。

Linux 还支持其他的 UNIX 文件系统,比如 XFS、JFS、UFS 等,也支持 Windows 的 FAT 文件系统和网络文件系统 NFS 等。

格式化:在windows 下的格式化其实我们应该理解成更换(或者说更新)文件系统,而格式化就是理解成把磁盘等等硬件设备按照文件系统的要求的格式进行划分。每个文件系统的规则都是不一样的,这也是为什么格式化之后文件都没了,因为新的文件系统规则是无法兼容旧的文件系统规则的,所以自然也就无法读取旧的文件系统的数据。

在windows下磁盘的分区是根据盘符来加以区分,而在linux下是根据磁盘分区的挂载点(mount命令)来确定位置。

磁盘管理

linux下磁盘的操作主要是通过 fdisk 命令

通过 fdisk 建立的磁盘 我们需要给他创建(构建)一个文件系统 创建文件系统后就能存放文件,这里用的就是 mkfs 命令去构建文件系统

在linux下和windows下不一样的是,windows会自动分配盘符给你,但是linux需要“手动分配盘符”,linux下是没有盘符的概念,linux是基于根目录/的根概念,所以我们可以认为linux只有一个盘符,我们只能把磁盘挂在“树的枝叶”上,也就是某个目录,这就涉及到了mount和unmount挂载和卸载的命令。

点击转到 fdisk 命令

点击转到 mkfs 命令

点击转到 mount 命令

文件类型&权限

文件类型

1
2
3
4
# ls -l
drwxr-xr-x 1 root root 4096 May 21 2019 vmware-tools
lrwxrwxrwx 1 root root 23 May 21 2019 vtrgb -> /etc/alternatives/vtrgb
-rw-r--r-- 1 root root 4942 Apr 9 2019 wgetrc
第一个字母
-普通文件
d目录文件
c字符设备文件,串口,音频等
b块设备文件,U盘,硬盘等
l符号链接
s套接字文件
p管道文件 FIFO

文件权限

其后九个字母,每三个为一组。

  • 第一组表示用户的权限
  • 第二组表示用户组的权限
  • 第三组表示其他用户的权限

列如-rw-r--r-- 1 root root 4942 Apr 9 2019 wgetrc

  • root用户权限是rw-
  • root组的权限是r--
  • 其他用户权限是r--
字母二进制
r1004可读权限: 如果目录没有可读权限,则无法用 ls 等命令查看目录中的文件内容.
w0102可写权限: 如果目录没有可写权限,则无法在目录中创建文件, 也无法在目录中删除文件.
x0011可执行权限:如果没有目录可执行权限,则无法 cd 到目录中
字母归属
aall user
uuser
ggroup user
oother user
字母操作
=拥有权限
+增加权限
-删除权限

chmod 文件权限修改

chmod [参数 ] [文件名 /目录名]

参数
-c类似-v,回显更改的部分
-f不显示错误信息
-R递归
-v显示执行过程
-t粘滞位
1
2
3
4
5
6
7
8
9
10
# 修改权限 
# test_dir文件夹权限更改为 rwxrwxrwx
chmod 777 test_dir
# 向组用户添加rwx权限
chmod g+rwx
# 递归更改为rwx权限
chmod -R 777 test_dir

# 755
# drwxr-xr-x

粘滞位

other用户可以在特定的目录下创建文件并写入,但是不想让任何人删除掉自己的文件

chown 文件夹归属修改

chown [参数 ] [用户名 .<组名 >] [文件名 /目录 ]

参数
-c类似-v,回显更改的部分
-f不显示错误信息
-h只对符号链接修改
-R递归
-v显示执行过程
1
2
# 递归修改dir文件夹归属者为 frank
sudo chown -Rv frank.frank dir/

文件夹权限

  • 目录的可执行权限是表示你可否在目录下执行命令。
  • 如果目录没有 - x 权限,则无法对目录执行任何命令,甚至无法 cd 进入目, 即使目录仍然有 - r 读权限(这个地方很容易犯错,认为有读权限就可以进入目录读取目录下的文件)
  • 而如果目录具有 - x 权限,但没有 - r 权限,则用户可以执行命令,可以 cd 进入目录。但由于没有目录的读权限
  • 所以在目录下,即使可以执行 ls 命令,但仍然没有权限读出目录下的文档。

压缩命令

zip [参数 ] [压缩文件名.zip] [被压缩的文件]

-r递归压缩,将指定目录下的所有文件和子一起压缩。
-v显示指令执行过程。
-num压缩率,为 1~9的数值。
-m压缩完成以后删除源文件。
-g将文件压缩入现有压缩文件中,不需要新建。
-n<字尾符号>不压缩特定拓展名文件
-P密码

unzip [参数 ] [压缩文件名 .zip]

-d解压到指定目录
-P密码
-v显示指令执行过程。
1
2
3
4
# 压缩
zip -rv -9 a.zip *.jpg
# 解压
unzip -d a a.zip

.bz2 .gz .xz文件

一般来说bz2的压缩率最高, 但是速度太慢了, gz压缩率比较均衡速度也比较快, tar只会打包不会压缩.

tar [参数 ] [压缩文件名] [被压缩文件名]

-c打包(将所有文件变成一个文件 Create a new archive)
-x解压缩, 解包
-jtar生成压缩文件 ,bzip2压缩
-ztar生成压缩文件,gzip压缩
-f<文件名>指定压缩文件
-v显示执行过程
-C,–directory=DIR执行任何操作前请先更改为DIR。 该选项是顺序敏感的,即它影响后面的所有选项。
1
2
3
4
5
6
7
8
9
10
11
12
13
# 压缩 bzip2
tar -cjvf 1.tar.bz2 *.*
#☆压缩 gzip
tar -czvf 1.tar.gz *.*
# 压缩 = c
tar -cvf a.tar /etc

# 解压 = x
tar -jxvf 1.tar.bz2
tar -zxvf 1.tar.gz
#tar会自动检测压缩类型,并且解压缩包文件。同样的命令可以用来解压缩使用其他算法,例如:.tar.gz 或者.tar.bz2 压缩的文件。
tar -v -x -f archive.tar.xz
tar -v -x -f archive.tar.xz -C ./dir1

用户和组 管理

/etc/passwd文件

Linux 系统中的 /etc/passwd 文件,是系统用户配置文件,存储了系统中所有用户的基本信息,并且所有用户都可以对此文件执行读操作。

1
2
# 查看用户和用户组
sudo cat /etc/passwd

每行用户信息都以 “:” 作为分隔符,划分为 7 个字段,每个字段所表示的含义如下:

用户名:密码:UID(用户ID):GID(组ID):描述性信息:主目录:默认Shell

读者可能会问,Linux 系统中默认怎么会有这么多的用户?这些用户中的绝大多数是系统或服务正常运行所必需的用户,这种用户通常称为系统用户或伪用户。系统用户无法用来登录系统,但也不能删除,因为一旦删除,依赖这些用户运行的服务或程序就不能正常执行,会导致系统问题。

UID 用户ID

UID,也就是用户 ID。每个用户都有唯一的一个 UID,Linux 系统通过 UID 来识别不同的用户。

实际上,UID 就是一个 0~65535 之间的数,不同范围的数字表示不同的用户身份,具体如表 1 所示。

UID 范围用户身份
0超级用户。UID 为 0 就代表这个账号是管理员账号。在 Linux 中,如何把普通用户升级成管理员呢?只需把其他用户的 UID 修改为 0 就可以了,这一点和 Windows 是不同的。不过不建议建立多个管理员账号。
1~499系统用户(伪用户)。也就是说,此范围的 UID 保留给系统使用。其中,199 用于系统自行创建的账号;100499 分配给有系统账号需求的用户。 其实,除了 0 之外,其他的 UID 并无不同,这里只是默认 500 以下的数字给系统作为保留账户,只是一个公认的习惯而已。
500~65535普通用户。通常这些 UID 已经足够用户使用了。但不够用也没关系,2.6.x 内核之后的 Linux 系统已经可以支持 232 个 UID 了。

GID 组ID

全称“Group ID”,简称“组ID”,表示用户初始组的组 ID 号。这里需要解释一下初始组和附加组的概念。

初始组,指用户登陆时就拥有这个用户组的相关权限。每个用户的初始组只能有一个,通常就是将和此用户的用户名相同的组名作为该用户的初始组。比如说,我们手工添加用户 lamp,在建立用户 lamp 的同时,就会建立 lamp 组作为 lamp 用户的初始组。

附加组,指用户可以加入多个其他的用户组,并拥有这些组的权限。每个用户只能有一个初始组,除初始组外,用户再加入其他的用户组,这些用户组就是这个用户的附加组。附加组可以有多个,而且用户可以有这些附加组的权限。

举例来说,刚刚的 lamp 用户除属于初始组 lamp 外,我又把它加入了 users 组,那么 lamp 用户同时属于 lamp 组和 users 组,其中 lamp 是初始组,users 是附加组。

当然,初始组和附加组的身份是可以修改的,但是我们在工作中不修改初始组,只修改附加组,因为修改了初始组有时会让管理员逻辑混乱。

需要注意的是,在 /etc/passwd 文件的第四个字段中看到的 ID 是这个用户的初始组。

/etc/shadow 文件

/etc/shadow 文件,用于存储 Linux 系统中用户的密码信息,又称为“影子文件”。

参考

1
2
# 查看密码文件 
sudo cat /etc/shadow

每行用户信息被划分为 9 个字段。每个字段的含义如下(时间的单位是天):

用户名:加密密码:最后一次修改时间:最小修改时间间隔:密码有效期:密码需要变更前的警告天数:密码过期后的宽限时间:账号失效时间:保留字段

1
2
3
4
5
6
frank@ubuntu-hyper:~$ sudo cat /etc/shadow
root:!:19361:0:99999:7:::
daemon:*:19235:0:99999:7:::
...
frank:$strstrstrssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss/:19361:0:99999:7:::
...

最后一次修改时间

此字段表示最后一次修改密码的时间,可是,为什么 root 用户显示的是15775 呢?

这是因为,Linux 计算日期的时间是以1970 年1 月1 日(UTC/GMT的午夜)作为1 不断累加得到的时间,到1971 年1 月1 日,则为366 天。这里显示15775 天,也就是说,此 root 账号在1970 年1 月1 日之后的第15775 天修改的 root 用户密码。

那么,到底15775 代表的是哪一天呢?可以使用如下命令进行换算:

1
2
frank@ubuntu-hyper:~$ date -d "1970-01-01 19361 days"
2023年 01月 04日 星期三 00:00:00 CST

可以看到,通过以上命令,即可将其换算为我们习惯的系统日期。

/etc/group文件

/ect/group 文件是用户组配置文件,即用户组的所有信息都存放在此文件中。

此文件是记录组 ID(GID)和组名相对应的文件。前面讲过,etc/passwd 文件中每行用户信息的第四个字段记录的是用户的初始组 ID,那么,此 GID 的组名到底是什么呢?就要从 /etc/group 文件中查找。

各用户组中,还是以 “:” 作为字段之间的分隔符,分为 4 个字段,每个字段对应的含义为:

组名:密码:GID:该用户组中的用户列表

user用户管理

su 切换root

切换成root用户

“sudo su 用户名 ”即可切换回去

第一次运行root没有密码需要先设置一个密码

1
sudo passwd root #输入密码就行了

查看用户

  • cat /etc/passwd文件就行了
  • 看第三个参数:1000以上的,就是后面建的用户了.其它则为系统的用户

adduser添加用户(优)

添加用户(需要Root权限)

会自动为创建的用户指定主目录、系统shell版本,会在创建时输入用户密码。

useradd 添加用户

需要使用参数选项指定上述基本设置,如果不使用任何参数,则创建的用户无密码、无主目录、没有指定shell版本。

deluser删除用户

删除用户(需要Root权限)

userdel 删除用户

◬ usermod 修改账号设定

参数说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
  -b, --badnames                allow bad names
-c, --comment 注释 GECOS 字段的新值
-d, --home HOME_DIR 用户的新主目录
-e, --expiredate EXPIRE_DATE 设定帐户过期的日期为 EXPIRE_DATE
-f, --inactive INACTIVE 过期 INACTIVE 天数后,设定密码为失效状态
-g, --gid GROUP 强制使用 GROUP 为新主组
◬ -G, --groups GROUPS 新的附加组列表 GROUPS
-a, --append GROUP 将用户追加至上边 -G 中提到的附加组中,
并不从其它组中删除此用户
-h, --help 显示此帮助信息并推出
-l, --login LOGIN 新的登录名称
-L, --lock 锁定用户帐号
-m, --move-home 将家目录内容移至新位置 (仅于 -d 一起使用)
-o, --non-unique 允许使用重复的(非唯一的) UID
-p, --password PASSWORD 将加密过的密码 (PASSWORD) 设为新密码
-R, --root CHROOT_DIR chroot 到的目录
-P, --prefix PREFIX_DIR prefix directory where are located the /etc/* files
-s, --shell SHELL 该用户帐号的新登录 shell
-u, --uid UID 用户帐号的新 UID
-U, --unlock 解锁用户帐号
-v, --add-subuids FIRST-LAST 添加子 UID 范围
-V, --del-subuids FIRST-LAST 移除子 UID 范围
-w, --add-subgids FIRST-LAST 添加子 GID 范围
-W, --del-subgids FIRST-LAST 移除子 GID 范围
-Z, --selinux-user SEUSER 用户账户的新 SELinux 用户映射
1
2
3
4
5
6
7
8
# 示例
# 将 userA 加入到 groupB 中
# Note 当时这个权限修改了但是没有生效 可能是要重开 ssh 我当时是重启主机解决的
usermod -aG userA groupB


#修改用户说明
usermod -c "test user" lamp

passwd 设置修改密码

1
sudo passwd root

id查看用户UID GID 归属 组

groupadd 添加用户组

groupdel 删除用户组

groupmod修改用户组信息

Note

给用户添加sudo权限 以及免除密码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 将用户添加一个附加sudo群组就好
# 下面有两种方法

# 1 修改group
# 查看sudo群组的id
cat /etc/group | grep 'sudo'
# 给new_username增加一个sudo群组
usermod -G 27 new_username
# id可以看到new_username多了一个群组
id new_username

# 2 修改sudoers
vim /etc/sudoers
# 然后在root ALL=(ALL:ALL) ALL下面添加上:
new_username ALL=(ALL:ALL) ALL


# 免除全部密码
your_user_name ALL=(ALL) NOPASSWD: ALL
# 免除部分命令的密码
your_user_name ALL= (root) NOPASSWD: /sbin/mount, (root) NOPASSWD: /bin/umount, (root) NOPASSWD: /mnt/mount, (root) NOPASSWD: /bin/rm, (root) NOPASSWD: /usr/bin/make, (root) NOPASSWD: /bin/ln, (root) NOPASSWD: /bin/sh, (root) NOPASSWD: /bin/mv, (root) NOPASSWD: /bin/chown, (root) NOPASSWD: /bin/chgrp, (root) NOPASSWD: /bin/cp, (root) NOPASSWD: /bin/chmod

ubuntu apt包管理

换源

1
2
3
# 一键更换国内软件源脚本
# https://github.com/SuperManito/LinuxMirrors
bash <(curl -sSL https://gitee.com/SuperManito/LinuxMirrors/raw/main/ChangeMirrors.sh)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# 源网站list
# https://www.raspbian.org/RaspbianMirrors
# examp
# mirrors.shu.edu.cn/raspbian/raspbian/
# http://mirrors.aliyun.com/raspbian/raspbian/
#

# 先备份
sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak
#
sudo vim /etc/apt/sources.list

# 改成如下 32bit OS
deb http://mirrors.aliyun.com/raspbian/raspbian/ buster main non-free contrib rpi
deb-src http://mirrors.aliyun.com/raspbian/raspbian/ buster main non-free contrib rpi
# 64bit OS
deb https://mirrors.tuna.tsinghua.edu.cn/debian buster main contrib non-free
deb https://mirrors.tuna.tsinghua.edu.cn/debian-security/ buster/updates main contrib non-free
deb https://mirrors.tuna.tsinghua.edu.cn/debian buster-updates main contrib non-free



# 先备份
sudo cp /etc/apt/sources.list.d/raspi.list /etc/apt/sources.list.d/raspi.list.bak
#
sudo nano /etc/apt/sources.list.d/raspi.list

# 改成如下
# debian 10.x (buster)
deb http://mirrors.aliyun.com/raspbian/raspbian/ buster main ui

# or
deb http://mirrors.tuna.tsinghua.edu.cn/raspbian/raspbian/ buster main ui
# debian 11.x (bullseye)
deb http://mirrors.aliyun.com/raspbian/raspbian/ bullseye main
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# ubuntu 20.04

#添加阿里源
deb https://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse
deb-src https://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse
deb https://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse
deb-src https://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse
deb https://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse
deb-src https://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse
deb https://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse
deb-src https://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse
deb https://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse
deb-src https://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse

# 默认注释了源码镜像以提高 apt update 速度,如有需要可自行取消注释
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-updates main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-updates main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-backports main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-backports main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-security main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-security main restricted universe multiverse

换源后出现证书问题

1
2
3
Err:22 https://mirrors.tuna.tsinghua.edu.cn/ubuntu focal Release
Certificate verification failed: The certificate is NOT trusted. The certificate chain uses expired certificate. Could not handshake: Error in the certificate verification. [IP: 101.6.15.130 443]
# 证书验证失败:证书不受信任。证书链使用过期的证书。无法握手:证书验证中出现错误。

原因为未安装ca-certificates

可以先使用http代替掉https,然后安装ca-certificates

安装 ca-certificates.

1
sudo apt-get install ca-certificates

再次 sudo apt-get update 发现问题已经消失.

1
2
3
4
5
6
7
sudo gpg --keyserver keyserver.ubuntu.com --recv 5523BAEEB01FA116 //(这个公钥根据提示来写的)
# eg.
# sudo gpg --keyserver keyserver.ubuntu.com --recv 648ACFD622F3D138 0E98404D386FA1D9 DCC9EFBF77E11517 112695A0E562B32A 54404762BBB6E853

sudo gpg --export --armor 5523BAEEB01FA116 | sudo apt-key add -
# eg.
# sudo gpg --export --armor 648ACFD622F3D138 0E98404D386FA1D9 DCC9EFBF77E11517 112695A0E562B32A 54404762BBB6E853 | sudo apt-key add -

常用命令

1
2
3
4
5
6
7
8
# 安装指定版本的包
# sudo apt-get install package=version
sudo apt-get install python3=3.7.3-1
# 列出所有包 apt-cache madison package
apt-cache madison python3

# 搜索相关r
apt-cache search <keyword>

更新源&包

1
2
3
4
# 更新源
sudo apt-get update
# 更新软件包
sudo apt-get upgrade

卸载包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 删除包
sudo apt-get remove nginx

# 查找 xx 相关软件
dpkg --get-selections|grep nginx

# 删除包及其配置
sudo apt-get --purge remove nginx
sudo apt-get purge --auto-remove nginx

# 删除不使用的包
sudo apt-get autoremove

# 清除缓存
sudo apt-get clean

linux 进阶

防火墙

https://zhuanlan.zhihu.com/p/139381645

https://wiki.ubuntu.org.cn/Ufw%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# 安装
sudo apt-get install ufw
# 启动
sudo ufw enable
# 以下这条命令 我们设置默认的规则为allow, 这样除非指明打开的端口, 否则所有端口默认都是关闭的。
sudo ufw default deny
# 查看状态
sudo ufw status
# 查看状态和规则编号
sudo ufw status numbered

ufw [--dry-run] route [delete] [insert NUM] allow|deny|reject|limit [in|out on INTERFACE] [log|log-all] [proto PROTOCOL] [from ADDRESS [port PORT]] [to ADDRESS [port PORT]]

sudo ufw allow 80 允许外部访问80端口
# 这个好像最大一次性只能开一百个
sudo ufw allow 50000:50100/tcp 允许外部访问端口范围

# 允许eth0的所有流量
sudo ufw allow in on eth0

# 删除允许访问 80 端口的规则
sudo ufw delete allow 80
# 删除编号为 66 的规则
sudo ufw delete 66

sudo ufw allow from 192.168.1.1 允许此IP访问所有的本机端口

sudo ufw deny smtp 禁止外部访问smtp服务

# 想要允许连接通过指定网络接口,使用allow in on 和 网络接口的名字:
sudo ufw allow in on eth2 to any port 3306

sudo ufw delete allow smtp 删除上面建立的某条规则

# 要拒绝所有的TCP流量从10.0.0.0/8 到192.168.0.1地址的22端口
sudo ufw deny proto tcp from 10.0.0.0/8 to 192.168.0.1 port 22

# 可以允许所有RFC1918网络(局域网/无线局域网的)访问这个主机(/8,/16,/12是一种网络分级):
sudo ufw allow from 10.0.0.0/8

sudo ufw allow from 172.16.0.0/12

sudo ufw allow from 192.168.0.0/16

环境变量

  1. echo 查看单个环境变量
1
echo $HOME
  1. env 查看全部环境变量
1
2
3
4
5
env
env | grep SSH

# export 也可以查看
export
  1. set 查看本地定义的环境变量
1
set
  1. export 设置一个新的环境变量(临时的,重启后消失)
1
export HELLO="hello"
  1. unset 清除环境变量
1
unset HELLO
  1. readonly 设定只读环境变量
1
readonly HELLO="hello"
  1. 添加环境变量
1
2
# 将/usr/local/nginx/sbin/目录临时添加到环境变量中
export PATH=/usr/local/nginx/sbin/:$PATH
  1. 设定永久环境变量(其实就是开机/启动bash等等这些操作之前会运行一个脚本,我们的思路就是在这个脚本)
1
2
3
4
# 编辑后面的特定位置的文件  示例是当前用户的bash的启动执行的脚本  如果是其他终端则修改的是对应的脚本  比如zsh 修改的是.zshrc
vim ~/.bashrc
# 加上环境变量
export DONT_PROMPT_WSL_INSTALL=1

一些常见环境变量

  1. PATH:决定了shell将到哪些目录中寻找命令或程序
  2. HOME:指定用户的主目录(即用户登录到Linux系统时的默认目录)
  3. HISTSIZE:保存历史命令记录的条数
  4. LOGNAME:显示当前用户的登录名 (同 指令logname)
  5. HOSTNAME:显示主机的名字 (同 指令hostname)
  6. SHELL:指当前用户使用的shell类型
  7. LANG/LANGUGE:语言相关的环境变量,多语言可以修改此环境变量

环境变量存放的位置

  1. etc/profile (所有用户)

这个文件是每个用户登录时都会运行的环境变量设置,当用户第一次登陆时该文件被执行*(这就是用户启动执行特定程序的原理了)*,并从/etc/profile.d目录的配置文件中搜索shell的设置。这个文件的作用就是当用户登录的时候用于获取系统的环境变量,只在登录的时候获取一次。

所以说,在/etc/profile文件中添加的变量,对所有用户永久的生效

  1. ~/.bash_profile(单个用户)

每个用户都可以使用该文件输入自己专用的shell信息,当用户登录时,该文件仅仅执行一次。默认情况下,它设置一些环境变量,执行用户的.bashrc文件。单个用户对此文件的修改只会影响到它以后的每一次登录。

也就是说,在用户目录下的.bash_profile文件中增加变量,仅对当前用户永久生效, 操作同 /etc/profile

  1. /etc/bashrc(所有用户)

在执行完 /etc/profile 内容后,如果用户运行 bash shell 的话,则就执行这个文件,当**每次一个新的bash shell 被打开时,该文件被读取**。****所以,如果每打开一个bash都执行某些操作,就可以在这个文件里面设置。

  1. ~/.bashrc (单个用户)

该文件只包含专用于你的bash信息,当你登录时以及每次打开新的shell时,该文件就会自动被读取

  1. ~/.bash_logout每次在退出shell的时候会执行该文件

每次在退出shell的时候会执行该文件,它提供了定制用户环境的功能,比如删除账号内的临时文件等命令就可以放在bash_logout 文件内,如果这个文件不存在的话则就执行其他的命令。

管道

xargs

https://www.runoob.com/linux/linux-comm-xargs.html

xargs 可以将管道或标准输入(stdin)数据转换成命令行参数,也能够从文件的输出中读取数据。

命令格式:

1
somecommand |xargs -item  command
  • -a file 从文件中读入作为 stdin
  • -e flag ,注意有的时候可能会是-E,flag必须是一个以空格分隔的标志,当xargs分析到含有flag这个标志的时候就停止。
  • -p 当每次执行一个argument的时候询问一次用户。
  • -n num 后面加次数,表示命令在执行的时候一次用的argument的个数,默认是用所有的。
  • -t 表示先打印命令,然后再执行。
  • -i 或者是-I,这得看linux支持了,将xargs的每项名称,一般是一行一行赋值给 {},可以用 {} 代替。
  • -r no-run-if-empty 当xargs的输入为空的时候则停止xargs,不用再去执行了。
  • -s num 命令行的最大字符数,指的是 xargs 后面那个命令的最大命令行字符数。
  • -L num 从标准输入一次读取 num 行送给 command 命令。
  • -l 同 -L。
  • -d delim 分隔符,默认的xargs分隔符是回车,argument的分隔符是空格,这里修改的是xargs的分隔符。
  • -x exit的意思,主要是配合-s使用。。
  • -P 修改最大的进程数,默认是1,为0时候为as many as it can ,这个例子我没有想到,应该平时都用不到的吧。

Example

复制所有图片文件到 /data/images 目录下:

1
ls *.jpg | xargs -n1 -I {} cp {} /data/images

inode

参考:

inode(index node) 是 UNIX 操作系统中的一种数据结构,其本质是[结构体],它包含了与文件系统中各个文件相关的一些重要信息。在 UNIX 中创建文件系统时,同时将会创建大量的 inode 。通常,文件系统磁盘空间中大约百分之一空间分配给了 inode 表。

inode主要是记录文件的元信息,比如文件权限信息、文件的大小、文件修改信息、文件位置信息(data block id)等等,我们可以理解为是文件的索引(index)。

如何通过inode找到文件数据的位置?

ext2文件系统中,inode存在12个直接指针1个间接指针(可以理解为指针),1个双重间接块指针(可以理解为指向指针的指针 两重指针),1个三重间接块指针(可以理解为 三重指针),通过这几个指针的索引我们就能找到对应的文件存放的位置。

我们假定每个指针占用4Byte的空间,每个Blocks大小为4KB(SSD的4K对齐应该也是指的这个)。

  • 直接块指针:
    • 前12个直接指针,直接指向存储数据的区域。blocks大小为4KB,前12个直接指针就可以保存48KB的文件
  • 间接块指针(一级间接快指针):
    • 每个指针占用4Byte,则间接快指针指向的Blocks可以保存(4*1024)/4=1024个记录(或者称为直接指针),也就是对应1024个Blocks,那么间接块指针可存储文件数据大小为1024*4KB=4MB
  • 双重间接块指针(二级间接快指针):
    • 同理,双重间接块指针可以储存文件数据大小为1024*1024*4KB=4GB
  • 三重间接块指针(三级间接快指针):
    • 同理,三重间接块指针可以储存文件数据大小为1024*1024*1024*4KB=4TB

操作系统:文件系统- 掘金

弊端

该存储结构带来的问题是对于大型文件,我们需要多次调用才可以访问对应块的内容,因此访问速度较慢。为此,ext4提出了新的解决方案:Extents。简单的说,Extents以一个树形结构来连续存储文件块,从而提高访问速度,大致结构如下图所示。

AFEIC: Advanced forensic Ext4 inode carving - ScienceDirect

冷知识:

同一个文件在磁盘上的物理位置可能不会是连续的, 大概率都是分散开的, 散落在磁盘的各个位置.

image-20230107231700676

使用

df

我们可以通过df命令查看所有已挂载的文件系统中已使用的 inode 的数目,以及文件系统中总体使用情况的百分比。

1
2
3
❯ df -i
Filesystem Inodes IUsed IFree IUse% Mounted on
/dev/sdc 67108864 556871 66551993 1% /

stat

我们可以通过stat命令查看文件(包括目录)的inode信息

1
2
3
4
5
6
7
8
9
❯ stat use_proxy.sh
File: use_proxy.sh
Size: 720 Blocks: 8 IO Block: 4096 regular file
Device: 820h/2080d Inode: 552923 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 1000/ frank) Gid: ( 1000/ frank)
Access: 2022-12-11 22:29:33.000000000 +0800
Modify: 2022-10-31 17:10:16.000000000 +0800
Change: 2022-12-11 22:31:28.141006225 +0800
Birth: -

find

我们可以通过find命令找特定inode号的文件

1
2
3
4
5
6
7
8
9
# 根目录的inode号为2
❯ find / -inum 2
/

❯ ll -li ~
total 16K
552923 -rw-r--r-- 1 frank frank 720 10月 31 17:10 xxx.sh
❯ find ~ -inum 552923
/home/frank/xxx.sh

硬链接 和 软连接(符号链接)

参考:Linux硬链接和软连接的区别与总结,硬链接和软连接(符号链接)的区别,linux中软链接和硬链接是什么意思?

硬链接(Hard Link) 和软链接(Symbolic Link)

img

硬链接(Hard Link)

硬链接是多个目录项中的「索引节点」指向一个文件,也就是指向同一个 inode,但是 inode 是不可能跨越文件系统的,每个文件系统都有各自的 inode 数据结构和列表,所以硬链接是不可用于跨文件系统的。由于多个目录项都是指向一个 inode,那么只有删除文件的所有硬链接以及源文件时,系统才会彻底删除该文件。

img

有关硬链接的总结

  1. 不可以在不同文件系统的文件间建立链接(Inode范围问题)
  2. 只有超级用户才可以为目录创建硬链接。
  3. 具有相同inode节点号的多个文件互为硬链接文件;
  4. 删除硬链接文件或者删除源文件任意之一,文件实体并未被删除;只有删除了源文件和所有对应的硬链接文件,文件实体才会被删除;
  5. 硬链接文件是文件的另一个入口;
  6. 可以通过给文件设置硬链接文件来防止重要文件被误删;
  7. 创建硬链接命令 ln 源文件 硬链接文件;
  8. 硬链接文件是普通文件,可以用rm删除;
  9. 对于静态文件(没有进程正在调用),当硬链接数为0时文件就被删除。注意:如果有进程正在调用,则无法删除或者即使文件名被删除但空间不会释放。

软链接(Symbolic Link)

软链接相当于重新创建一个文件,这个文件有独立的 inode,但是这个文件的内容是另外一个文件的路径,所以访问软链接的时候,实际上相当于访问到了另外一个文件,所以软链接是可以跨文件系统的,甚至目标文件被删除了,链接文件还是在的,只不过指向的文件找不到了而已。

img

有关软链接的总结

  1. 软链接类似windows系统的快捷方式;
  2. 软连接的目标文件建议使用绝对路径,否则软连接被移动后将会失效。
  3. 软链接里面存放的是源文件的路径,指向源文件;
  4. 删除源文件,软链接依然存在,但无法访问源文件内容;
  5. 软链接失效时一般是白字红底闪烁;
  6. 软链接和源文件是不同的文件,文件类型也不同,inode号也不同 是两个不同的文件
  7. 软链接的文件类型是“l”,可以用rm删除。

两者区别

硬链接和软链接的区别

原理上,硬链接和源文件的inode节点号相同,两者互为硬链接。软连接和源文件的inode节点号不同,进而指向的block也不同,软连接block中存放了源文件的路径名。

实际上,硬链接和源文件是同一份文件,而软连接是独立的文件,类似于快捷方式,存储着源文件的位置信息便于指向。

使用限制上,不能对目录创建硬链接,不能对不同文件系统创建硬链接,不能对不存在的文件创建硬链接;可以对目录创建软连接,可以跨文件系统创建软连接,可以对不存在的文件创建软连接。

命令

硬链接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
$ ls -lhi
1180598 -rw-rw-r-- 3 frank frank 5 2月 12 22:31 123.txt
$ stat *.txt
文件:123.txt
大小:5 块:8 IO 块:4096 普通文件
设备:805h/2053d Inode:1180598 硬链接:1
...

# 使用 ln 命令创建链接 先看看语法
$ ln --help
用法:ln [选项]... 目标... 目录
在指定<目录>中创建指向指定<目标>的链接。
默认创建硬链接,当使用--symbolic 时创建符号链接。
默认情况下,创建每个目标时不应存在与新链接的名称相同的文件。
创建硬链接时,每个指定的<目标>都必须存在。符号链接可以指向任意的位置;
当链接解析正常时,将其解析为一个相对于其父目录的相对链接。
...
# 在当前目录下创建一个 硬链接 '123.ln.txt'指向'123.txt'
$ ln 123.txt ./123.ln.txt
$ ls -lhi
1180598 -rw-rw-r-- 3 frank frank 5 2月 12 22:31 123.ln.txt
1180598 -rw-rw-r-- 3 frank frank 5 2月 12 22:31 123.txt
# 我们可以看到 '123.txt''123.ln.txt' 的Inode指向同一个位置 自然他们的大小也是一致的
# 并且 '硬链接' 的数目由1变成了2
# 如果 rm 其中一个文件, 只是删除了文件指针文件内容并不会删除, 也就是说只有等到 硬链接 数目变成0了内核才会将文件内容删除
$ stat *.txt
文件:123.ln.txt
大小:5 块:8 IO 块:4096 普通文件
设备:805h/2053d Inode:1180598 硬链接:2
...
文件:123.txt
大小:5 块:8 IO 块:4096 普通文件
设备:805h/2053d Inode:1180598 硬链接:2
...

# 加 -s 参数 创建一个 软链接
# 在当前目录下创建一个 软链接 '123.soft.txt'指向'123.txt'
$ ln -s 123.txt ./123.soft.txt
# 注意看 软件链接 的类型是 l
$ ls -hli
1180598 -rw-rw-r-- 3 frank frank 5 2月 12 22:31 123.ln.txt
1181799 lrwxrwxrwx 1 frank frank 7 2月 12 22:41 123.soft.txt -> 123.txt
1180598 -rw-rw-r-- 3 frank frank 5 2月 12 22:31 123.txt
$ stat *.txt
文件:123.ln.txt
大小:5 块:8 IO 块:4096 普通文件
设备:805h/2053d Inode:1180598 硬链接:3
...
文件:123.soft.txt -> 123.txt
大小:7 块:0 IO 块:4096 符号链接
设备:805h/2053d Inode:1181799 硬链接:1
...
文件:123.txt
大小:5 块:8 IO 块:4096 普通文件
设备:805h/2053d Inode:1180598 硬链接:3
...

linux 常用命令

TODO 将这些命令进行分类!

查看支持的shell

1
cat /etc/shells

查看当前使用哪个shell

1
echo $SHELL

更改用户的默认shell

1
chsh -s /bin/zsh  [用户名:模认当前用户]

alias 起别名

命名别名

1
2
3
4
5
6
# 起别名
alias 别名=“路径”
# 取消别名
unalias 别名
# 查看命令类型
type -a ls

别名优先级最高

1
2
3
4
5
6
# 别名优先
ls
# 跳过别名
\ls
"ls"
'ls'

ls list file

  • ls -l 显示文件的详细信息,文件目录具有的权限,当前权限文件的数量,拥有者,所属的群组,文件目录的大小,创建或者修改时间,文件目录的名字。可以使用ls -la

  • ls -R 递归列出目录所有文件

  • ls -a 显示所有文件以及子目录,包括“.”开头的隐藏文件

cd

  • cd / 进入根目录
  • cd .. 返回上一级
  • cd ~ 返回当前用户主目录

pwd显示路径

显示当前文件目录的绝对路径

uname系统信息查看

  • -r 列出当前系统的具体内核版本号。
  • -s 列出系统内核名称。
  • -o 列出系统信息。
  • ubuntu版本查看
1
2
cat /etc/lsb-release
lsb_release -a

clear清屏

快捷键 Ctrl+l(小写的L) 同clear

sudo

暂时提升到root权限

su可以直接变成管理员

  • -h help
  • -p 改变询问密码的提示符(不知道是啥)

wc WordCount

用法

  • wc -l <文件名> 输出行数统计
  • wc -c <文件名> 输出字节数统计
  • wc -m <文件名> 输出字符数统计
  • wc -L <文件名> 输出文件中最长一行的长度
  • wc -w <file name> 显示一个文件的字数
1
2
3
4
$wc 123.txt
7 11 117 123.txt
# 依次是
# 行数 单词数 字节数 文件名称。

cat 文本输出命令

-n 由1开始对所有行进行编号

-b 类似-n不对空行编号

-s 遇到两行空行以上时合并成一个空行

ifconfig 显示网络配置

  • sudo ifconfig ens33 192.168.128.128 修改ip

man 系统帮助-查命令

reboot 重启

poweroff 关机

install 安装软件命令

apt-get

APT工具可以实现软件的自动下载、配置、安装

1
2
3
4
# 查找有哪些版本
apt-cache madison <<package name>>
# 安装指定版本
apt-get install <<package name>>=<<version>>

fdisk 磁盘工具

linux  磁盘管理 fdisk

Linux fdisk 是一个创建和维护分区表的程序,它兼容 DOS 类型的分区表、BSD 或者 SUN 类型的磁盘列表。

语法

1
fdisk [必要参数][选择参数]

必要参数:

  • -l 列出素所有分区表
  • -u 与 -l 搭配使用,显示分区数目

选择参数:

  • -s<分区编号> 指定分区
  • -v 版本信息

菜单操作说明

  • m :显示菜单和帮助信息
  • a :活动分区标记/引导分区
  • d :删除分区
  • l :显示分区类型
  • n :新建分区
  • p :显示分区信息
  • q :退出不保存
  • t :设置分区号
  • v :进行分区检查
  • w :保存修改
  • x :扩展应用,高级功能
1
2
3
4
5
6
7
8
9
10
11
> sudo fdisk /dev/sdb
# 查看帮助
> m
# 删除分区
> d
# 新建分区
> n
# 写入分区表
> w
# 这个时候虽然分区分好了但是还不能使用, 因为没有分配文件系统
> mkfs

mkfs 格式化(建立文件系统)

linux 构造文件系统 mkfs

Linux mkfs(英文全拼:make file system)命令用于在特定的分区上建立 linux 文件系统。

使用方式 :

1
mkfs [-V] [-t fstype] [fs-options] filesys [blocks]

参数

  • 选项:
  • -t, –type=<类型> 文件系统类型;若不指定,将使用 ext2
    fs-options 实际文件系统构建程序的参数
    <设备> 要使用设备的路径
    <大小> 要使用设备上的块数
  • -V, –verbose 解释正在进行的操作;
    多次指定 -V 将导致空运行(dry-run)
  • -h, –help display this help
  • -V, –version display version

实例

将sda6分区格式化为ext3格式

1
mkfs -t ext3 /dev/sda6  

注意:这里的文件系统是要指定的,比如 ext3 ;reiserfs ;ext2 ;fat32 ;msdos 等。

df 磁盘信息

disk free

1
df -h
-h可读显示
-aall
-l本地文件系统
-TType 文件系统类型

du 磁盘使用分析

disk usaged

1
du --max-depth=1 -BM | sort -rn

-h:以人类可读的方式显示。
-a:显示目录占用的磁盘空间大小,还要显示其下目录和文件占用磁盘空间的大小。
-s:只显示目录占用的磁盘空间大小,不显示其子目录和文件占用的磁盘空间大小。
-c:显示几个目录或文件占用的磁盘空间大小,还要统计它们的总和。
–apparent-size:显示目录或文件自身的大小
-l :统计硬链接占用磁盘空间的大小。
-L:统计符号链接所指向的文件占用的磁盘空间大小。

-B: 单位修改 -BM = 用MB -BG=用GB

–max-depth: –max-depth=1列出目录的深度为1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# ** du命令还可以对结果进行排序,以方便快速找出占用空间最多目录。 **

du -s 目录 | sort -rn #这是按字节排序
du -sh 目录 | sort -rn #这是按兆(M)来排序
#由于-sh大小显示看起来是乱的,因此建议使用du -s|sort -nr
du -s 目录 | sort -rn | head #选出排在前面的10个
du -s 目录 | sort -rn | tail #选出排在后面的10个

# ** 统计总数大小 **
du -sh xmldb/
du -sm * | sort -n //统计当前目录大小 并安大小 排序
du -sk * | sort -n
du -sk * | grep guojf //看一个人的大小
du -m | cut -d "/" -f 2 //看第二个/ 字符前的文字

# ** 查看此文件夹有多少文件 /*/*/* 有多少文件 **
du xmldb/
du xmldb/*/*/* |wc -l
# wc [-lmw]说明
# 参数说明:-l :多少行; -m:多少字符; -w:多少字

touch 创建新文件

mkdir 创建文件夹

-p递归创建, 前面的不存在, 就会创建

rmdir 删除文件夹

rm 删除

1
2
3
4
5
6
7
8
# 删除folder文件之外的所有文件
rm -rf !(folder)
#删除folder1和folder2文件之外的所有文件
rm -rf !(folder1 | folder2)
#删除keep文件之外的所有文件
ls | grep -v keep | xargs rm
# 说明: ls先得到当前的所有文件和文件夹的名字, grep -v keep,进行grep正则匹配查找keep,-v参数决定了结果为匹配之外的结果,也就是的到了keep之外的所有文件名,然后 xargs用于从 标准输入获得参数 并且传递给后面的命令,这里使用的命令是 rm,然后由rm删除前面选择的文件。

-d直接把要删除的目录硬连数据成 0 ,删除该目录。
-f直接把要删除的目录硬连数据成 0 ,删除该目录。
-i删除文件或者夹 (目录 )之前先询问用户。
-r递归删除,指定文件夹 (目录 )下的所有文件和子夹全部删除掉。
-v显示删除过程。

cp 复制

cp [参数 ] [源地址 ] [目的地址 ]

-r递归处理,指定目录下一并处理
-f强行复制文件,不管要的是否已经存在于目标录。

mv 文件移动 重命名

mv [参数 ] [源地址 ] [目的地址 ]

-b如果要覆盖文件的话前先进行备份。
-f若目标文件或录与现在的重复,直接覆盖。
-I在覆盖之前询问用户。

find 查找

find [路径 ] [参数 ] [关键字 ]

  • -name<filename> 按照文件名称查找,与 filename匹配的文件,可使用通符。
1
find /etc -name *.config

grep 文件中搜内容

1
grep -r -i code

Linux grep 命令用于查找文件里符合条件的字符串。

grep 指令用于查找内容包含指定的范本样式的文件,如果发现某文件的内容符合所指定的范本样式,预设 grep 指令会把含有范本样式的那一列显示出来。若不指定任何文件名称,或是所给予的文件名为 **-**,则 grep 指令会从标准输入设备读取数据。

参数

  • -B<显示行数> 或 –before-context=<显示行数> : 除了显示符合样式的那一行之外,并显示该行之前的内容。
  • -C<显示行数> 或 –context=<显示行数>或-<显示行数> : 除了显示符合样式的那一行之外,并显示该行之前后的内容。
  • -d <动作> 或 –directories=<动作> : 当指定要查找的是目录而非文件时,必须使用这项参数,否则grep指令将回报信息并停止动作。
  • -n 或 –line-number : 在显示符合样式的那一行之前,标示出该行的列数编号。
  • -r 或 –recursive : 此参数的效果和指定”-d recurse”参数相同。
  • -i 或 –ignore-case : 忽略字符大小写的差别。
  • -v 或 –invert-match : 显示不包含匹配文本的所有行。

我们可以通过管道操作来让grep变得更强大,管道操作就是把前面一条命令的输出作为后面一条命令的输入,从而把很多简单的命令组合起来完成复杂的功能。例如,如果我们想查找包含apple的行,但又想过滤掉pineapple,可以用下面的命令:

1
grep apple fruitlist.txt | grep -v pineapple

如果我们想把搜索结果保存起来,那么可以把命令的标准输出重定向到文件:

1
grep apple fruitlist.txt | grep -v pineapple > apples.txt

重定向符号>和管道操作符号|的区别是,重定向后面接的是一个文件,它后面不能再接任何文件或命令了;而管道操作后面接的是命令,可以无限地接下去。如果想以追加方式写到文件,可以用>>。管道操作是Linux命令行的一种哲学,它是计算机技术中少有的能沿用几十年的技术之一。通过管道操作,一行命令可以完成Windows下上千行程序也不能完成的文本处理功能。

grep [参数 ] 关键字 文件列表

-i无视大小写
-r递归查找
-v反转,只显示不匹配
-w全匹配 match whole word
–exclude-dir排除文件夹
–exclude排除文件
1
2
3
4
5
6
grep -ir "ubuntu" /etc
# 注意 如果 "双引号内带有--" 可能会有不可预知的情况
# grep -ir "--ubuntu" /etc 这种写法会出问题

grep -ir "Application_Initialize" /a_usr/rosemaryCR/mikan/ --exclude-dir=out
grep -ir "CARRIER_HOME_REVERSAL" ./ --exclude=GRTAGS --exclude=mechapi.c

grep 搜索正则表达式并列出

1
2
3
# | grep 22
sudo netstat -ntlp | grep 22
sudo apt list | grep php

pwd

print work directory 输出当前目录

cat

在当前命令窗口输出文件

nano

文本编辑器

mount unmount 挂载卸载

linux 挂载 mount

mount 挂载

1
2
3
4
5
6
7
# 需要先创建一个挂载点
sudo mkdir /mnt/usb
# 挂载
sudo mount /dev/sda1 /mnt/usb

# mount 中文乱码
sudo mount -o iocharset=utf8 /dev/sda1 /mnt/usb

umount 卸载

1
2
3
# 卸载
sudo umount /mnt/usb
# 卸载的时候出错注意是不是文件夹正在使用中

树莓派自动挂载

1
2
3
# 打开文件 添加以下 这个带有超时,可以避免拔掉U盘开不了机
sudo nano /etc/fstab
# /dev/sda1 /mnt/usb auto defaults,nofail,x-systemd.device-timeout=1,noatime 0 0

mkdir 创建文件夹

rmdir 删除文件夹

rm -rf

功能说明:删除文件或目录。

语法:rm [-dfirv][–help][–version][文件或目录]

补充说明:执行rm指令可删除文件或目录,如欲删除目录必须加上参数”-r”,否则预设仅会删除文件。

参数:

  • -d 或 –directory  直接把欲删除的目录的硬连接数据删成0,删除该目录。

  • -f 或 –force  强制删除文件或目录。

  • -i 或 –interactive  删除既有文件或目录之前先询问用户。

  • -r 或 -R 或 –recursive  递归处理,将指定目录下的所有文件及子目录一并处理。

  • -v 或 –verbose  显示指令执行过程。

netstat 列出网络

1
2
3
4
# 列出所有
sudo netstat -ntlp
# 查找
netstat -ntlp | grep 80

ln 文件夹链接

1
2
# 软链接 现有a 链接到b(没有的,目标的)
ln -s a b

dd 读取、转换并输出数据

dd 可从标准输入或文件中读取数据,根据指定的格式来转换数据,再输出到文件、设备或标准输出。

参数说明:

  • if=文件名:输入文件名,默认为标准输入。即指定源文件。
  • of=文件名:输出文件名,默认为标准输出。即指定目的文件。
  • ibs=bytes:一次读入bytes个字节,即指定一个块大小为bytes个字节。
    obs=bytes:一次输出bytes个字节,即指定一个块大小为bytes个字节。
    bs=bytes:同时设置读入/输出的块大小为bytes个字节。
  • cbs=bytes:一次转换bytes个字节,即指定转换缓冲区大小。
  • skip=blocks:从输入文件开头跳过blocks个块后再开始复制。
  • seek=blocks:从输出文件开头跳过blocks个块后再开始复制。
  • count=blocks:仅拷贝blocks个块,块大小等于ibs指定的字节数。
  • conv=<关键字>,关键字可以有以下11种:
    • conversion:用指定的参数转换文件。
    • ascii:转换ebcdic为ascii
    • ebcdic:转换ascii为ebcdic
    • ibm:转换ascii为alternate ebcdic
    • block:把每一行转换为长度为cbs,不足部分用空格填充
    • unblock:使每一行的长度都为cbs,不足部分用空格填充
    • lcase:把大写字符转换为小写字符
    • ucase:把小写字符转换为大写字符
    • swap:交换输入的每对字节
    • noerror:出错时不停止
    • notrunc:不截短输出文件
    • sync:将每个输入块填充到ibs个字节,不足部分用空(NUL)字符补齐。
  • –help:显示帮助信息
  • –version:显示版本信息

dd 进行测速

1
2
3
4
# 以下两条Shell分别测试写入和读取1G的文件从/mnt/usb/目录,就是U盘的挂载点(硬盘测试也可以这样):

time dd if=/dev/zero of=/mnt/usb/1g bs=1024 count=1000000
time dd if=/mnt/usb/1g bs=128k | dd of=/dev/null

source 刷新环境变量

1
2
3
# 刷新环境变量
source ~/.profile
source 后面接文件

tail 循环读取log

1
tail -f filename

file 辨识文件类型

语法

1
file [-bcLvz][-f <名称文件>][-m <魔法数字文件>...][文件或目录...]

参数

  • -b  列出辨识结果时,不显示文件名称。
  • -c  详细显示指令执行过程,便于排错或分析程序执行的情形。
  • -f<名称文件>  指定名称文件,其内容有一个或多个文件名称时,让file依序辨识这些文件,格式为每列一个文件名称。
  • -L  直接显示符号连接所指向的文件的类别。
  • -m<魔法数字文件>  指定魔法数字文件。
  • -v  显示版本信息。
  • -z  尝试去解读压缩文件的内容。
  • [文件或目录…] 要确定类型的文件列表,多个文件之间使用空格分开,可以使用shell通配符匹配多个文件。

curl

-x

每次访问时都需要写代理参数

1
curl -x socks5://127.0.0.1:1024 http://www.google.com # -x 参数等同于 --proxy

-v

curl -v参数会输出请求中访问的路由信息,方便确定是否设置成功,请求有没有代理

-w

[使用 curl 测试网站加载速度](##使用 curl 测试网站加载速度)

该选项在请求结束之后打印本次请求的统计数据到标准输出。

首先,我们定义控制打印行为的格式化字符串。新建文本文件 fmt.txt,并填入下面的内容:

1
2
3
4
5
6
7
8
9
\n
Response Time for: %{url_effective}\n\n
DNS Lookup Time:\t\t%{time_namelookup}s\n
Redirection Time:\t\t%{time_redirect}s\n
Connection Time:\t\t%{time_connect}s\n
App Connection Time:\t\t%{time_appconnect}s\n
Pre-transfer Time:\t\t%{time_pretransfer}s\n
Start-transfer Time:\t\t%{time_starttransfer}s\n\n
Total Time:\t\t\t%{time_total}s\n

curl 提供了很多置换变量,可以在格式化字符串中通过 %{var} 的形式使用。完整的变量列表可以在 curl 的 manpage 中查看。简单介绍一下我们使用的这几个变量:

  • url_effective: 执行完地址重定向之后的最终 URL;
  • time_namelookup: 从请求开始至完成名称解析所花的时间,单位为秒,下同;
  • time_redirect: 执行所有重定向所花的时间;
  • time_connect: 从请求开始至建立 TCP 连接所花的时间;
  • time_appconnect: 从请求开始至完成 SSL/SSH 握手所花的时间;
  • time_pretransfer: 从请求开始至服务器准备传送文件所花的时间,包含了传送协商时间;
  • time_starttransfer: 从请求开始至服务器准备传送第一个字节所花的时间;
  • time_total: 完整耗时。

然后执行请求,通过 @filename 指定保存了格式化字符串的文件:

1
$ curl -L -s -w @fmt.txt -o /dev/null http://www.google.com

输出:

1
2
3
4
5
6
7
8
9
10
Response Time for: http://www.google.co.jp/?gfe_rd=cr&dcr=0&ei=cjIaWpTkHeiQ8QfnxYzoBA

DNS Lookup Time: 0.000038s
Redirection Time: 0.207271s
Connection Time: 0.000039s
App Connection Time: 0.000039s
Pre-transfer Time: 0.000067s
Start-transfer Time: 0.260115s

Total Time: 0.467691s

type

通过type 命令可以查看命令类型:

1
2
$ type echo
echo is a shell builtin

whereis

Linux whereis命令

Linux whereis命令用于查找文件。

该指令会在特定目录中查找符合条件的文件。这些文件应属于原始代码、二进制文件,或是帮助文件。

该指令只能用于查找二进制文件、源代码文件和man手册页,一般文件的定位需使用locate命令。

语法

1
whereis [-bfmsu][-B <目录>...][-M <目录>...][-S <目录>...][文件...]

参数

-b  只查找二进制文件。

-B<目录>  只在设置的目录下查找二进制文件。

-f  不显示文件名前的路径名称。

-m  只查找说明文件。

-M<目录>  只在设置的目录下查找说明文件。

-s  只查找原始代码文件。

-S<目录>  只在设置的目录下查找原始代码文件。

-u  查找不包含指定类型的文件。

实例

使用指令”whereis”查看指令”bash”的位置,输入如下命令:

1
$ whereis bash 

上面的指令执行后,输出信息如下所示:

1
bash:/bin/bash/etc/bash.bashrc/usr/share/man/man1/bash.1.gz 

注意:以上输出信息从左至右分别为查询的程序名、bash路径、bash的man 手册页路径。

如果用户需要单独查询二进制文件或帮助文件,可使用如下命令:

1
2
$ whereis -b bash 
$ whereis -m bash

输出信息如下:

1
2
3
4
$ whereis -b bash               #显示bash 命令的二进制程序  
bash: /bin/bash /etc/bash.bashrc /usr/share/bash # bash命令的二进制程序的地址
$ whereis -m bash #显示bash 命令的帮助文件
bash: /usr/share/man/man1/bash.1.gz #bash命令的帮助文件地址

systemctl

  • 设置开机自启动 systemctl enable
  • 停止开机自启动 systemctl disable
  • 验证一下是否为开机启动 systemctl is-enabled
  • 启动服务 systemctl start xxxxx.service
  • 停止服务 systemctl stop xxxxx.service
  • 重启服务 systemctl restart xxxxx.service
  • 查看服务状态 systemctl status xxxxx.service
  • 查看所有已启动的服务 systemctl list-units --type=service

sed 流编辑器

UNIX 中的 SED 命令代表流编辑器,它可以对文件执行许多功能,如搜索、查找和替换、插入或删除。尽管 UNIX 中 SED 命令的最常见用途是用于替换或查找和替换。通过使用 SED,您甚至可以在不打开文件的情况下编辑文件,这是一种在文件中查找和替换某些内容的方法,比先在 VI 编辑器中打开该文件然后进行更改要快得多。

  • SED 是一个强大的文本流编辑器。可以进行插入、删除、搜索和替换(替换)。
  • unix 中的 SED 命令支持正则表达式,允许它执行复杂的模式匹配。

Syntax:

1
sed OPTIONS... [SCRIPT] [INPUTFILE...] 
OPTIONS
-b,--binary以二进制模式打开输入文件以考虑以换行符结束的行。
--debug切换到调试模式以规范形式打印输入并注释程序执行。
--follow-symlinks如果指定文件是符号链接,则编辑最终目标。它仅在与**-i**选项结合使用时才有效。
--help显示使用信息。
--i,--in-place [=SUFFIX]通过覆盖原始文件就地执行编辑。
--posix禁用对 POSIX 的所有扩展**sed** 以简化编写可移植脚本。
--version**sed**显示系统运行的版本。
-E, -r,--regexp-extended使用扩展的正则表达式。
-e script,--expression=script添加指定的脚本以与命令一起运行。
-f script-file添加指定脚本文件的内容以与命令一起运行。
-l N,--line-length=N为命令定义所需的换行长度**l**(默认值为 70)。
-n, --quiet,--silent禁用输出打印。
-s,--separate将指定的文件视为单独的文件,而不是作为单个连续的长流。
--sandbox禁用运行外部程序并仅在命令行上对输入文件进行操作。
-u,--unbuffered最小化输入和输出缓冲区。
-z, --null-data,--zero-terminated将输入视为一组行,每行都以零字节结尾。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# ---------------------------- 替换 ----------------------------
# 使用 sed 命令替换字符串
# 语法
sed 's/old_string/new_string/' filename.txt
# 将box 替换成bin
sed 's/box/bin/' foxinbox.txt
# 将box 全部 替换成bin
sed 's/box/bin/g' foxinbox.txt

# sed 命令替换字符串并忽略大小写
# 使用 i 指示忽略大小写
sed 's/fox/cow/i' foxinbox.txt

# 使用 sed 命令替换一行中的特定某次匹配
# 语法 “#”代表数字例如1、2、
sed 's/old_string/new_string/#' filename.txt
# 将在每行第2次出现的 box 替换成 bin
sed 's/box/bin/2' foxinbox.txt

# 使用 sed 命令替换特定行中的字符串
# 该sed命令允许您通过将行号作为前缀添加到子命令来替换特定行中的字符串:
# 语法
sed '# s/old_string/new_string/' filename.txt
# 以下命令将文本第四行 中的socks替换为sandals
sed '4 s/socks/sandals/' foxinbox.txt

# sed 命令仅替换特定行范围内的字符串
sed '#,# s/old_string/new_string/' filename.txt
# 将 4-6 行的 socks 替换成 sandals
sed '4,6 s/socks/sandals/' foxinbox.txt

# ---------------------------- 删除 ----------------------------
# 删除特定行
sed '#,#d' filename.txt
# 删除第二行
sed '2d' foxinbox.txt
# 删除 2-4行
sed '2,4d' foxinbox.txt
# 从特定行删除到最后一行
sed '#,$d' filename.txt
# 从第3行删除到末尾
sed '3,$d' foxinbox.txt

# ---------------------------- Misc ----------------------------
# 仅打印带有替换文本的行
# -n选项禁用自动打印,而命令p指示sed打印发生替换的行。
sed -n 's/old_string/new_string/p' filename.txt
# 实例
sed -n 's/box/bin/p' foxinbox.txt

linux 内核原理入土

namespace

cgroup

Shell

通过 shell 使用 uart

  1. 获取串口号 ls -lha /dev/tty* 一版串口名为 串口5 ttyS5 串口3 ttyS3 也有部分是 ttyAS3
  2. cat /dev/ttyS3 接收串口3的数据。
  3. echo helloword > /dev/ttyS3 向串口3发送数据。

通过 shell 使用 tcp

linux 设备里面有个比较特殊的文件:

/dev/[tcp|upd]/host/port 只要读取或者写入这个文件,相当于系统会尝试连接 host 这台机器,对应port端口。如果主机以及端口存在,就建立一个socket 连接。

将在,/proc/self/fd目录下面,有对应的 fd 文件序号出现。

  1. 请使用 bash zsh似乎不支持此操作

  2. cat < /dev/tcp/127.0.0.1/22

    1. 接收从127.0.0.1:22 端口发送来的数据。< 代表只读通道。
  3. exec 64<> /dev/tcp/127.0.0.1/22

    1. 使用指定的文件描述符 64 建立可读写通道<> 连接 127.0.0.1:22

    2. ls /proc/self/fd -lh 可以看到文件描述符 64 的文件

    3. 发送数据 echo hello >&64 将数据重定向输出到 &64 文件描述符

      1. 其实 2>&1 的原理和这个是一致的 文件描述符2是stderr 文件描述符1是stdout

    4. 接收数据 cat <&64 将数据重定向输入到&64文件描述符

    5. 关闭通道 exec 64>&- 使用>&-来关闭指定文件描述符

      1. exec 64<&- 也可以用来关闭

从时间服务器读取时间:

cat</dev/tcp/time.nist.gov/13

获取网页:

  • 创建tcp连接

    • exec 64<> /dev/tcp/www.baidu.com/80
  • 发送http请求头

    • echo -e "HEAD / HTTP/1.1\n\n\n\n\n">&64
  • 获取返回信息

    • cat <&64

    • 返回值示例

    • HTTP/1.1 302 Found
      Connection: keep-alive
      Content-Length: 17931
      Content-Type: text/html
      Date: Wed, 27 Dec 2023 10:13:53 GMT
      Etag: "54d9748e-460b"
      Server: bfe/1.0.8.18
              
      HTTP/1.1 400 Bad Request
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24







      ## `>>`、`>`、`<`、`2>&1`

      ```shell
      # > 和 >> 是将一条命令执行结果(标准输出,或者错误输出,本来都要打印到屏幕上面的)重定向其它输出设备(文件,打开文件操作符,或打印机等等)
      >> #追加内容(原有内容保留)
      #覆盖内容
      # < 命令默认从键盘获得的输入,改成从文件,或者其它打开文件以及设备输入
      <

      # 将产生的所有信息丢弃
      >/dev/null

      # 将错误输出 重定向到 标准输出
      2>&1
      # 0 表示stdin标准输入
      # 1 表示stdout标准输出
      # 2 表示stderr标准错误

Editor

VIM

  • 命令模式(Command mode)
  • 插入模式(Insert mode)
  • 底线命令模式(Last line mode)

指令模式

(n)=数字

i前面插入
I行首插入
a后面插入
A行尾插入
o下方新建一行
O上面新建一行
s删除字符
r替换字符
hjkl光标移动
(n)G光标移动到第n行 跳转到行
(n)+下移n行
(n)-上移n行
Ctrl+f上一页
Ctrl+b下一页
cc删除整行,并修改
dd删除整行
(n)dd删除n行
x删除光标所在字符
X删除光标前一个字符
yy复制整行
(n)yy复制n行
v选择 开始
按下 v 来选择字符。
(也可以用 V 来选择整行,Ctrl-v 来选择矩形块)
d剪切 结束
光标移动到结束剪切的位置。
按下 d 来剪切。
y复制 结束
光标移动到结束复制的位置。
按下 y 来复制。
p粘贴
u撤销
^r重做

底行模式

: 指令

x保存退出
q!不保存强制退出
(n)跳转到行:n 需要回车

/ 搜索

  • 查看下一个匹配,按下n(小写n)
  • 跳转到上一个匹配,按下N(大写N)
  • noh或者set noh 高亮

VIM Note

跳转到行

  • 指令模式 (n)G 光标移动到第n行 跳转到行
  • 底行模式 :n (跳转到文件第n行,需要回车)
  • vim +n filename (在打开文件后,跳转到文件的第n行)

替换

:[range]s/from/to/[flags]

range:搜索范围,如果没有指定范围,则作用于但前行。

1
2
3
4
:1,10s/from/to/ 表示在第1到第10行(包含第1,第10行)之间搜索替换;
:10s/from/to/ 表示只在第10行搜索替换;
:%s/from/to/ 表示在所有行中搜索替换;
:1,$s/from/to/ 同上。

flags 有如下四个选项:

1
2
3
4
c confirm,每次替换前询问;
e error, 不显示错误;
g globle,不询问,整行替换。如果不加g选项,则只替换每行的第一个匹配到的字符串;
i ignore,忽略大小写。
  1. vim 中可用 :s 命令来替换字符串,具体如下:

    • :s/str1/str2/ 替换当前行第一个 str1 为 str2
    • :s/str1/str2/g 替换当前行中所有 str1 为 str2
    • :m,ns/str1/str2/ 替换第 n 行开始到最后一行中每一行的第一个 str1 为 str2
    • :m,ns/str1/str2/g 替换第 n 行开始到最后一行中所有的 str1 为 str2
      (注:m和n 为数字,若m为 .,表示为当前行开始;若n为$,则表示到最后一行结束)
      如果使用 # 作为分隔符,则中间出现的 / 不会作为分隔符,比如:
      :s#str1/#str2/# 替换当前行第一个 str1/ 为 str2/
      :%s+/oradata/apras/+/user01/apras1+ (使用+ 来 替换 / ): /oradata/apras/替换成/user01/apras1/
  2. 其他:

  • %s/str1/str2/(等同于 :g/str1/s//str2/) 替换每一行的第一个 str1 为 str2
  • :%s/str1/str2/g(等同于 :g/str1/s//str2/g 和 :1,$ s/str1/str2/g ) 替换文中所有 str1 为 str2
    从替换命令可以看到,g 放在命令末尾,表示对搜索字符串的每次出现进行替换;不加 g,表示只对搜索

正则表达式替换

元字符
元字符说明
.匹配任意字符
[abc]匹配方括号中的任意一个字符,可用-表示字符范围。如[a-z0-9]匹配小写字母和数字
[^abc]匹配除方括号中字符之外的任意字符
\d匹配阿拉伯数字,等同于[0-9]
\D匹配阿拉伯数字之外的任意字符,等同于[^0-9]
\x匹配十六进制数字,等同于[0-9A-Fa-f]
\X匹配十六进制数字之外的任意字符,等同于[^0-9A-Fa-f]
\l匹配[a-z]
\L匹配[^a-z]
\u匹配[A-Z]
\U匹配[^A-Z]
\w匹配单词字母,等同于[0-9A-Za-z_]
\W匹配单词字母之外的任意字符,等同于[^0-9A-Za-z_]
\t匹配字符
\s匹配空白字符,等同于[\t]
\S匹配非空白字符,等同于[^\t]
需转义的普通字符
元字符说明
*匹配 * 字符
.匹配 . 字符
/匹配 / 字符
\匹配 \ 字符
[匹配 [ 字符
]匹配 ] 字符
表示数量的元字符
元字符说明
*匹配0-任意个
+匹配1-任意个
?匹配0-1个
{n,m}匹配n-m个
{n}匹配n个
{n,}匹配n-任意个
{,m}匹配0-m个
表示位置的元字符
元字符说明
$匹配行尾
^匹配行首
<匹配单词词首
>匹配单词词尾

替换变量

在正则式中以“”以及“”以及“”括起来的正则表达式,在后面使用的时候可以用“\1”、“\2”等变量来访问“”以及“”以及“”中的内容。

例子

1
2
3
4
5
6
7
8
9
删除行尾空格:                         :%s/\s+$//g
删除行首多余空格: :%s/^\s*// 或者 %s/^ *//
删除沒有內容的空行: :%s/^$// 或者 g/^$/d
删除包含有空格组成的空行 :%s/^\s*$// 或者 g/^\s*$/d
删除以空格或TAB开头到结尾的空行: :%s/^[ |\t]*$// 或者 g/^[ |\t]*$/d

把文中的所有字符串“abc……xyz”替换为“xyz……abc”可以有下列写法
:%s/abc\(.*\)xyz/xyz\1abc/g
:%s/\(abc\)\(.*\)\(xyz\)/\3\2\1/g

vim 编辑二进制

  1. vim -b binary_file -b 这个参数设定了 ‘binary’ 选项。
  2. 输入:%!xxd把文件内容以常见的字节偏移 十六进制 ASCII码的版面显示
  3. 然后输入R进入改写模式,即可按照版面格式进行编辑。
    注意:只有十六进制部分的修改才会被采用。右边ASCII文本部分的修改无效。
  4. 编辑完成以后:%!xxd -r把刚才的编辑格式转换会原始文本格式。
  5. 输入:wq保存退出。

vim 复制 剪切 粘贴

https://harttle.land/2022/03/19/vim-copy-paste.html

基本配置

1
2
3
4
# 设置 tab = 4 空格
set ts=4
# 显示行号
set nu

Nano

alt+6 复制

ctrl+u 粘贴

gedit

GCC

参数
-ogcc main.c -o main指定输出文件名
-cgcc main.c -c只编译输出.o不生成.out可执行文件
-g生成调试所需的符号信息
-O&-O2优化&更优化
-Wall显示警告
-std=-std=c99使用C99标准

Makefile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 依赖main.o input.o calcu.o生成 main ,如果依赖文件不存在就会根据规则生成相应的 *.o 文件
main: main.o input.o calcu.o
gcc -o main main.o input.o calcu.o

main.o: main.c
gcc -c main.c
input.o: input.c
gcc -c input.c
calcu.o: calcu.c
gcc -c calcu.c

clean:
rm *.o
rm main

=

1
2
3
4
5
6
7
8
name = sss
cur = $(name)
name = ppp

print:
@echo cur: $(cur)

# 这里会输出 ppp
=类似指针,值等于其真实值
:=类似赋值,等于其赋值时的值
?=如果变量没有赋值,就赋后面的值
+=类似字符串后面追加一个字符串
%代表非空字符串,可用于匹配文件名

自动化变量

自动化变量
$@规则中的目标集合,在模式规则中,如果有多个目标的话,“ $@”表示匹配模式中定义的目标集合。
$<所有依赖文件的集合, 使用空格分开, 如果在依赖文件中有多个重复的文件,“$^”会去除重复的依赖文件,值保留一份。
$^依赖文件集合中的第一个,如果依赖文件是以模式 (即“ %”)定义的,那么 “$<”就是符合模式的一系列文件集。
$?所有比目标新的依赖集合,以空格分开。
$%当目标是函数库的时候表示规则中成员名, 如果目标不是函数库文件,那么其值为空。
$+和“ $^”类似,但是当依赖文件存在重复的话不会去除重复的依赖文件。
$*这个变量表示目标模式中”%”及其之前的部分,如果目标是 test/a.test.c,目标模 ,目标模为 a.%.c,那么“ $*”就是test/a.test。
$(XX)类似替换成XX的值

伪目标

例如,目录内存在clean文件运行 make clean 则运行的是clean文件的规则,如果将Makefile文件内的clean定义为伪目标则不管如何都是执行Makefile内的指令。

1
2
3
4
5
6
7
8
9
10
11
12
objects = main.o input.o calcu.o
main: $(objects)
gcc -o main $(objects)
# 声明伪目标
.PHONY : clean

%.o : %.c
gcc -c $<

clean:
rm *.o
rm main

条件判断

  • ifeq 比较参数是否相等
  • ifneq
  • ifdef 判断变量是否为真
  • ifndef

函数

subst 字符串替换

1
2
3
4
5
6
7
$(subst<from>,<to>,<text>)
# 字符串替换
# 将text中的from替换成to,函数返回替换以后的字符串

#例
$(subst ppp,lll,my name is ppp)
# my name is lll

patsubst 模式字符串替换

1
2
3
4
5
6
$(patsubst <pattern>,<replacement>,<text>)
# 查找text单词是否符合模式pattern,符合就用replacement替换

# 例
$(patsubst %.c,%.o,a.c b.c c.c)
# “a.o b.o c.o”

dir 获取目录

1
2
3
4
5
6
$(dir <names…>)
# 此函数用来从文件名序列<names>中提取出目录部分

# 例
$(dir </src/a.c>)
# /src

notdir 去除文件中目录部分

1
2
3
4
5
6
$(notdir <names…>)
# 此函数用与从文件名序列<names>中提取出文件名非目录部分

# 例
$(notdir </src/a.c>)
# a.c

freach 循环

1
2
3
$(foreach <var>, <list>,<text>)
# foreach函数用来完成循环,用法如下
# 此函数的意思就是把参数<list>中的单词逐一取出来放到参数<var>中,然后再执行<text>所包含的表达式。每次<text>都会返回一个字符串,循环的过程中,<text>中所包含的每个字符串会以空格隔开,最后但整个循环结束时,<text>所返回的每个字符串所组成的整个字符串将会是函数foreach函数的返回值。

wildcard 函数

1
2
3
4
5
6
$(wildcard PATTERN…)
#通配符“ 通配符“ %”只能用在规则中, 只有在规则中它才会展开,如果在变量定义和函数使用时通配符不会自动展开,这个时候就要用到函数wildcard

# 例
$(wildcard *.c)
#上面的代码是用来获取当前目录下所有.c文件,类似“%”

一些包

iperf 网络流量测试

https://blog.csdn.net/bingyu9875/article/details/105700655/

官方网站:https://iperf.fr/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
Usage: iperf [-s|-c host] [options]
iperf [-h|--help] [-v|--version]

Server or Client:
-p, --port # server port to listen on/connect to
-f, --format [kmgKMG] format to report: Kbits, Mbits, KBytes, MBytes
-i, --interval # seconds between periodic bandwidth reports
-F, --file name xmit/recv the specified file
-A, --affinity n/n,m set CPU affinity
-B, --bind <host> bind to a specific interface
-V, --verbose more detailed output
-J, --json output in JSON format
-d, --debug emit debugging output
-v, --version show version information and quit
-h, --help show this message and quit
Server specific:
-s, --server run in server mode
-D, --daemon run the server as a daemon
-1, --one-off handle one client connection then exit
Client specific:
-c, --client <host> run in client mode, connecting to <host>
-u, --udp use UDP rather than TCP
-b, --bandwidth #[KMG][/#] target bandwidth in bits/sec (0 for unlimited)
(default 1 Mbit/sec for UDP, unlimited for TCP)
(optional slash and packet count for burst mode)
-t, --time # time in seconds to transmit for (default 10 secs)
-n, --bytes #[KMG] number of bytes to transmit (instead of -t)
-k, --blockcount #[KMG] number of blocks (packets) to transmit (instead of -t or -n)
-l, --len #[KMG] length of buffer to read or write
(default 128 KB for TCP, 8 KB for UDP)
-P, --parallel # number of parallel client streams to run
-R, --reverse run in reverse mode (server sends, client receives)
-w, --window #[KMG] set window size / socket buffer size
-C, --linux-congestion <algo> set TCP congestion control algorithm (Linux only)
-M, --set-mss # set TCP maximum segment size (MTU - 40 bytes)
-N, --nodelay set TCP no delay, disabling Nagle's Algorithm
-4, --version4 only use IPv4
-6, --version6 only use IPv6
-S, --tos N set the IP 'type of service'
-L, --flowlabel N set the IPv6 flow label (only supported on Linux)
-Z, --zerocopy use a 'zero copy' method of sending data
-O, --omit N omit the first n seconds
-T, --title str prefix every output line with this string
--get-server-output get results from server

[KMG] indicates options that support a K/M/G suffix for kilo-, mega-, or giga-

iperf3 homepage at: http://software.es.net/iperf/
Report bugs to: https://github.com/esnet/iperf

speedometer 网络监控工具

s-tui cpu温度使用监测

htop 进程查看器

sysbench 性能测试工具

Sysbench的测试主要包括以下几个方面:

1、磁盘io性能

2、cpu性能

3、内存分配及传输速度

4、POSIX线程性能

5、调度程序性能

6、数据库性能(OLTP基准测试).

1
2
# 4线程 测试cpu 找20000前的所有素数
sysbench --test=cpu --num-threads=4 --cpu-max-prime=20000 run

crontab 定期执行程序

https://www.runoob.com/linux/linux-comm-crontab.html

注意:新创建的 cron 任务,不会马上执行,至少要过 2 分钟后才可以,当然你可以重启 cron 来马上执行。

语法

1
crontab [ -u user ] file

1
crontab [ -u user ] { -l | -r | -e }

说明:

crontab 是用来让使用者在固定时间或固定间隔执行程序之用,换句话说,也就是类似使用者的时程表。

-u user 是指设定指定 user 的时程表,这个前提是你必须要有其权限(比如说是 root)才能够指定他人的时程表。如果不使用 -u user 的话,就是表示设定自己的时程表。

参数说明

  • -e : 执行文字编辑器来设定时程表,内定的文字编辑器是 VI,如果你想用别的文字编辑器,则请先设定 VISUAL 环境变数来指定使用那个文字编辑器(比如说 setenv VISUAL joe)
  • -r : 删除目前的时程表
  • -l : 列出目前的时程表

时间格式如下:

1
f1 f2 f3 f4 f5 program
  • 其中 f1 是表示分钟,f2 表示小时,f3 表示一个月份中的第几日,f4 表示月份,f5 表示一个星期中的第几天。program 表示要执行的程序。
  • 当 f1 为 * 时表示每分钟都要执行 program,f2 为 * 时表示每小时都要执行程序,其馀类推
  • 当 f1 为 a-b 时表示从第 a 分钟到第 b 分钟这段时间内要执行,f2 为 a-b 时表示从第 a 到第 b 小时都要执行,其馀类推
  • 当 f1 为 */n 时表示每 n 分钟个时间间隔执行一次,f2 为 */n 表示每 n 小时个时间间隔执行一次,其馀类推
  • 当 f1 为 a, b, c,… 时表示第 a, b, c,… 分钟要执行,f2 为 a, b, c,… 时表示第 a, b, c…个小时要执行,其馀类推
1
2
3
4
5
6
7
8
*    *    *    *    *
- - - - -
| | | | |
| | | | +----- 星期中星期几 (0 - 6) (星期天 为0)
| | | +---------- 月份 (1 - 12)
| | +--------------- 一个月中的第几天 (1 - 31)
| +-------------------- 小时 (0 - 23)
+------------------------- 分钟 (0 - 59)

实例

每一分钟执行一次 /bin/ls:

1
* * * * * /bin/ls

在 12 月内, 每天的早上 6 点到 12 点,每隔 3 个小时 0 分钟执行一次 /usr/bin/backup:

1
0 6-12/3 * 12 * /usr/bin/backup

周一到周五每天下午 5:00 寄一封信给 alex@domain.name

1
0 17 * * 1-5 mail -s "hi" alex@domain.name < /tmp/maildata

每月每天的午夜 0 点 20 分, 2 点 20 分, 4 点 20 分….执行 echo “haha”:

1
20 0-23/2 * * * echo "haha"

下面再看看几个具体的例子:

1
2
3
4
5
0 */2 * * * /sbin/service httpd restart  意思是每两个小时重启一次apache 

50 7 * * * /sbin/service sshd start 意思是每天7:50开启ssh服务

50 22 * * * /sbin/service sshd stop 意思是每天22:50关闭ssh服务

Note

增加开机启动项

raspberry

1
2
3
4
sudo nano /etc/rc.local
# 在打开的rc.local找到exit 0,在exit 0 之前添加即可
# 执行这段代码时是使用root用户权限的,注意当前的用户权限,以免因权限问题导致脚本执行失败。

Ubuntu

service 方式

Ubuntu 20.04的服务管理是基于systemd的,因此设置服务自启动最推荐的方法是创建一个systemd服务文件,配置好要执行的服务。

  1. 创建我们需要开机自启动的脚本,例如start.sh,其内容如下:
1
2
3
4
5
#!/bin/sh

cd /tmp
touch 11111111111.txt

  1. /etc/systemd/system目录下创建一个systemd服务文件, 命名为xxxxxx.service, 内容如下:
1
2
3
4
5
6
7
8
9
10
[Unit]
Description=frank rc Service
After=network.service nss-lookup.target

[Service]
User=frank
ExecStart=/home/hqc/test.sh

[Install]
WantedBy=multi-user.target
  • After表示服务何时启动,After=network.service 表示网络连接完成后,启动我们的服务;

  • User 表示使用哪个用户去执行,这里最好去设定特定的用户防止使用root执行

  • ExecStart表示我们的脚本(步骤1中的test.sh)的路径;注意要填绝对路径

  • WantedBy默认填default.target。

  • xxxxxx.service 内容释义

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    [Unit]:服务的说明
    Description:描述服务
    After:描述服务类别

    [Service]服务运行参数的设置
    Type=forking 是后台运行的形式
    ExecStart 为服务的具体运行命令
    ExecReload 为服务的重启命令
    ExecStop 为服务的停止命令
    PrivateTmp=True 表示给服务分配独立的临时空间
    注意:启动、重启、停止命令全部要求使用绝对路径

    [Install] 服务安装的相关设置,可设置为多用户
    WantedBy=multi-user.target
  1. 给脚本增加运行权限
1
chmod +x start.sh
  1. 重新加载系统的systemd服务文件,并启用我们自己写的xxxxxx.service文件。
1
2
3
4
5
sudo systemctl daemon-reload
# /etc/systemd/user 目录创建用这个命令
systemctl --user enable xxxxxx.service
# /etc/systemd/system 目录创建用这个命令
sudo systemctl enable xxxxxx.service

用systemd启动的服务默认是root权限,放脚本很不安全,如果只需要登录用户的权限,改成user service (systemctl –user)更好,如果有桌面环境,还可以用XDG Autostart

改成 (systemctl –user) 似乎这个用户不登陆这个脚本就没法执行了

用脚本执行多个程序,如果脚本退出了,程序也就退出了

profile.d

将写好的脚本(.sh文件)放到目录 /etc/profile.d/ 下,系统启动后就会自动执行该目录下的所有shell脚本。

Ubuntu 20.04.4 LTS service

放在这个目录里面似乎要在用户登录了之后才会启动服务

zerotier

官方定义的名词

  • PLANET 行星服务器,Zerotier 根服务器
  • MOON 卫星服务器,用户自建的私有根服务器,起到代理加速的作用
  • LEAF 叶子节点,网络客户端,就是每台连接到网络节点。

下载安装

https://www.zerotier.com/download/

查看安装zerotier版本
sudo zerotier-cli status

加入一个netWork
sudo zerotier-cli join ################(networkid)

查看加入的网络的信息,比如network
sudo zerotier-cli listnetworks

退出加入的network网段
sudo zerotier-cli leave ################(networkid)

搭建moon节点

搭建moon节点的需求

  • 需要一台公网服务器
  • 公网服务器需要加入网络

搭建步骤

  1. 生成moon模板

    1
    2
    cd /var/lib/zerotier-one
    zerotier-idtool initmoon identity.public > moon.json
  2. 修改moon配置

    1
    vi moon.json
    • 修改”stableEndpoints”为 vps 的公网的 IP,例如”stableEndpoints”: [“1.1.1.1/9993”]
  3. 生成签名文件

    1
    zerotier-idtool genmoon moon.json
    • 执行之后会生产一个000000xxxx.moon的文件,将这个文件用Winscp等工具从vps上下载下来。
  4. 将moon节点加入网络, 这一步公网服务器和其他所有的主机都需要操作

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # zerotier-one目录下操作
    # Windows:
    # C:\ProgramData\ZeroTier\One

    # Linux:
    # /var/lib/zerotier-one
    mkdir moons.d
    mv ./*.moon ./moons.d/

    # 重启服务
    service zerotier-one restart
  5. 检查是否成功连上节点

    1
    zerotier-cli listpeers
    • <role>里面有出现MOON那就是成功加入了

OpenWrt加moon节点有所不同

OpenWrt需要修改一个脚本,因为其var目录时一个内存虚拟的临时目录,重启后原有配置不会保留。通过ssh连接OpenWrt(ssh功能可在系统->管理权中开启)。

执行命令:vi /etc/init.d/zerotier,在“add_join() {”上方插入两行代码:

1
2
mkdir -p $CONFIG_PATH/moons.d
cp /home/moons.d/* $CONFIG_PATH/moons.d/

修改OpenWrt中ZeroTier的启动脚本

脚本修改完成后,在/home目录下新建一个moons.d文件夹,将000000xxxx.moon文件上传到该文件夹,在Web页面上重启ZeroTier即可。

添加sudo管理员权限

1.切换到root用户下
2.添加sudo文件的写权限,命令是:

sudo chmod u+w /etc/sudoers
3.编辑sudoers文件

sudo nano /etc/sudoers
找到这行 root ALL=(ALL) ALL,在他下面添加

xxx ALL=(ALL) ALL (这里的xxx是你的用户名)
4.撤销sudoers文件写权限,命令:

sudo chmod u-w /etc/sudoers

允许root账号登录 并修改root密码

  1. 允许root登录
1
vim /etc/ssh/sshd_config

#PermitRootLogin prohibit password 修改为 PermitRootLogin yes

  1. 修改root密码
1
2
3
synouser --setpw root password

reboot

查看端口被占用情况

1
2
3
4
5
6
# lsof is a command listing open files.
lsof -i
lsof -i:80

netstat -tunlp
netstat -tunlp|grep 80

windows远程

1
sudo apt-get install xrdp

route 路由

1
2
3
# Note:
直接可达, 用 dev 配置路由, 标识符 U
间接可达, 用 gw 配置网关路由, 标识符 UG

route 输出结果解析:

  • Destination:目标网络或目标主机
  • Gateway:网关地址或 ‘*’ (如未设置)
  • Genmask:目标网络的子网掩码;’255.255.255.255’为主机,’0.0.0.0’为缺省路由
  • Flags:路由标志
    • U (route is up) :路由正常
    • H (target is a host) :主机路由
    • G (use gateway) :使用网关的间接路由
    • R (reinstate route for dynamic routing) :为动态选路恢复路由
    • D (dynamically installed by daemon or redirect) :该路由由选路进程或重定向动态创建
    • M (modified from routing daemon or rederict) :该路由已由选路进程或重定向修改
    • ! (reject route) :阻塞路由
  • Metric:通向目标的距离(通常以跳来计算)
  • Ref:使用此路由的活动进程个数(Linux内核并不使用)
  • Use:查找此路由的次数。根据-F 和 -C的使用,此数值是路由缓存的损失数或采样数
  • Iface:使用此路由发送分组的接口(网卡名字)
  • MSS:基于此路由的TCP连接的缺省最大报文段长度
  • Window:基于此路由的TCP连接的缺省窗口长度
  • irtt:初始往返时间。内核用它来猜测最佳TCP协议参数而无须等待(可能很慢的)应答
  • HH (cached only):为缓存过的路由而访问硬件报头缓存的ARP记录和缓存路由的数量。如果缓存过路由的接口(如lo)无须硬件地址则值为-1
  • Arp (cached only):无论缓存路由所用的硬件地址情况如何都进行更新

route命令从/proc/net/route文件中取数据,设备名不变、目的地址从右到左每两位十六进制显示,标志位有1、3两种,分别是U和UG,掩码和目的地

1
2
3
4
5
6
7
8
9
10
11
12
frank@OIKIOU-PQ:~$ cat /proc/net/route
Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
eth0 00000000 011015AC 0003 0 0 0 00000000 0 0 0
docker0 000011AC 00000000 0001 0 0 0 0000FFFF 0 0 0
eth0 001015AC 00000000 0001 0 0 0 00F0FFFF 0 0 0
frank@OIKIOU-PQ:~$ route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
default OIKIOU-PQ.mshom 0.0.0.0 UG 0 0 0 eth0
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0
172.21.16.0 0.0.0.0 255.255.240.0 U 0 0 0 eth0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 删除默认路由
route del default

# linux静态路由查看
route -n

# 设置指定网段路由
route add -net 192.168.3.0 netmask 255.255.255.0 gw 192.168.6.66
# 或者
route add -net 192.168.3.0/24 gw 192.168.6.66
# 或者 添加特定接口的路由
route add -net 10.1.1.0/24 dev ztrfyiymyx

# 删除指定网段路由
route del -net 192.168.3.0 netmask 255.255.255.0

用电脑代替路由器,必须要启用电脑的IP转发功能,改/proc/sys/net/ipv4/ip_forward里的内容为1(默认为0),用下面的命令完成echo 1 > /proc/sys/net/ipv4/ip_forward
网络重启后,上面的文件自动改为0

永久修改路由:
直接执行route命令来添加路由,是不会永久保存的,当网卡重启或者机器重启之后,该路由就失效了。要想永久保存,可以保存到配置文件。linux 默认只支持一条默认路由,当重新启动网口时,会把其他默认路由去掉,只剩下一条该网口生成的默认路由。

  1. /etc/sysconfig/static-routes文件为路由固化文件,但是linux系统一般不会自动生成,需要手动创建。
  2. 在文件内编辑路由,路由格式是固定的:
    • 添加默认路由:any net 0.0.0.0 netmask 0.0.0.0 gw 10.60.60.1
    • 添加网络路由:any net 1.1.1.0 netmask 255.255.255.0 gw 10.60.60.1
1
2
3
4
5
添加到主机的路由:
any host 192.168.101.200 gw 192.168.101.1
添加到网络的路由:
any net 192.168.101.0/24 gw 192.168.101.1
any net 1.1.1.0 netmask 255.255.255.0 gw 10.60.60.1

samba 文件共享

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# 安装
sudo apt-get install samba
# 配置
sudo nano /etc/samba/smb.conf

# 在末尾加入如下内容
# 分享名称
[Pi]
# 说明信息
comment = PiStorage
# 可以访问的用户
valid users = pi,root
# 共享文件的路径,raspberry pi 会自动将连接到其上的外接存储设备挂载到/media/pi/目录下。
path = /media/pi/
# 可被其他人看到资源名称(非内容)
browseable = yes
# 可写
writable = yes
# 新建文件的权限为 664
create mask = 0664
# 新建目录的权限为 775
directory mask = 0775

# 测试配置文件是否有错误,根据提示做相应修改
testparm
# 添加登陆账户并创建密码,必须是 linux 已存在的用户
sudo smbpasswd -a pi
# 重启 samba 服务
sudo service smbd restart

sudo /etc/init.d/samba restart
sudo /etc/init.d/smbd restart
sudo /etc/init.d/nmbd restart

attention

出现过win10无法访问,

“gpedit.msc” “计算机配置”“管理模板”“网络”“Lanman工作站”“启用不安全的来宾登录”=“已启用”

挂载

在客户端Linux系统上,使用mount命令临时挂载Samba共享。基本语法如下:

sudo mount -t cifs //<server>/<share> <mount-point> -o <options>

例如,要将位于192.168.0.100/shared的Samba共享挂载到/mnt/samba目录,可以使用:

sudo mount -t cifs //192.168.0.100/shared /mnt/samba -o username=<username>,password=<password>

在Ubuntu 22.04上,您需要安装cifs-utils包来挂载SMB共享,并创建一个凭证文件以安全地存储用户名和密码:

1
2
3
4
5
6
7
8
9
10
sudo apt install cifs-utils -y
# 为了安全地存储访问 Samba 共享所需的用户名和密码 创建一个凭证文件。
sudo nano /root/.smbcredentials
# 添加以下内容
username=<username>
password=<password>

# 确保只有 root 用户可以读取
sudo chmod 600 /root/.smbcredentials

手动挂载

1
sudo mount -t cifs //server/share /mnt/samba_share -o uid=1000,gid=1000,credentials=/root/.smbcredentials,vers=3.0

其中 //server/share 是 Samba 服务器的共享路径,/mnt/samba_share 是挂载点。credentials 选项指定了凭证文件的位置,vers=3.0 指定了使用的 SMB 版本

自动挂载
/etc/fstab文件中添加挂载信息:

1
2
//server/share /mnt/samba_share cifs uid=1000,gid=1000,vers=3.0,credentials=/root/.smbcredentials
# 这里制定了用户名和用户组

测试挂载是否成功

1
sudo mount -a

NFS 网络文件系统

网络文件系统 (Network File System)

TFTP 文件传输

TFTP(Trivial File Transfer Protocol,简单文件传输协议)

固定ip

1
2
3
4
5
6
7
8
9
10
11
# ens33 是网卡名
vi /etc/sysconfig/network-scripts/ifcfg-eth0

# 将 BOOTPROTO=dhcp
# 改成
BOOTPROTO=static3
# 增加
IPADDR=192.168.2.2
NETMASK=255.255.255.0
GATEWAY=192.168.2.1
DNS1=223.5.5.5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Raspberry
sudo nano /etc/dhcpcd.conf

# 找到如下内容 对应修改即可
# Example static IP configuration:
#interface eth0
#static ip_address=192.168.0.10/24
#static ip6_address=fd51:42f8:caae:d92e::ff/64
#static routers=192.168.0.1
#static domain_name_servers=192.168.0.1 8.8.8.8 fd51:42f8:caae:d92e::1

# eg.
interface wlan0
static ip_address=192.168.31.222/24
static routers=192.168.31.254
static domain_name_servers=223.5.5.5 192.168.31.254

后台执行程序

1
2
3
4
5
6
7
8
9
# 基本形式
nohup command &
# eg.
nohup ping 1.1.1.1 &

# 重定向输出
nohup command > myout.file 2>&1 &
# eg.
nohup ping 1.1.1.1 > \myout.file 2>&1 &

开启路由转发

临时生效:

1
2
3
4
5
6
# 方法1
echo "1" > /proc/sys/net/ipv4/ip_forward
# 方法2
sudo sh -c 'echo "1" > /proc/sys/net/ipv4/ip_forward'
# 马上生效
sysctl -p

永久生效:

1
2
3
vim /etc/sysctl.conf
# 修改设置
net.ipv4.ip_forward = 1

aria2 安装

aria2

1
2
3
4
5
6
7
8
9
10
11
12
# 首先,安装:
sudo apt-get install aria2

# 创建 Aria2 的配置文件夹:
sudo mkdir /etc/aria2

# 创建 session 和配置文件:
sudo touch /etc/aria2/aria2.session
sudo touch /etc/aria2/aria2.conf

# 编辑 /etc/aria2/aria2.conf:
sudo nano /etc/aria2/aria2.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
## 文件保存相关 ##
## 文件保存相关 ##
## 文件保存相关 ##
# 文件保存目录 此处文件保存目录自行设定
dir=/mnt/usb/aria2
# 启用磁盘缓存, 0为禁用缓存, 需1.16以上版本, 默认:16M
disk-cache=32M
# 断点续传
continue=true

# 文件预分配方式, 能有效降低磁盘碎片, 默认:prealloc
# 预分配所需时间: none < falloc ? trunc < prealloc
# falloc和trunc则需要文件系统和内核支持
# NTFS建议使用falloc, EXT3/4建议trunc, MAC 下需要注释此项
#file-allocation=falloc

## 下载连接相关 ##
## 下载连接相关 ##
## 下载连接相关 ##
# 最大同时下载任务数, 运行时可修改, 默认:5
#max-concurrent-downloads=5
# 同一服务器连接数, 添加时可指定, 默认:1
max-connection-per-server=15
# 整体下载速度限制, 运行时可修改, 默认:0(不限制)
#max-overall-download-limit=0
# 单个任务下载速度限制, 默认:0(不限制)
#max-download-limit=0
# 整体上传速度限制, 运行时可修改, 默认:0(不限制)
#max-overall-upload-limit=0
# 单个任务上传速度限制, 默认:0(不限制)
#max-upload-limit=0
# 禁用IPv6, 默认:false
disable-ipv6=true

# 最小文件分片大小, 添加时可指定, 取值范围1M -1024M, 默认:20M
# 假定size=10M, 文件为20MiB 则使用两个来源下载; 文件为15MiB 则使用一个来源下载
min-split-size=10M
# 单个任务最大线程数, 添加时可指定, 默认:5
split=10

## 进度保存相关 ##
## 进度保存相关 ##
## 进度保存相关 ##
# 从会话文件中读取下载任务
input-file=/etc/aria2/aria2.session
# 在Aria2退出时保存错误的、未完成的下载任务到会话文件
save-session=/etc/aria2/aria2.session
# 定时保存会话, 0为退出时才保存, 需1.16.1以上版本, 默认:0
save-session-interval=60

## RPC相关设置 ##
## RPC相关设置 ##
## RPC相关设置 ##
# 启用RPC, 默认:false
enable-rpc=true
# 允许所有来源, 默认:false
rpc-allow-origin-all=true
# 允许外部访问, 默认:false
rpc-listen-all=true
# RPC端口, 仅当默认端口被占用时修改
# rpc-listen-port=6800
# 设置的RPC授权令牌, v1.18.4新增功能, 取代 --rpc-user 和 --rpc-passwd 选项
#rpc-secret=<TOKEN>

## BT/PT下载相关 ##
## BT/PT下载相关 ##
## BT/PT下载相关 ##
# 当下载的是一个种子(以.torrent结尾)时, 自动开始BT任务, 默认:true
#follow-torrent=true
# 客户端伪装, PT需要
peer-id-prefix=-TR2770-
user-agent=Transmission/2.77
# 强制保存会话, 即使任务已经完成, 默认:false
# 较新的版本开启后会在任务完成后依然保留.aria2文件
#force-save=false
# 继续之前的BT任务时, 无需再次校验, 默认:false
bt-seed-unverified=true
# 保存磁力链接元数据为种子文件(.torrent文件), 默认:false
bt-save-metadata=true

然后执行:

1
sudo aria2c --conf-path=/etc/aria2/aria2.conf -D

没有任何提示则表示成功。接下来添加开机自启:

1
2
sudo touch /etc/init.d/aria2c
sudo nano /etc/init.d/aria2c

添加:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#!/bin/sh
### BEGIN INIT INFO
# Provides: aria2
# Required-Start: remotefsnetwork
# Required-Stop: remotefsnetwork
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Aria2 Downloader
### END INIT INFO

case "$1" in
start)
echo -n "Starting aria2c"
sudo aria2c --conf-path=/etc/aria2/aria2.conf -D

;;
stop)
echo -n "Shutting down aria2c "
killall aria2c
;;
restart)
# killall aria2c
sudo aria2c --conf-path=/etc/aria2/aria2.conf -D

;;
esac
exit

执行:

1
sudo chmod +x /etc/init.d/aria2c

安装aria2的web管理界面(AriaNg)

这里需要用到一个第三方的工具,这个是通过rpc接口来管理aria2下载的工具。

安装git和nginx

1
sudo apt install -y git nginx

下载aira-ng

1
wget https://github.com/mayswind/AriaNg/releases/download/1.1.4/aria-ng-1.1.4.zip -O aira-ng.zip

解压

1
unzip aira-ng.zip -d aira-ng

将aira-ng放到nginx的/var/www/html/目录下,然后设置开机启动nginx

1
2
sudo mv aira-ng /var/www/html/
sudo systemctl enable nginx

用浏览器访问树莓派IP下的aira-ng,即:http://ip/aira-ng

然后在系统设置点击AriaNg设置 –> 全局 –> 设置语言为中文 –> 点击RPC–>修改为 rpc 密钥:secret

aria2 自动更新tracker

https://www.moerats.com/archives/374/

安装SSH服务端

WSL Ubuntu

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#设置root的口令(密码),用作后续登陆使用
sudo passwd root

#安装openssh-server(ubuntu自带已安装,但是我使用有问题,没找到原因)
sudo apt remove openssh-server
sudo apt install openssh-client openssh-server

#备份原始的sshd_config
# ssh_config是针对客户端的配置文件
# sshd_config是针对服务端的配置文件
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
sudo cp /etc/ssh/ssh_config /etc/ssh/ssh_config.bak

#使用vim进行编辑,按i进入insert模式
sudo vim /etc/ssh/sshd_config

在vim中找到对应项并修改,ESC,输入`wq`保存退出:
Port 2222
ListenAddress 0.0.0.0 # 如果需要指定监听的IP则去除最左侧的井号,并配置对应IP,默认即监听PC所有IP
PermitRootLogin no # 如果你需要用 root 直接登录系统则此处改为 yes
PasswordAuthentication yes # 将 no 改为 yes 表示使用帐号密码方式登录
TCPKeepAlive yes #

#启动ssh,查看status
sudo service ssh start #启动SSH服务
sudo service ssh status #检查状态
sudo systemctl enable ssh #开机自动启动ssh命令,WSL下无效

# 如果出错了可以用下面的命令查看错误信息
sshd -T

SSH主动断开连接

network error: software caused connection abort

1
2
3
4
5
6
7
8
9
10
# 
sudo vim /etc/ssh/sshd_config

# 找到TCPKeepAlive将其配置为yes 保持TCP的连接
TCPKeepAlive yes
# 将 ‘ClientAliveInterval’ 设定成 60s
# ClientAliveInterval指定了服务器端向客户端请求消息的时间间隔, 默认是0,不发送。而ClientAliveInterval 60表示每分钟发送一次,然后客户端响应,这样就保持长连接了。
ClientAliveInterval 60
# ClientAliveCountMax,使用默认值3即可。ClientAliveCountMax表示服务器发出请求后客户端没有响应的次数达到一定值,就自动断开
ClientAliveCountMax 3

SSH连接Linux时自动启动某个脚本

etc目录下有一个profile文件,在文件末尾加上脚本命令,或者脚本目录地址。(切换root用户)

1
sudo vim /etc/profile

/etc/ssh/ 目录下面创建一个 sshrc 的文件

1
#!/bin/bash

配置 SSH 密钥登录(免密码)

一、第一次登录远程主机流程

第一次ssh到远程主机时远程主机会发送它的公钥到客户端主机,客户机确认继续连接后会把远程主机的公钥保存到.ssh/known_hosts文件,下次再连接此远程主机时会去.ssh/known_hosts查看,如果是已经保存的公钥证明是信任主机,即不会告警并直接提示输入用户名密码登录。

  • 如果中途SSH提示你对方的密钥指纹发生了变化那这个时候你就要担心了, 可能存在MITM(Man-In-The-Middle-Attack 中间人攻击)
    • 远程主机的这些操作会导致密钥指纹发生变化
    • 重新安装了操作系统
    • 重新安装了openssh或者手动更新了/etc/ssh下的密钥对

虽然有著名的DH密钥交换算法,但SSH原理上不能抵御中间人攻击。然而实际上,SSH使用TOFU安全模型等同于做到了防中间人攻击。SSH的首次连接会下载服务端的公钥,用户确认后公钥将被保存并信任。下次访问时客户端将会核对服务端发来的公钥和本地保存的是否相同,不同就发出中间人攻击的警告拒绝连接,除非用户手动清除已保存的公钥。所以,如果首次连接没有中间人,之后的连接就无需担心中间人,因为中间人给出的公钥和服务端给出的公钥相同的可能性可以忽略。如果首次连接就有中间人攻击,那么恭喜你中奖了。

二、密码登录流程

远程主机收到客户端请求后会把自己的公钥发送给客户端,客户端通过公钥加密之后将密码发送给远程主机,远程主机用密钥解密,密码如果正确则登录成功。

三、公钥登录(免密登录)流程

公钥登录原理就是客户端将自己的公钥存储到远程主机的.ssh/authorized_keys中,客户端发起登录时,远程主机会发送一段随机字符串给客户端,客户端用自己的私钥加密后重新发回远程主机,远程主机用存储的客户端公钥解密之后对比之前发送给客户端的字符串,相同的话即认为客户机认证,不在需要输入密码直接登录系统。

  1. client机器生成密钥

    1
    2
    3
    4
    5
    ssh-keygen
    # 或者
    ssh-keygen -t rsa
    # 注意 RSA 现阶段不再建议使用了, 改成ed25519生成
    ssh-keygen -t ed25519 -C "your_email@example.com"

    RSA 现阶段不再建议使用了

  2. client查看~/.ssh/id_rsa.pub文件内容, 并复制

  3. server编辑SSH的配置vim /etc/ssh/sshd_config

    1. PubkeyAuthentication 配置成yes, 允许密钥登录
    2. 重启ssh服务 systemctl restart sshd
  4. server生成密钥

    1
    ssh-keygen
  5. server创建~/.ssh/authorized_keys文件, 并将client的公钥(~/.ssh/id_rsa.pub)内容粘贴进去

    • 需要注意的是.ssh文件夹的权限应当为700,authorized_keys文件的权限应该为600
    • 可以直接使用命令cat .ssh/id_rsa.pub | ssh user_name@xxx.xxx.xxx.xx 'cat >> .ssh/authorized_keys'
  6. client使用指定私钥登录

    1
    ssh -i /root/.ssh/id_rsa user@ip_or_domain
  7. 测试登录OK后建议关闭密码登录(不安全), 同时Root用户也建议禁止登录

    PasswordAuthentication no, PermitRootLogin no

SSH config

SSH 的配置文件有两个:

1
2
~/.ssh/config            # 用户配置文件
/etc/ssh/ssh_config # 系统配置文件
1
2
3
4
5
6
# comment! 
Host pq.github.com
HostName github.com # 目标服务器地址
User git # 用户名
Port 22 # 端口
IdentityFile ~/.ssh/id_rsa # 密钥->私钥

配置项说明

SSH 的配置文件有两个:

1
2
$ ~/.ssh/config            # 用户配置文件
$ /etc/ssh/ssh_config # 系统配置文件

下面来看看常用的配置参数。

Host
用于我们执行 SSH 命令的时候如何匹配到该配置。

  • *,匹配所有主机名。
  • *.example.com,匹配以 .example.com 结尾。
  • !*.dialup.example.com,*.example.com,以 ! 开头是排除的意思。
  • 192.168.0.?,匹配 192.168.0.[0-9] 的 IP。

AddKeysToAgent
是否自动将 key 加入到 ssh-agent,值可以为 no(default)/confirm/ask/yes。

如果是 yes,key 和密码都将读取文件并以加入到 agent ,就像 ssh-add。其他分别是询问、确认、不加入的意思。添加到 ssh-agent 意味着将私钥和密码交给它管理,让它来进行身份认证。

AddressFamily
指定连接的时候使用的地址族,值可以为 any(default)/inet(IPv4)/inet6(IPv6)。

BindAddress
指定连接的时候使用的本地主机地址,只在系统有多个地址的时候有用。在 UsePrivilegedPort 值为 yes 的时候无效。

ChallengeResponseAuthentication
是否响应支持的身份验证 chanllenge,yes(default)/no。

Compression
是否压缩,值可以为 no(default)/yes。

CompressionLevel
压缩等级,值可以为 1(fast)-9(slow)。6(default),相当于 gzip。

ConnectionAttempts
退出前尝试连接的次数,值必须为整数,1(default)。

ConnectTimeout
连接 SSH 服务器超时时间,单位 s,默认系统 TCP 超时时间。

ControlMaster
是否开启单一网络共享多个 session,值可以为 no(default)/yes/ask/auto。需要和 ControlPath 配合使用,当值为 yes 时,ssh 会监听该路径下的 control socket,多个 session 会去连接该 socket,它们会尽可能的复用该网络连接而不是重新建立新的。

ControlPath
指定 control socket 的路径,值可以直接指定也可以用一下参数代替:

  • %L 本地主机名的第一个组件
  • %l 本地主机名(包括域名)
  • %h 远程主机名(命令行输入)
  • %n 远程原始主机名
  • %p 远程主机端口
  • %r 远程登录用户名
  • %u 本地 ssh 正在使用的用户名
  • %i 本地 ssh 正在使用 uid
  • %C 值为 %l%h%p%r 的 hash

请最大限度的保持 ControlPath 的唯一。至少包含 %h,%p,%r(或者 %C)。

ControlPersist
结合 ControlMaster 使用,指定连接打开后后台保持的时间。值可以为 no/yes/整数,单位 s。如果为 no,最初的客户端关闭就关闭。如果 yes/0,无限期的,直到杀死或通过其它机制,如:ssh -O exit。

GatewayPorts
指定是否允许远程主机连接到本地转发端口,值可以为 no(default)/yes。默认情况,ssh 为本地回环地址绑定了端口转发器。

HostName
真实的主机名,默认值为命令行输入的值(允许 IP)。你也可以使用 %h,它将自动替换,只要替换后的地址是完整的就 ok。

IdentitiesOnly
指定 ssh 只能使用配置文件指定的 identity 和 certificate 文件或通过 ssh 命令行通过身份验证,即使 ssh-agent 或 PKCS11Provider 提供了多个 identities。值可以为 no(default)/yes。

IdentityFile
指定读取的认证文件路径,允许 DSA,ECDSA,Ed25519 或 RSA。值可以直接指定也可以用一下参数代替:

  • %d,本地用户目录 ~
  • %u,本地用户
  • %l,本地主机名
  • %h,远程主机名
  • %r,远程用户名

LocalCommand
指定在连接成功后,本地主机执行的命令(单纯的本地命令)。可使用 %d,%h,%l,%n,%p,%r,%u,%C 替换部分参数。只在 PermitLocalCommand 开启的情况下有效。

LocalForward
指定本地主机的端口通过 ssh 转发到指定远程主机。格式:LocalForward [bind_address:]post host:hostport,支持 IPv6。

PasswordAuthentication
是否使用密码进行身份验证,yes(default)/no。

PermitLocalCommand
是否允许指定 LocalCommand,值可以为 no(default)/yes。

Port
指定连接远程主机的哪个端口,22(default)。

ProxyCommand
指定连接的服务器需要执行的命令。%h,%p,%r

如:ProxyCommand /usr/bin/nc -X connect -x 192.0.2.0:8080 %h %p

User
登录用户名

查看ssh登录失败记录

1
2
3
# 查看并筛选 失败次数大于3次的 ip
sudo lastb |awk '{print $3}'|sort |uniq -c|awk '{if ($1 > 3) print $2}'
sudo lastb |awk '{print $3}'|sort |uniq -c|sort -bn|awk '{if ($1 > 3) print}'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 写一个脚本 统计一下ip 将这些ip禁止
# -------------------------------
#!/bin/bash
list=$( sudo lastb |awk '{print $3}'|sort |uniq -c|awk '{if ($1 > 3) print $2}' )
for ip in ${list}
do
# echo ${ip}
# 下面这个是加入黑名单
# echo ALL: ${ip} >> /etc/hosts.deny #加入黑名单
# 这个是加入防火墙的禁止规则
ufw deny from ${ip}
done
echo > /var/log/btmp #清空失败记录,防止脚本下次执行重复统计IP
# -------------------------------

# 定时执行 ssh密码错误没找到回调函数, 这里要是有回调函数处理起来就很及时了
> crontab -e
# 内容为每天12:12执行一次脚本
12 12 * * * /bin/bash /home/xx/xx.sh

hosts文件

1
/ets/hosts

服务器测试工具

1
wget -qO- --no-check-certificate https://raw.githubusercontent.com/oooldking/script/master/superbench.sh | bash

或者

1
curl -Lso- -no-check-certificate https://raw.githubusercontent.com/oooldking/script/master/superbench.sh | bash

搭建简易文件服务器http server wget下载

两台服务器之间传递文件,可以使用http server,参考文章:python开启http服务传输文件.
在需要提供服务的主机中运行以下命令:

1
2
3
4
5
6
7
8
# Python <= 2.3
python -c "import SimpleHTTPServer as s; s.test();" 8000

# Python >= 2.4
python -m SimpleHTTPServer 8000

# Python 3.x
python -m http.server 8000

如果目录有一个名为index.html的文件,该文件将作为初始文件。如果没有index.html,则将列出目录中的文件。

访问:

1
wget ip:8080/filename

查看支持的shell

1
cat /etc/shells

uninx 资源管理器

Glances

适合运维、云端开发人员或命令行爱好者

img

安装:

1
$ sudo pip3 install glances

启动:

1
$ sudo glances

Sysmontask

适合桌面端用户,界面仿照 Win10 资源管理器,提供更多信息更直观

img

安装:

1
$ sudo pip3 install sysmontask

启动:

1
$ sudo sysmontask

bpytop

github: https://github.com/aristocratos/bpytop

main

1
2
3
4
# 安装
git clone https://github.com/aristocratos/bpytop.git
cd bpytop
sudo make install

清理RAM Cache


Sync

操作系统在运行过程中,会把访问到的文件放到buffer中。为了避免断电,等故障造成数据丢失,我们需要把buffer中的缓存数据写入到磁盘


手动释放内存的命令

1
echo 3 > /proc/sys/vm/drop_caches

drop_caches的值可以是0-3之间的数字,代表不同的含义:

  • 0:不释放(系统默认值)
  • 1:释放页缓存
  • 2:释放dentries和inodes

设置代理

编辑文件/etc/profile,增加如下两行, 临时使用直接export即可

1
2
export http_proxy=http://proxy.com:8080/
export https_proxy=http://proxy.com:8080/

然后更新一下环境文件:

1
source /etc/profile
环境变量描述值示例
http_proxy为http变量设置代理;默认不填开头以http协议传输10.0.0.51:8080 user:pass@10.0.0.10:8080 socks4://10.0.0.51:1080 socks5://192.168.1.1:1080
https_proxy为https变量设置代理;同上
ftp_proxy为ftp变量设置代理;同上
all_proxy全部变量设置代理,设置了这个时候上面的不用设置同上
no_proxy无需代理的主机或域名; 可以使用通配符; 多个时使用“,”号分隔;.aiezu.com,10...,192.168.., *.local,localhost,127.0.0.1

脚本为WSL设置代理

WSL 中获取宿主机 IP

WSL 每次启动的时候都会有不同的 IP 地址,所以并不能直接用静态的方式来设置代理。WSL2 会把 IP 写在 /etc/resolv.conf中,因此可以用 cat /etc/resolv.conf | grep nameserver | awk '{ print $2 }' 这条指令获得宿主机 IP 。

设置代理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#!/bin/sh
hostip=$(cat /etc/resolv.conf | grep nameserver | awk '{ print $2 }')
wslip=$(hostname -I | awk '{print $1}')
http_port=<PORT>
socks5_port=<PORT>

PROXY_HTTP="http://${hostip}:${http_port}"
PROXY_SOCKS5="socks5://${hostip}:${socks5_port}"

set_proxy(){
export http_proxy="${PROXY_HTTP}"
export HTTP_PROXY="${PROXY_HTTP}"

export https_proxy="${PROXY_HTTP}"
export HTTPS_PROXY="${PROXY_HTTP}"

export all_proxy="${PROXY_SOCKS5}"
export ALL_PROXY="${PROXY_SOCKS5}"
}

unset_proxy(){
unset http_proxy
unset HTTP_PROXY
unset https_proxy
unset HTTPS_PROXY
unset all_proxy
unset ALL_PROXY
}

test_setting(){
echo "Host ip:" ${hostip}
echo "WSL ip:" ${wslip}
echo "Current https_proxy:" $https_proxy
echo "Current all_proxy:" $all_proxy
}

if [ "$1" = "set" ]
then
set_proxy

elif [ "$1" = "unset" ]
then
unset_proxy

elif [ "$1" = "test" ]
then
test_setting
else
echo "Unsupported arguments."
fi

!!注意!!

之后运行 . ./proxy.sh set 就可以自动设置代理了。unset 可以取消代理,test 可以查看代理状态,能够用来检查环境变量是否被正确修改。

运行的时候不要忘记之前的 .,或者使用 source ./proxy.sh set,只有这样才能够修改环境变量

直接运行例如 ./proxy.sh set 或者 sh proxy.sh set,这样会是运行在一个子 shell 中,对当前 shell 没有效果

另外可以在 ~/.bashrc 中选择性的加上下面两句话,记得将里面的路径修改成你放这个脚本的路径。

1
2
alias proxy="source /path/to/proxy.sh"
. /path/to/proxy.sh set

第一句话可以为这个脚本设置别名 proxy,这样在任何路径下都可以通过 proxy 命令使用这个脚本了,之后在任何路径下,都可以随时都可以通过输入proxy unset 来暂时取消代理。

第二句话就是在每次 shell 启动的时候运行该脚本实现自动设置代理,这样以后不用额外操作就默认设置好代理啦~

获取IP归属地

http://ip-[api](https://so.csdn.net/so/search?q=api&spm=1001.2101.3001.7020).com/json/ # 国际化英文显示

http://ip-api.com/json/?lang=zh-CN  # 中文显示

http://ip-api.com/json/8.8.8.8?lang=zh-CN #查询某个ip的信息

使用 curl 测试网站加载速度

参考Curl章节-w参数

rsync 同步工具

Full system backup

rsync 用法教程_阮一峰

备份远程主机 192.168.1.1/目录, 到本地./xx_backup/ , 并排除一些文件, 生成日志

1
2
3
4
rsync -a -e "ssh -p 22" --exclude={"/dev/*","/proc/*","/sys/*","/tmp/*","/run/*","/mnt/*","/media/*","/lost+found"} user@192.168.1.1:/ ./xx_backup | tee ./xx_backup.log
# "ssh -p 22" 22 = port = 端口号
# user@192.168.1.1 user = user = 用户名
# 192.168.1.1 = ip

-r 参数

本机使用 rsync 命令时,可以作为cpmv命令的替代方法,将源目录同步到目标目录。

1
$ rsync -r source destination

上面命令中,-r表示递归,即包含子目录。注意,-r是必须的,否则 rsync 运行不会成功。source目录表示源目录,destination表示目标目录。

如果有多个文件或目录需要同步,可以写成下面这样。

1
$ rsync -r source1 source2 destination

上面命令中,source1source2都会被同步到destination目录。

-a 参数

-a参数可以替代-r,除了可以递归同步以外,还可以同步元信息(比如修改时间、权限等)。由于 rsync 默认使用文件大小和修改时间决定文件是否需要更新,所以-a-r更有用。下面的用法才是常见的写法。

1
$ rsync -a source destination

目标目录destination如果不存在,rsync 会自动创建。执行上面的命令后,源目录source被完整地复制到了目标目录destination下面,即形成了destination/source的目录结构。

如果只想同步源目录source里面的内容到目标目录destination,则需要在源目录后面加上斜杠。

1
$ rsync -a source/ destination

上面命令执行后,source目录里面的内容,就都被复制到了destination目录里面,并不会在destination下面创建一个source子目录。

-n 参数

对比两个目录下文件,想知道目标目录下哪些文件被修改或增加删除了,rsync提供了一个只校验文件但不实际同步目录内容的参数 --dry-run-n.

如果不确定 rsync 执行后会产生什么结果,可以先用-n--dry-run参数模拟执行的结果。

1
$ rsync -anv source/ destination

上面命令中,-n参数模拟命令执行的结果,并不真的执行命令。-v参数则是将结果输出到终端,这样就可以看到哪些内容会被同步。

--delete 参数

默认情况下,rsync 只确保源目录的所有内容(明确排除的文件除外)都复制到目标目录。它不会使两个目录保持相同,并且不会删除文件。如果要使得目标目录成为源目录的镜像副本,则必须使用--delete参数,这将删除只存在于目标目录、不存在于源目录的文件。

1
$ rsync -av --delete source/ destination

上面命令中,--delete参数会使得destination成为source的一个镜像。

ufw ubuntu防火墙

UFW 只是 iptables 的前端,因此这些日志条目实际上来自 iptables。

第 1 行:Feb 6 16:27:08 jonasgroenbek kernel: [71910.873115]

日期和时间、您的计算机名称和自引导以来的内核时间。

第 2 行:[UFW BLOCK] IN=eth0 OUT=

每当 iptables 执行日志条目时,都会有一个可选的--log-prefix,在这种情况下[UFW BLOCK]。UFW 最烦人的一点是,它对每种类型的日志条目都使用相同的前缀,因此很难关联回 iptables 规则集。IN是数据包到达的网络接口名称。是空白的OUT,因为数据包没有被重新传输,如果这是一个路由器应用程序可能就是这种情况。

第 3 行:MAC=a6:8d:e2:51:62:4c:f0:4b:3a:4f:80:30:08:00

这些是本地目标 (a6:8d:e2:51:62:4c (eth0)) 和源 (f0:4b:3a:4f:80:30) 网络接口卡的机器地址代码。在您的情况下,源可能是您的 ISP 网关 NIC 的 MAC。每个 6 个字节。末尾额外的 2 个字节(08:00)是帧类型,在这种情况下,它表示“以太网帧携带 IPv4 数据报”。

第 4 行:SRC=77.72.85.26 DST=157.230.26.180

这些是数据包来自哪里的IP地址,SRC,它应该去哪里,DST,应该是你的IP地址。

第 5 行:LEN=40 TOS=0x00 PREC=0x00 TTL=251 ID=62215 PROTO=TCP

原始数据包的有效载荷部分的长度;服务类型、存在时间、生存时间(在数据包因跳数过多而死亡之前还剩下多少跳);鉴别; 协议(在本例中为 TCP)。

第 6 行:SPT=42772 DPT=3194 WINDOW=1024

源端口;探测端口;TCP 窗口大小

第 7 行:RES=0x00 SYN URGP=0

TCP 标志,这里重要的是“SYN”,意思是它试图建立一个新的连接。此日志条目表示尝试已被阻止。

linux >和>>的区别,<号使用

>:将一条命令执行结果(标准输出,或者错误输出,本来都要打印到屏幕上面的)重定向其它输出设备(文件,打开文件操作符,或打印机等等)

  • >>:追加内容(原有内容保留)

  • >:覆盖内容

<:命令默认从键盘获得的输入,改成从文件,或者其它打开文件以及设备输入

访问samba

Linux用户可以从命令行访问samba共享,使用文件管理器或挂载samba共享。

smbclient是一个允许您从命令行访问Samba共享资源的工具。大绝大部分的Linux发行版中,smbclient软件包并不是预先安装的,所以需要在您的发行版软件包管理器中安装它。

1
sudo apt install smbclient

访问Samba共享资源

1
smbclient //samba_hostname_or_server_ip/share_name -U username

看到这个提示符就表示成功登录了

1
2
Try "help" to get a list of possible commands.
smb: \>

还有一种用的比较多的方法就是直接将Samba文件夹挂载到系统文件夹下.

挂载

我们需要先安装包cifs-utils

1
sudo apt install cifs-utils

创建挂载点:

1
sudo mkdir /mnt/smbmount

挂载远程共享目录到本地目录/mnt/smbmount

1
sudo mount -t cifs -o username=my_username //samba_hostname_or_server_ip/sharePath /mnt/smbmount

把远程服务器192.168.20.245上的共享目录share,用户名为frank,挂载到本地目录/mnt/smbmount上:

1
sudo mount -t cifs -o username=frank //192.168.20.245/share /mnt/smbmount

系统将提示需要输入密码验证:

1
Password for frank@//192.168.20.245/share:  ********

查看挂载情况 可以看到已经成功挂载了

1
df -h

Note:如果提示文件系统错误, 或者远程文件只读错误可以看看是不是没安装cifs-utils

开机挂载

先卸载刚刚挂载的目录:

1
umount /mnt/smbmount

我们要实现开机自动挂载,需要修改配置文件/etc/fstab,假设服务器IP地址为192.168.20.245,共享目录名为share,本地目录为/mnt/smbmount,用户名为frank,密码为123,在配置文件的最后一行添加以下内容:

1
//192.168.20.245/share /mnt/smbmount  cifs  username=frank,password=123,soft,rw  0 0

测试挂载:

1
mount -a

验证:看看挂载情况:

1
df -h

接下来查看文件:

1
ll /mnt/smbmount

查看文件占用

ADD ME

1
2
3
4
5
6
7
8
9
sudo apt install ncdu

ncdu
# 排除/mnt
ncdu --exclude /mnt



du -h -d 1

修改语言

CentOS 更改系统语言

使用 localectl list-locales 查看已有语言环境。例如切换简中只需运行下面命令,重启系统生效。

1
localectl set-locale LANG=zh_CN.UTF-8

也可以手动修改语言配置文件 /etc/locale.conf 设置,效果是一样的。

某些场景可能只要临时切换语言,仅对当前登录会话生效,这时可用 LANG=zh_CN.UTF-8 命令设置。

Ubuntu 更改系统语言

先用 locale -a 查看系统语言环境。按下面命令格式更改语言,注销重新登录生效。

1
update-locale LANG=zh_CN.UTF-8

如果系统没有所需语言,先使用下面命令添加,以添加简中语言为例。

1
locale-gen zh_CN.UTF-8 && update-locale

Debian 更改系统语言

用要添加语言的国家地区代码,相应修改如下命令运行,以简中为例。

1
export LANG=zh_CN.UTF-8

再执行 dpkg-reconfigure locales 命令重新配置语言,用空格键选择,之后重启系统生效。

Docker 内 ubuntu

1
2
3
4
5
6
apt-get install language-pack-zh-hans
locale-gen zh_CN.UTF-8
locale -a
echo "export LC_ALL=zh_CN.UTF-8">> /etc/profile
source /etc/profile
locale

date日期时间和Unix时间戳互转

将日期转换为Unix时间戳

将当前时间以Unix时间戳表示:

1
date +%s

输出如下:

1
1361542433

转换指定日期为Unix时间戳:

1
date -d '2013-2-22 22:14' +%s

输出如下:

1
1361542440

将Unix时间戳转换为日期时间

不指定日期时间的格式:

1
date -d @1361542596

输出如下:

1
Fri Feb 22 22:16:36 CST 2013

指定日期格式的转换:

1
date -d @1361542596 +"%Y-%m-%d %H:%M:%S"

输出如下:

1
2013-02-22 22:16:36

固定IP

1
2
3
4
# 临时 固定ip 重启后失效
ifconfig eth0 192.168.2.20 netmask 255.255.255.0 up
# 添加 路由表
route add gw 192.168.2.254

Swap 分区大小调整

vps磁盘空间比较小,var/swapfile占用空间比较大,调整swap的大小,减小这个文件占用的空间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
检查 swap 大小
free -m
关闭swap
swapoff -a
1.创建交换分区的文件:增加2G大小的交换分区
dd if=/dev/zero of=/var/swapfile bs=1M count=2048
2.设置交换文件
mkswap /var/swapfile
3.启用交换分区文件
swapon /var/swapfile
4.在/etc/fstab添加
echo '/var/swapfile swap swap defaults 0 0'>>/etc/fstab
5.检查
free -m

CPU调频

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 查看当前CPU使用什么 驱动
cpufreq-info
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_driver

# 常见的有 intel_cpufreq acpu_freq

analyzing CPU 0:
driver: intel_cpufreq

# 查看可以使用的模式
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors

# 查看当前运行的模式
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor

模式介绍
Performance性能模式 保持以最大频率运行
powersave只会保持最低频率,节能省电
userspace自定义频率
ondemand一有cpu计算量的任务,就会立即达到最大频率运行,等执行完毕就立即回到最低频率
conservative根据负载状态自动在频率上下限调整 对比于ondemand 他的调整更滞后,更加柔和
Schedutil
参考https://www.kernel.org/doc/Documentation/cpu-freq/governors.txt

CPU Driver的修改

修改 /etc/default/grub 可以修改Driver的类型

1
2
3
4
5
6
7
8
9
10
11
vi /etc/default/grub

# 找到quiet那个位置,后面加空格,再加 intel_pstate=disable ,就可以改成 acpu_freq 类型
GRUB_CMDLINE_LINUX_DEFAULT="quiet"
->
GRUB_CMDLINE_LINUX_DEFAULT="quiet intel_pstate=disable"

# 更新
update-grub
# reboot 生效
reboot

intel_cpufreq TYPE

在这个模式下可以通过修改/etc/default/cpufrequtils文件来修改cpu运行模式和最大最小频率

1
vi /etc/default/cpufrequtils

acpu_freq TYPE

在这个模式下可以通过修改/etc/init.d/cpufrequtils文件来修改cpu运行模式和最大最小频率

1
2
3
4
5
vi /etc/init.d/cpufrequtils

# 重启服务
systemctl daemon-reload
/etc/init.d/cpufrequtils restart

wget 代理

方法一、在环境变量中设置代理

1
export http_proxy=http://127.0.0.1:8087

方法二、使用配置文件

为wget使用代理,可以直接修改/etc/wgetrc,也可以在主文件夹下新建.wgetrc,并编辑相应内容,本文采用后者。

将/etc/wgetrc中与proxy有关的几行复制到~/.wgetrc,并做如下修改:

1
2
3
4
5
6
7
8
#You can set the default proxies for Wget to use for http, https, and ftp.
# They will override the value in the environment.
https_proxy = http://127.0.0.1:8087/
http_proxy = http://127.0.0.1:8087/
ftp_proxy = http://127.0.0.1:8087/

# If you do not want to use proxy at all, set this to off.
use_proxy = on

这里 use_proxy = on 开启了代理,如果不想使用代理,每次都修改此文件未免麻烦,我们可以在命令中使用-Y参数来临时设置:

1
-Y, --proxy=on/off           打开或关闭代理

方法三、使用-e参数

wget本身没有专门设置代理的命令行参数,但是有一个”-e”参数,可以在命令行上指定一个原本出现在”.wgetrc”中的设置。于是可以变相在命令行上指定代理:

1
-e, --execute=COMMAND   执行`.wgetrc'格式的命令

例如:

1
wget -c -r -np -k -L -p -e "http_proxy=http://127.0.0.1:8087" http://www.subversion.org.cn/svnbook/1.4/

这种方式对于使用一个临时代理尤为方便。

sudo 复杂语句

使用管道执行语句

1
2
echo "echo 12000 > /dev/null" | sudo sh

串口终端 显示不全 stty设置终端宽度

1
2
3
4
5
6
7
8
# 使用stty size可以查看行和列数
stty size

# 使用stty设置列宽
stty cols 200

# 设置 行数
stty columns 80

参考 tty 手册

pigz 多线程压缩解压缩

Pigz 的功能与 gzip 的功能相同,但在压缩时将工作分散到多个处理器和内核上。

1
pigz -p 16 --fast

linux 备份

dd 指令备份

用 dd 指令全卡备份 有数据无数据的位置都会备份

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 查看块设备
sudo lsblk

# 查看disk
sudo fdisk -l

# 将文件备份
# status=progress 是显示进度条
sudo dd if=/dev/sd<x> status=progress | gzip>./sd_card_backup.gz
# 调用多核压缩
sudo dd if=/dev/sd<x> status=progress | pigz -p 16 --fast >./sd_card_backup.gz


# linux 下还原
sudo gzip -dc ./sd_card_backup.gz | sudo dd of=/dev/sd<x> bs=1M status=progress

在找资料的途中发现,野火的linux教程里面有一个骚操作。

通过df -h 计算出来 boot 分区和 rootfs两个分区占用的大小。

在使用dd指令的时候仅复制特定大小的区块。

sudo dd if=/dev/sdc of=./imx6ull_backup.img count=1024 bs=1M conv=sync,比如这里就是复制1G大小。

文件系统可能会把文件存在存储设备块的后面地址吗?如果会这种方式岂不是会丢文件?

备份文件系统

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
cd /
#tar.gz格式
tar cvpzf system_backup.tar.gz / --exclude=/proc --exclude=/lost+found --exclude=/system_backup.tar.gz --exclude=/mnt --exclude=/sys

#tar.bz2格式
tar cvpjf system_backup.tar.bz2 / --exclude=/proc --exclude=/lost+found --exclude=/system_backup.tar.bz2 --exclude=/mnt --exclude=/sys


# 恢复系统
cd /
#上传文件到根目录下
tar xvpfz system_backup.tar.gz -C /

tar xvpfj system_backup.tar.bz2 -C /

#创建备份时排除的目录
mkdir proc
mkdir lost+found
mkdir mnt
mkdir sys

bash 显示 git 分支名

~/.bashrc文件末尾添加如下代码

1
2
3
4
5
6
7
8
9
10
function git_branch {
branch="`git branch 2>/dev/null | grep "^\*" | sed -e "s/^\*\ //"`"
if [ "${branch}" != "" ];then
if [ "${branch}" = "(no branch)" ];then
branch="(`git rev-parse --short HEAD`...)"
fi
echo " ($branch)"
fi
}
export PS1='\u@\h \[\033[01;36m\]\W\[\033[01;32m\]$(git_branch)\[\033[00m\] \$ '

SCP 文件传输

目录加-r参数即可

1
2
3
4
5
6
7
8
# 从服务器上下载文件
scp username@servername:/path/filename /path/filename

# 上传本地文件到服务器
scp /path/filename username@servername:/path/filename

# 下载整个目录
scp -r username@servername:/path/ /path

系统信息查看

  1. uname - 显示内核信息:
    • uname -a:显示所有信息,包括内核版本、主机名、处理器类型等。
  2. lsb_release - 显示Linux标准基础(LSB)版本信息:
    • lsb_release -a:显示LSB和发行版信息。
  3. hostnamectl - 显示系统主机名和系统信息:
    • hostnamectl:显示当前的主机名、操作系统名称、内核版本等。
  4. cat /etc/release - 显示发行版信息:
    • cat /etc/release:显示类似于lsb_release的信息,但直接从文件中读取。
  5. df - 显示磁盘空间使用情况:
    • df -h:以人类可读的格式显示磁盘空间。
  6. free - 显示内存使用情况:
    • free -m:以MB为单位显示内存使用情况。
  7. tophtop - 实时显示系统进程和资源使用情况。
  8. vmstat - 显示虚拟内存统计信息。
  9. iostat - 显示CPU和输入/输出统计信息。
  10. dmesg - 显示或控制内核环形缓冲区。
  11. ifconfigip addr - 显示网络接口配置。
  12. lscpu - 显示CPU信息。
  13. lsblk - 列出所有可用的块设备。
  14. lspci - 列出所有PCI设备,网卡、硬盘、显示器…。
  15. lsusb - 列出所有USB设备。
  16. lsmod - 显示已加载的内核模块。
  17. uptime - 查询平均负载

sysbench

sysbench 是一款开源的多用途基准测试实用程序,它可以评估包括 CPU、内存、I/O 和数据库(如 MySQL)在内的多个系统组件的性能。

1
2
3
# 对cpu进行测试 使用8个线程 测试时间60s 
sysbench cpu --threads=8 --time=60 run

RaspberryPI

密码

树莓派OS 默认

pi
raspberry

注意!!

新版树莓派的镜像将没有默认密码

参考

我们只需要将存储卡插入到PC在boot盘下新建文件userconf或者userconf.txt

文件内容是username:encrypted-password

encrypted-password是通过这个命令运算来的

1
echo 'mypassword' | openssl passwd -6 -stdin

用户名是pi密码是raspberry 那么文件内容形如下面这样

1
pi:$6$LXbLeu63.T9FIeWq$rdm2RMzZQLjs1nDI7wiPEx8UKrVWpcEuhSvjFTR4smGXqO9bMow5Imkdgzk.PKdxf.sjxy.dKYDIXneJ0INst/

初始化

WiFi 网络配置

用户可以在未启动树莓派的状态下单独修改 /boot/wpa_supplicant.conf 文件配置 WiFi 的 SSID 和密码,这样树莓派启动后会自行读取 wpa_supplicant.conf 配置文件连接 WiFi 设备。

操作方法简单:将刷好 Raspbian 系统的 SD 卡用电脑读取。在 boot 分区,也就是树莓派的 /boot 目录下新建 wpa_supplicant.conf 文件,按照下面的参考格式填入内容并保存 wpa_supplicant.conf 文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
country=CN
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1

network={
ssid="WiFi-A" #ssid:网络的ssid
psk="12345678" #psk:密码
key_mgmt=WPA-PSK
priority=1 #priority:连接优先级,数字越大优先级越高(不可以是负数)
}

# 隐藏WiFi
network={
ssid="WiFi-B"
psk="12345678"
key_mgmt=WPA-PSK
priority=2
scan_ssid=1 #scan_ssid:连接隐藏WiFi时需要指定该值为1
}

# WiFi 没有密码
network={
ssid="你的无线网络名称(ssid)"
key_mgmt=NONE
}

# 如果你的 WiFi 使用WEP加密
network={
ssid="你的无线网络名称(ssid)"
key_mgmt=NONE
wep_key0="你的wifi密码"
}

开启 SSH 服务

  • 在boot盘下新建ssh文件即可开启ssh

其他配置

1
2
# 树莓派相关配置
sudo raspi-config

开关机

安全关机:

1
2
3
4
sudo shutdown -h now
sudo halt
sudo poweroff
sudo init 0

安全重启:

1
2
sudo reboot
shutdown -r now

GPIO

GPIO1

image-20210801204738591

RaspberryPI Note

wiringPi GPIO库

1
2
3
4
5
6
7
8
9
10
cd /tmp
wget https://project-downloads.drogon.net/wiringpi-latest.deb
sudo dpkg -i wiringpi-latest.deb

# 查看GPIO编码
gpio readall

# 树莓派4b 需要版本大于2.52
gpio -v

shell操作

创建

进入/sys/class/gpio/目录并查看文件

1
2
cd /sys/class/gpio/
ls

img

目录export为创建,unexport为删除

将gpio18重定向用户定义设备,生成gpio18目录

1
sudo echo 18 > export

img

进入gpio18目录并查看文件

img

direction设置引脚方向,输入还是输出

value设置引脚状态,高电平还是低电平

输入状态

设置引脚状态为输入状态

1
sudo echo in > direction

img

查看引脚高低电平

1
cat value 

输出状态

设置引脚状态为输出状态

1
sudo echo out > direction

img

设置输出高电平

1
sudo echo 1 > value

设置输出低电平

1
sudo echo 0 > value

删除

测试完毕之后返回/sys/class/gpio/目录,并将gpio注销

1
2
cd /sys/class/gpio/
sudo echo 18 > /sys/class/gpio/unexport

增加开机启动项

1
2
3
4
sudo nano /etc/rc.local
# 在打开的rc.local找到exit 0,在exit 0 之前添加即可
# 执行这段代码时是使用root用户权限的,注意当前的用户权限,以免因权限问题导致脚本执行失败。

树莓派自动挂载U盘

1
2
3
# 打开文件 添加以下 这个带有超时,可以避免拔掉U盘开不了机
sudo nano /etc/fstab
# /dev/sda1 /mnt/usb auto defaults,nofail,x-systemd.device-timeout=1,noatime 0 0

查看温度

使用watch命令每秒打印一次cpu温度信息

1
watch -n 1 cat /sys/class/thermal/thermal_zone0/temp

由于 Raspberry Pi 系列上使用的 SoC 的架构,以及在 Raspberry Pi OS 发行版中使用上游温度监控代码,基于 Linux 的温度测量可能不准确。但是,该vcgencmd命令在直接与 GPU 通信时提供了当前 SoC 温度的准确和即时读数:

1
vcgencmd measure_temp

远程桌面

1
sudo apt-get install xrdp

固定IP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
sudo nano /etc/dhcpcd.conf

# 找到如下内容 对应修改即可
# Example static IP configuration:
#interface eth0
#static ip_address=192.168.0.10/24
#static ip6_address=fd51:42f8:caae:d92e::ff/64
#static routers=192.168.0.1
#static domain_name_servers=192.168.0.1 8.8.8.8 fd51:42f8:caae:d92e::1

# eg.
interface wlan0
static ip_address=192.168.31.222/24
static routers=192.168.31.254
static domain_name_servers=223.5.5.5 192.168.31.254

I2C相关

修改I2C总线速度

启用I2C接口

sudo raspi-config

命令将启动raspi-config实用程序。选择“Interfacing Options”:

将光标移动到“P5 I2C”,选中,然后“select”。

编辑Config.txt文件设置I2C总线速度

sudo nano /boot/config.txt

查找包含“dtparam=i2c_arm=on”的行,添加“i2c_arm_baudrate=400000”,其中400000是新设置的速度(400kbit /s),注意i2c前面的逗号。完整代码如下:

dtparam=i2c_arm=on,i2c_arm_baudrate=400000

这样可以启用I2C总线的同时,也完成了新波特率的设置。编辑完成后,使用CTRL-X,然后选择Y,保存文件并退出,并重新启动

1
2
3
4
Get-AppxPackage *WindowsStore* | Select Name, PackageFullName

https://aka.ms/Microsoft.VCLibs.x64.14.00.Desktop.appx
https://aka.ms/Microsoft.VCLibs.x86.14.00.Desktop.appx

Linux 杂乱学习笔记
https://www.oikiou.top/2020/d4436089/
作者
Oikiou
发布于
2020年10月29日
许可协议