本文包含我在日常使用Ubuntu系统中遇到的一些问题的记录, 没有什么特定的顺序和联系, 不定期更新.
系统初始化与环境配置
安装node
使用官方网站推荐的方式安装. 该页面会自动识别操作系统类型并推荐合适的安装方式.
如果无法直接下载安装脚本, 可手动打开该页面并保证到本地. 安装过程可能依赖Github的数据, 需要先确保Git的拉取能力正常.
使用该方式会自动配置环境变量, 并且可以方便的切换node版本.
安装OneDrive客户端
对于Ubuntu系统,可以安装OneDrive客户端实现Ubuntu与Windows的文件同步. 安装过程执行如下的代码
1 | # 安装OneDrive客户端需要的依赖 |
安装完成后执行onedrive开启程序进行第一次配置,此时会输出一个onedrive的登陆URL,通过该URL登陆即可对客户端授权登陆.
之后会自动开始同步操作,第一次同步操作结束后会自动退出. 一定要等待程序同步完所有文件后再开始后续的配置.
使用如下的指令配置开机自启动
1 | systemctl --user enable onedrive |
之后可以使用如下的指令查看运行日志
1 | journalctl --user-unit onedrive -f |
设置时区
1 | sudo timedatectl set-timezone Asia/Shanghai |
linux基础认知
Linux系统目录结构
常用指令介绍
ll各列的含义
1 | drwxrwxr-x 9 lizec lizec 4.0K 4月 7 10:10 ./ |
第一列表示文件权限,可以分为四个部分,其中第一部分包含一个字母,之后的三个部分每个部分包含3个字母. 第一个字母表示文件的类型,d表示文件夹,-表示普通文件. 后续的三个部分分别表示此文件的用户,同组的用户以及其他用于对该文件的权限.
第二列表示链接数量. 对于文件夹表示其中的一级子目录的数量,对于文件表示链接的数量.
后续几列分别表示文件的所有者,所有者所在的组,文件的大小,修改时间以及相应的文件名.
lost+found目录
lost+found 是 Linux/Unix 文件系统中的特殊目录,由系统在创建文件系统时自动生成(如使用 mkfs 命令). 它的核心作用是充当文件系统的 “失物招领处” ——当文件系统因意外崩溃、断电或不洁卸载导致损坏时,修复工具 fsck 会扫描磁盘. 若发现未被任何文件引用的孤立数据块,便会将这些零散数据恢复为文件并存入 lost+found. 目录通常位于文件系统根目录下(如 /lost+found 或 /mnt/disk/lost+found),权限严格限制(仅 root 可访问).
关键特性:
- 健康状态为空:目录内容为空是正常的,表明文件系统近期无需修复.
- 内容不可直接识别:内部文件以数字编号命名(如
#12345),需通过file、strings等命令分析内容,可能是碎片、完整文件或垃圾数据. - 绝对不可删除:即使为空,它也是文件系统的关键基础设施. 删除会导致
fsck无法在修复时恢复数据,削弱系统自我修复能力. - 存在即合理:若目录中出现文件,说明对应分区经历过修复,需管理员谨慎检查内容;若为空,则无需任何操作,忽略即可.
总结:lost+found 是文件系统为应对意外损坏而预留的安全恢复机制,其存在本身即是保护措施. 用户应避免操作此目录,将其视为系统的重要底层设施而非普通文件夹.
系统更新与包管理
APT更换国内镜像源
1 | cp -a /etc/apt/sources.list /etc/apt/sources.list.bak |
清理apt缓存
使用apt安装软件后, 相应的安装包会缓存在/var/cache/apt/archives/, 可以使用以下的指令查看这部分缓存占用的空间.
1 | sudo du -sh /var/cache/apt/archives/ |
如果已经占用较大的空间, 可以使用以下指令自动清理缓存:
1 | sudo apt clean |
查看已安装软件位置
1 | dpkg -L <软件名> |
Ubuntu管理多版本软件
Ubuntu可以直接使用apt安装多个版本的Java, 多个版本的Java并不会直接产生冲突.
使用如下的指令, 可以切换java指令的版本
1 | sudo update-alternatives --config java |
输入上述指令后, 会显示类似如下的内容
1 | There are 3 choices for the alternative java (providing /usr/bin/java). |
输入相应的编号就可以切换java的默认版本. 同理还可以切换javac, javadoc等命令的版本.
除了Java和Python等软件外,还可以自己添加管理项目, 可参考update-alternatives使用详解
snap包管理器
snap是Ubuntu系统自带的一个包管理器, 可以代替apt安装更多应用. 由于snap的包由开发者直接控制, 因此通常版本更新. 使用snap find可以查找需要的包. snap 有三种级别:
| confinement | 沙箱隔离 | 系统权限 | 安装要求 | 典型用途 |
|---|---|---|---|---|
strict(默认) |
✅ 强隔离 | 最小权限,仅通过接口显式授权 | 无需额外参数 | 普通应用(浏览器、办公、工具) |
classic |
❌ 无沙箱 | 全系统访问(同传统 deb) | 必须加 --classic 才能安装 |
IDE、编译器、系统工具、开发环境 |
devmode |
半隔离 | 宽松权限 + 日志审计 | 开发调试用 | 开发者打包测试 |
对于classic类型的应用, 必须使用--classic参数安装.
由于是闭源的, 还会挂载一堆磁盘镜像, 很多人并不喜欢这个包管理器. 但如果图省事, 那还是比手动安装要快速.
存储管理
磁盘操作
Ubuntu挂载U盘
- 使用
sudo fdisk -l命令查看U盘的位置
1 | # 结果可能包含如下字段 |
- 挂载U盘到指定节点
1 | # 挂载FAT32格式的U盘 |
- 卸载u盘
1 | # 卸载之前挂载的U盘 |
ubuntu开机自动挂载新硬盘
操作需要Root权限
- 查看分区的UUID
1 | sudo blkid |
- 配置开机加载
打开/etc/fstab, 按照如下格式写入配置
1 | UUID=66E85884E8585501 /home/lizec/share/C ntfs defaults 0 1 |
以上配置前三项分别是分区ID, 挂载点, 分区格式. 其余的配置可以使用默认值.
- 验证配置
执行以下指令检查配置是否正确, 不正确的配置将导致系统无法正常启动
1 | sudo mount -a |
确认无误后重启系统即可使配置生效
注意: 如果以后挂载信息发生变动, 一定要删除相关的配置, 否则将因为挂载失败导致系统无法启动
清理系统硬盘空间
Linux服务器在长期使用后, 会逐渐产生一些缓存文件和日志文件, 这些文件如果未进行清理, 将逐步消耗磁盘空间, 导致服务器可用空间减少.
排查思路
直接使用以下指令查看文件夹内空间占用情况的概述, 可以找到占用空间较大的目录, 进入该目录后重复执行上述指令, 定位最终消耗空间较大的目录
1 | du -ah --max-depth=1 |
查看当前目录总共占的容量, 而不单独列出各子项占用的容量
1 | du -sh |
查看当前目录下一级子文件和子目录占用的磁盘容量
1 | du -lh --max-depth=1 |
清理系统日志
在Ubuntu系统的/var/log/journal存储了二进制格式的内核日志, 系统服务日志和应用程序日志等内容, 并且这些日志在默认情况下并不会自动删除, 长期使用的服务器可能在这里积累数GB的日志文件.
通常不建议直接删除这些日志, 可执行如下指令, 保留最新的2个日志文件
1 | sudo journalctl --vacuum-files=2 |
清除/dev/loop设备
这些设备来自snap系统, 可以使用如下的指令清理未使用的设备
1 | sudo apt-get purge snapd |
Ubuntu server扩展lvm空间
网络配置与服务
配置代理服务
对于部分常用软件, 可以通过配置代理的方式加速
Ubuntu全局代理
在桌面版的Ubuntu系统中, 可以在网络选项下找到代理配置, 可以设置为手动配置.
此处的配置对于大部分软件而言都是全局生效的, 但对于apt等命令行工具无效.
Firefox对于Socks5的支持不太好, 有时候代理软件没问题, 但是Firefox就是用不了
Mac全局代理
在设置中搜索代理, 即可在弹出的页面中选择配置socks5等代理. 其中IP地址可指定局域网内其他机器, 从而先实现基本的代理能力. 在基于此模式下进一步下载其他的依赖项并编译本地的可执行程序.
APT
APT可配置临时使用一次代理, 指令为
1 | sudo apt-get -o Acquire::http::proxy="socks5h://127.0.0.1:1080/" update |
Git
1 | git config --global http.proxy 'socks5://127.0.0.1:1080' |
上述设置仅对使用HTTP方式访问的项目有效, 对于以SSH方式访问的项目, 可以对SSH添加代理配置, 编辑~/.ssh/config文件, 输入以下内容
对于Linux, 使用如下的配置
1 | Host github.com |
对于windows, 使用如下的配置
1 | Host github.com |
之后可以使用ssh -T git@github.com测试连接是否生效.
Docker
Docker的代理分为两类, 一类是docker指令在拉取镜像过程中使用的代理, 配置可以参考Configure the Docker client.
首先创建配置文件
1 | mkdir ~/.docker |
输入如下的配置
1 | { |
一类是容器运行过程中使用的代理, 可以参考HTTP/HTTPS proxy. 配置文件可以参考如下的内容:
1 | [Service] |
关于Docker镜像仓库的配置, 可以参考笔记Docker笔记之使用镜像
配置镜像源
pip
pip可以临时指定使用的镜像, 例如
1 | pip install -i https://pypi.tuna.tsinghua.edu.cn/simple some-package |
也可以直接指定全局永久生效
1 | pip config set global.index-url https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple |
npm
1 | npm config set registry http://mirrors.cloud.tencent.com/npm/ |
配置Samba服务
执行如下指令安装服务并设置共享路径和用户名密码
1 | sudo apt-get install samba samba-common |
配置/etc/samba/smb.conf文件, 添加如下内容
1 | [share] |
如果使用VIM, 注意复制的时候开头的字母是否完整的复制. 此服务不检查配置文件语法结构是否正确
最后重启服务, 启用配置
1 | sudo service smbd restart |
如果客户端连接遇到问题, 可以参考如下的解决方案
Openwrt路由器配置Hosts
自动化与计划任务
开机执行程序
- 在18.04中,可以在Tweak中直接设置开启启动程序
- 在20.04中, 搜索startup可以在设置中添加启动指令
- 非桌面版系统可以使用crontab设置开启执行的脚本
设置定时任务
使用crontab -e打开文件, 并输入要执行的指令. 例如
1 | 0 3 * * * /root/Application/TimeMachine.sh daily |
注意: 全部位置都要使用绝对路径,并且手动执行一次脚本, 确认权限和路径没有问题
Crontab语法解析
在Crontab的文件中, 每一行表示一个要执行的指令, 每一行都具有如下的格式
1 | * * * * * /path/to/script.sh |
前面的5个*的位置分别表示分钟, 小时, 天, 月, 和星期. 如果是数字就是具体的时刻, 如果是*则表示所有, 例如
1 | 0 3 * * * ==> 每天3点0分执行一次 |
此外, Crontab还支持一些特殊的语法, 例如下面的指令表示每次系统重启后先休眠300秒, 然后写入当前的时间到指定文件之中.
1 | @reboot sleep 300 && date >> ~/date.txt |
注意: 确保脚本能正常结束, 否则应该加入
&符号使脚本在后台执行
更多配置方式, 可以参考下面的文章
- Crontab in Linux with 20 Useful Examples to Schedule Jobs
- Crontab Reboot: How to Execute a Job Automatically at Boot
不执行原因排查
首先在根目录手动执行一次脚本, 确定脚本的权限和路径设置都是正确的. 如果脚本可以手动执行, 但配置就是不生效, 可以将脚本的输出重定向到日志文件, 例如
1 | * * * * * /root/Application/TimeMachine.sh daily >> /root/TM.log 2>&1 |
之后可以在日志中查看是否有报错.
开发环境与工具
添加搜索路径
通常系统会在用户的home目录下添加一个搜索路径, 以便于用户可以调用自己编写的程序, 如果没有, 可以按照如下方式添加
修改
.bashrc- 此文件位于用户的home目录下, 可以使用顺手的编辑器打开
添加指令
- 例如将home目录下的bin目录添加到搜索路径中, 则添加如下语句
1 | export PATH=~/bin:"$PATH" |
- 重启终端使配置生效
安装fish
安装并切换默认shel
1 | sudo apt install fish |
注意不要以root身份执行chsh, 否则该操作仅对root用户生效
fish提供自动补全功能, 使用→接受整个补全结果, 使用Alt+→接受补全结果中的一个单词. 使用Alt+s在上一条指令前补充sudo指令.
使fish支持conda
在bash环境中执行
1 | conda init fish |
然后重新开shell即可实现conda环境的切换
添加环境变量
常规的对PATH变量的修改对fish无效, 如果需要添加新的路径到PATH变量中, 可以执行
echo “set PATH /home/lizec/.local/bin $PATH” >> ~/.config/fish/config.fish
编译参数
编译线程有关程序
如果用到了pthread.h中的函数,在使用gcc编译的时候,需要加上-pthread
编译32位程序
安装如下的包
1 | sudo apt install build-essential module-assistant gcc-multilib g++-multilib |
之后可以使用-m32指令进行编译, 例如
1 | gcc -m32 hello.c |
查询头文件对应的依赖
使用源码编译时,可能因为缺少相关的依赖,导致编译出错. 此时可以通过如下指令查询头文件对应的依赖包名称
1 | # 安装工具 |
执行上述命令会出现如下的搜索结果
1 | ivtools-dev: /usr/include/IV-X11/Xlib.h |
经过分析,安装libx11-dev即可解决依赖问题
注意configure指令可能会根据依赖的情况设置编译变量,因此安装对应依赖后需要重新执行configure指令
远程管理与服务器
服务器版开启X11支持
执行如下指令安装需要的模块
1 | sudo apt install xorg xauth openbox xserver-xorg-legacy |
之后可以输入xclock测试配置是否正确
注意: 安装X11界面后, 同时会开启自动休眠策略, 为了避免服务器自动关机, 同时需要进行如下的设置
1 | sudo systemctl mask sleep.target suspend.target hibernate.target hybrid-sleep.target |
配置X11转发
使用X11转发功能, 可以使得其他设备查看Ubuntu系统上的窗口, 进而实现可视化的操作. 虽然基于X11转发的性能不太行, 不如专门的远程桌面, 但相较于专门开启图形化界面进行操作, 这种和SSH紧密结合且仅传输一个窗口的模式对于开发还是非常的方便.
运行Chrome很卡, 但运行bochs绰绰有余
实现X11转发需要两个条件:
- 本地存在相应的软件, 能够渲染从服务器传输过来的数据
- 本地使用的SSH软件支持X11转发
针对第一点, 可以安装vcxsrv, 针对第二点, 不同的软件有不同的配置方法, 可以参考
其他参考资料:
服务器部署项目推荐
服务器指北 - 有了服务器之后可以做点什么 - idealclover
多媒体处理
安装ffmpeg
开源项目ffmpeg提供了非常好用的视频处理功能, 一般情况下仅使用ffmpeg就可以满足所有的视频处理需求. 对于Ubuntu系统, 可以使用如下指令安装
1 | sudo apt install ffmpeg |
直接安装, 之后可使用如下指令查看安装是否成功
1 | ffmpeg -version |
如果感觉版本较旧, 可考虑使用snap安装 或者 源码编译
视频转码
要使用FFmpeg将视频转码为H.265编码MP4文件, 可以按照以下步骤操作
1 | ffmpeg -i input.mp4 -c:v libx265 -preset medium -crf 26 -c:a copy output_1080p.mp4 |
-i参数指定输入文件. 如果仅指定-i则ffmpeg仅输出文件的元信息(编码格式, 分辨率, 码率等). -c:v指定视频编码格式, 常见选项包含
| 编码器参数名 | 含义 |
|---|---|
| libx264 | CPU编码的H.264格式 |
| libx265 | CPU编码的H.265格式 |
| libaom-av1 | CPU编码的AV1格式 |
| h264_nvenc | NVIDIA显卡编码的H.264格式 |
| hevc_nvenc | NVIDIA显卡编码的H.265格式 |
| av1_nvenc | NVIDIA显卡编码的AV1格式(40系及以上显卡支持) |
| h264_videotoolbox | Mac平台硬件编码的H.264格式 |
| hevc_videotoolbox | Mac平台硬件编码的H.265格式 |
通常情况下, 使用纯CPU编码时, AV1格式比H265格式慢3~5倍. 而使用NVIDIA显卡时可以提供x17倍的编码速度, 使用Mac平台时可以提供x6倍的编码速度. 虽然Mac的转码速度比显卡慢, 不过确实能耗比较低, 不会导致发烫, 也不影响同时做其他事情
在编码前需要读取视频文件并对视频解码, 默认自动选择CPU进行解码, 但也支持使用-c:v指定GPU解码(需要在-i参数前指定), 具体参数如下
| 解码器参数名 | 含义 |
|---|---|
| h264_cuvid | NVIDIA显卡解码的H.264格式 |
| hevc_cuvid | NVIDIA显卡解码的H.265格式 |
通常解码速度不构成瓶颈, 因此可以直接用默认的CPU解码, 但如果有显卡, 也可以让显卡解码, 能省电一点.
-preset medium: 设置编码速度与压缩效率的平衡. 常用的预设包括 ultrafast, superfast, veryfast, faster, fast, medium, slow, slower, veryslow. 预设越快,编码速度越快,但压缩效率可能较低;预设越慢,压缩效率越高,但编码时间更长. medium 是默认值,适合大多数情况.
-crf: 设置恒定质量因子(Constant Rate Factor),范围为0-51,数值越小,输出质量越高,文件大小也越大. 常用范围是18-28,其中23是默认值, 期望减少体积时可以设置为28.
-crf控制了画面的质量, 决定了最后视频文件的体积大小, 而-preset控制了编码的速度, 牺牲速度可以在同样的画面质量下获得更小的体积.-preset对于显卡编码意义不大, 保持默认即可.
-c:a copy: 音频部分直接复制, 不进行转码处理
注意: 转码操作前需要先确认原视频的码率, 如果原视频码率已经非常低了, 那么即使转换为其他格式, 收益也不大(甚至可能视频文件会变大)
注意: Mac平台硬件编码不支持恒定质量因子, 必须手动指定码率
调整码率
基于质量因子的方法难以预估最终文件的体积大小, 而采用基于码率的方法则可以较为准确的评估. 例如假设视频当前的码率为6000kb/s, 其占用的空间为8GB, 则使用相同编码进行转码, 控制码率为3000kb/s, 则最终文件体积一定会在4GB左右.
使用如下指令可将一个给定的视频码率调整为h265格式且码率为2500kb/s
1 | ffmpeg -i input.mp4 -c:v libx265 -b:v 2500k -c:a copy output.mp4 |
通常情况下, 对于如下的几种常见编码格式, 可以使用如下的码率
| 编码格式 | 推荐码率 |
|---|---|
| H.264 | 3500k |
| H.265 | 2500k |
| AV1 | 2000k |
对于大部分场景而言, 在H.264格式下的1080p视频, 使用3500k的码率, 即可获得较好的视觉效果. 对于H.265编码和AV1编码, 则可以在更低码率下获得相似甚至更好的视觉效果.
由于显卡有硬件支持, 因此有显卡时优先使用
AV1格式, 无显卡时优先使用H.265格式
任务时间估计
执行对应的指令后, 在当前命令行会输出一个统计信息, 其中包含 speed=1.23x之类的数据, 其含义为相较于视频原始的播放速度, 当前任务执行速度的倍率. 例如原始视频长度为1小时, 当speed=2x时, 转码需要的时间则正好为0.5小时.
音频提取
要使用FFmpeg提取MP4视频的音频部分, 可使用如下指令
1 | ffmpeg -i input.mp4 -vn -acodec copy output.m4a |
常用参数说明:
| 参数 | 作用 |
|---|---|
-i input.mp4 |
指定输入文件 |
-vn |
禁用视频流处理 |
-acodec copy |
复制原始音频编码(无损) |
-c:a [编码器] |
指定音频编码器(如libmp3lame) |
-q:a [1-9] |
设置MP3质量(值越小质量越高) |
-b:a 192k |
固定比特率(例如192kbps) |
-ar 44100 |
设置采样率(Hz) |
-ac 2 |
设置声道数(2=立体声) |
原始音频编码可通过
ffmpeg -i input.mp4在输出信息中查看(如Stream #0:a行)
截取片段
要使用 FFmpeg 截取音频文件的前 5 分钟,请使用以下命令格式:
1 | ffmpeg -i input_audio.ext -t 300 -c copy output_clip.ext |
可以指定精确的开始和结束时间, 使用-avoid_negative_ts make_zero可避免截取位置不是关键帧导致的画面错位或者开头黑屏
1 | ffmpeg -i input.mp4 -ss 00:00:10 -to 00:00:30 -c copy -avoid_negative_ts make_zero output.mp4 |
合并多个文件
1 |
|
ubuntu桌面版优化
注意事项
- 不建议选择过于新的系统, 选择发布至少一年的版本比较稳妥.
- 直接使用迅雷下载镜像文件, 从网页下载到2GB时会卡住.
- 安装时语言选择中文, 从而确保安装了对应的输入法, 否则在英文操作系统上安装输入法将消耗大量时间.
- 不要安装第三方驱动, 尤其是显卡驱动. 否则容易出现版本不匹配导致无法启动图像界面.
- 不要选最小安装, 全部使用默认值即可, 附带的软件一般最后都会用上, 提前安装好可以节省后续的时间.
- 尽量使用命令行安装和卸载软件, 至少能看到错误信息. 不到最后, 不要使用图形界面安装.
- 不要强制卸载任何软件, 否则可能导致依赖关系破坏, 直接影响整个apt系统.
每个长期支持版都可以使用7年, 不必可以追求最新版. 而且由于最新版的系统中基础软件版本较高, 可能导致无法安装第三方软件. 例如fish对于Python最高版本有要求, 过高的Python版本将导致无法安装fish.
从图形界面安装程序虽然比较简单, 但如果出现错误无法查看错误信息, 如果界面卡住也无法得知具体的进度情况. 强制终止容易出现错误, 进而破坏整个安装系统.
安装搜狗输入法
注意: 安装系统时语言必须选择中文, 以免产生不必要的麻烦
搜狗输入法目前已经支持到Ubuntu20.04, 按照如下的教程安装即可. 更高版本的系统可能会安装失败.
ubuntu隐藏顶部标题栏
1 | sudo apt install gnome-shell-extension-autohidetopbar |
注销当前用户后, 重新登录并在搜索页面中打开Extension, 选择Hide Top Bar即可
ubuntu隐藏wine状态栏
访问此链接安装指定的插件, 即可将独立窗口的Wine System Tray移动到右上的状态栏之中.
由于该网站通过在网页上点击的方式安装系统插件, 因此需要先给浏览器安装一个通信插件才能正常使用该功能
ubuntu安装基于wine的软件
访问zq1997/deepin-wine, 按照教程添加第三方库后即可按照指令安装Windows平台的软件.
键位替换
将CapsLK替换为Esc
搜索tweaks打开配置页面, 选择Keyboard & Mouse选项卡, 点击Additional Layout Options, 再弹出的窗口中选择Caps Lock Behavior选项, 并选择Make Caps Lock an additional Esc
其他键位相关的配置也可以在这里修改, 相比与前几年, ubuntu的配置简单了很多了
使用Mac键位
对于我的键盘, 在Mac布局下Cmd建的位置, 对应的是Win键, 因此只需要将Ctrl键覆盖Win键即可解决大部分最难受的快捷键. 配置方法与将CapsLK替换为Esc相同
从文件安装软件
和Windows平台一样,Ubuntu也可以从文件安装软件. Ubuntu平台默认的安装包格式是deb格式,对于该格式的文件,可以直接双击打开安装页面.
对于其他Linux平台的安装包(例如rpm格式),可以通过alien命令转换为deb格式, 例如
1 | sudo apt install alien |
之后会生成同名的deb包,双击安装即可
不建议以这种方式安装软件, 容易导致依赖管理出现错误
EPUB阅读器
如果在阅读的同时还需要对大量电子书进行管理, 则直接安装Calibre并可以配合Calibre-Web使用.
如果单纯需要阅读EPUB格式的电子书, 则可以安装FBReader, 该软件可以通过snap安装, 即
1 | snap install fbreader |
双系统设置默认启动项
- 打开相关的配置文件
1 | $ sudo gedit /etc/default/grub |
- 修改相关选项
1 | # 节选其中的一段内容如下所示 |
- 更新
只有更新上述设置以后, 相关的修改才会生效
1 | $ sudo update-grub |
创建桌面快捷方式
使用文件编辑器在桌面创建一个以.desktop结尾的文件. 然后依据需要设置一下的内容
1 | [Desktop Entry] |
最后更新: 2026年04月16日 15:06
版权声明:本文为原创文章,转载请注明出处
原始链接: https://lizec.top/2017/08/10/Ubuntu%E4%BD%BF%E7%94%A8%E8%AE%B0%E5%BD%95/