引言

本次课内容:

  • Linux vs. Windows
  • 命令行工具概述
  • 如何学习Linux

Linux vs. Windows

我们为什么使用计算机?

  • 爸爸妈妈爷爷奶奶
    • 看剧, 网购 -> 浏览器
  • 秘书
    • 文档, 表格, 幻灯片编辑 -> Office
  • 美工
    • 图像处理 -> PhotoShop

 

这些任务都有一个很复杂但容易上手的工具来完成

  • 这就是Windows GUI工具的风格

Unix - 另一种风格

  • Unix(Linux的祖先)通过命令行搞定一切
    • ping www.baidu.com - 查看网络基本状态
    • df / - 查看磁盘分区使用情况
    • fdisk /dev/sdb - 对磁盘进行分区
    • poweroff - 关机
    • find . -name "*.[ch]" - 查找当前目录下的.c和.h文件
    • grep "\bint i\b" a.c - 查找文件中定义变量i的位置
    • wc a.c - 统计文件的行数/单词数/字符数
    • apt-get install gcc - 一键下载安装新工具
    • wget http://www.xxx.com/abc.zip - 下载文件
    • iconv -f gbk -t utf-8 file.txt - 文件编码转换

有什么好处? 这些在windows下点点鼠标也能做

有些简单的事Windows GUI反而做不好

例子: 比较两个文件是否完全相同

  • 在Windows GUI下如何实现?

 

Linux的解决方案

  • 文本文件的比较: vimdiff file1 file2
  • 非文本文件的比较: diff file1 file2
  • 很大的文件: md5sum file1 file2

 

也许你在Windows中下载了一个计算MD5的GUI工具

  • 你需要点击多少次鼠标? (Linux操作熟练只需3s)

也许你觉得一次也省不了多少时间

  • 真相 - 你的工作效率就是这样一点点降低的

有些稍微复杂的事Windows GUI几乎做不了

例子: 列出一个C语言项目中所有被包含过的头文件

  • 在Windows下如何用GUI实现?

 

Linux的解决方案:

find . -name "*.[ch]" | xargs cat | grep "^#include" | sort | uniq

 

这体现了Unix哲学

  1. 每个小工具只做一件事, 但做到极致
  2. 小工具采用文本进行输入输出, 从而易于使用
  3. 通过小工具之间的组合来解决复杂问题

 

Windows的GUI工具之间几乎无法组合

为什么Linux更适合程序员?

  • 关键思想: 通过编程创造提升解决问题的效率
    • 标准小工具之间的组合 -> shell编程
    • vim -> 命令编程(dd->删除1行, 10dd->删除10行)
    • grep/awk/sed -> 正则表达式编程
  • Linux命令行已经成为不少IT行业的首选
    • 运维, 开发服务器, 路由器…
  • 开源: 有机会认识计算机系统如何工作
    • .bashrc, /etc/profile, /etc/rcS.d/S01udev, …
    • strace, ltrace, …
    • 甚至是OS的源代码

 

Windows的目标是大众人群, “易上手”是最重要的

工具是第一生产力

命令行的一些约定

命令格式:

命令 参数1 参数2 ...

 

例: 查看当前目录下的文件

$ ls -l -a    # 也可以把选项合并成ls -la
total 56K
drwxr-xr-x  2 yzh yzh  4096 Sep 11 09:52 .  --> 当前目录
drwxr-xr-x 10 yzh yzh  4096 Sep 10 19:51 .. --> 父目录
-rw-r--r--  1 yzh yzh 34565 Sep  4 10:48 01.md
-rw-r--r--  1 yzh yzh  9314 Sep 11 09:36 02.md
|\./\./\./  | \./ \./ \.../ \........../   +--> 文件名
| |  |  |   |  |   |    |        +------------> 上次修改日期
| |  |  |   |  |   |    +---------------------> 文件大小(字节)
| |  |  |   |  |   +--------------------------> 文件所属组
| |  |  |   |  +------------------------------> 文件所属用户
| |  |  |   +---------------------------------> 硬链接数量
| |  |  +-------------------------------------> 其他用户权限
| |  +----------------------------------------> 组内用户权限
| +-------------------------------------------> 所属用户权限
+---------------------------------------------> 文件类型

Linux Filesystem Hierarchy Standard (FHS)

~表示/home/当前用户/

丰富的工具

Busybox套件(包含常用的Linux命令行工具)将工具分为如下类别:

  • 网络管理
  • 系统日志管理
  • 登录/密码管理
  • 控制台管理
  • 启动/关机
  • Linux Ext2文件系统
  • Linux内核模块管理
  • 打印机管理
  • 邮件管理
  • runit兼容
  • Debian兼容
  • klibc兼容
  • 杂项

 

标准Linux的工具更多: /bin目录下有上千个工具

如果需要安装工具, 但不知道在哪个包, 可以在包搜索页面搜索

工具如何运行?

打开黑盒的方法

  • 看源码(source): 可以得知每一处静态细节, 但较繁琐
  • 看踪迹(trace): 可以了解运行动态行为, 但不全面
    • 不过却容易理解!

 

一个重要的踪迹工具: strace

  • system call trace, 记录程序运行过程中的系统调用信息
  • 系统调用 = 一个由操作系统来执行的特殊的函数调用
  • 通过观察程序运行过程中发生的系统调用, 可以大致了解程序关键行为

工具如何运行?(续)

例1: ls如何运行

strace ls
strace ls -l

 

例2: ls如何被寻找?

strace -f bash -c "ls"
strace -f bash -c "abcdefg"
strace -f bash -c "PATH='aaa:bbb:ccc' ls"

 

例3: 用户如何与man交互

strace -o strace.log -f man ls
tail -f strace.log # 在另一个终端执行

强大的shell

作为和操作系统交互的界面, shell具有很多方便的功能

  • 通过Tab键自动补全
  • 通过上下方向键检索历史命令
  • 可以通过A-fA-b按键来按单词移动光标
    • 更多快捷键可以阅读man readline
  • 通过history命令查看历史命令
    • 通过!n(n为历史命令的编号)再次执行命令
    • 通过!xxx再次执行以xxx开头的最近一条命令
  • 通过cd -返回上一个工作目录
  • 通配符*(任意长度的任意字符串), ?(任意一个字符)和[...](集合中的任意一个字符)
  • 括号扩展{...} (例: echo Hello-{a,bb,ccc}-{1,2}!)

使用alias为常用命令设置别名

alias ls="ls --color"

可以写入~/.bashrc文件, 打开终端时生效, 无需重复设置

 

常见的Linux rm梗, 请谨慎尝试 🙃

正则表达式

一种用于字符串匹配的编程语言

  • 匹配能力比通配符强大很多
  • 一般配合grep, awk, sed, vim等工具使用

 

例: 匹配email

任务管理

通过命令行模拟窗口管理的功能

  • 最小化(在后台运行) - C-Z + bg
    • 或运行命令时通过末尾添加&指定后台运行
  • 任务栏 - jobs
  • 最大化 - fg
  • 关闭 - kill
    • 一般通过kill -9 进程号强行关闭

 

任务管理器 - ps aux, top, htop

输入输出重定向

Linux上的程序在运行时默认打开了3个文件, 通过 “文件描述符”来编号:

  • 0号文件 - 标准输入(默认为当前终端)
  • 1号文件 - 标准输出(默认为当前终端)
  • 2号文件 - 标准错误(默认为当前终端)

可通过lsof -p 进程号来查看打开的文件

 

可将标准输出重定向到文件, 供后续使用

ls > result.txt
strace -f bash -c "ls > result.txt"

yes > /dev/null &
lsof -p `pgrep yes`

输入输出重定向(续)

向文件追加输出

ls >> result.txt

 

可将标准错误重定向到文件

  • 标准错误一般用于报告错误信息
ls 2> /dev/null

 

将标准输入重定向到文件, 无需手动输入

sort < result.txt

管道: 工具间组合的秘诀

管道 = 一个用于连接程序间输入输出的缓冲区

+-------+  stdout   +------+  stdin   +-------+
| prog1 | --------> | pipe | -------> | prog2 |
+-------+           +------+          +-------+

 

例:

yes | cat > /dev/null
# 通过lsof查看打开的文件

 

xargs: 一个特殊的命令, 可以将标准输入转变为命令的参数

组合变得更强

青春版直播时钟

watch -t -n 1 "echo -n '第六期一生一芯 | 周六 15:00~17:00 | '; \
  date; echo '课程主页 https://ysyx.oscc.cc/docs/'"

 

无人值守重试操作

while ! git push origin HEAD; do echo "retry"; done
while [[ `seq 1 10 | shuf | head -n 1` != "1" ]]; do echo "retry"; done

 

自制CPU主频监视器

watch -n 1 "cat /proc/cpuinfo | grep MHz | awk '{print \$1 NR \$3 \$4 \$2}'"

 

打包特定文件并上传到远端

find . -name "*.pdf" | xargs tar cj | ssh yzh@192.168.1.1 'cd ysyx; > pdf.tar.bz2'

脚本: 自动化重复的工作

把命令写到一个文件里面

  • 可以重复执行, 不用每次都手动键入了
  • 可以被其他脚本调用, 自动化工作
    • 人的按键频率(~4Hz) vs. CPU的工作频率(~4GHz)

工具的本质

统计一下工具的类型分布

echo $PATH | tr -t : '\n' | xargs -I{} find {} -maxdepth 1 -type f -executable | \
  xargs file -b -e elf | sort | uniq -c | sort -nr

结果: 大部分是可执行文件(ELF), 小部分是脚本

   1365 ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV)
    187 POSIX shell script, ASCII text executable
    106 Perl script text executable
     52 ELF 64-bit LSB pie executable, x86-64, version 1 (GNU/Linux)
     32 Python script, ASCII text executable
     26 Bourne-Again shell script, ASCII text executable
     17 ELF 64-bit LSB executable, x86-64, version 1 (SYSV)
     12 setuid ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV)
      8 POSIX shell script, Unicode text, UTF-8 text executable
      7 setgid ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV)
      7 ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux)
      2 Python script, Unicode text, UTF-8 text executable
      1 Tcl/Tk script, ASCII text executable
      1 Python script, ISO-8859 text executable
      1 POSIX shell script, ASCII text executable, with very long lines (933)
      1 POSIX shell script, ASCII text executable, with very long lines (456)
      1 POSIX shell script, ASCII text executable, with very long lines (317)
      1 Paul Falstad's zsh script, ASCII text executable
      1 Java source, Unicode text, UTF-8 text

自制工具 = 编程!

  • 写脚本
    • if, for, while, case…等控制流
    • 变量赋值和引用
    • 函数定义和调用
    • 内建命令
    • 更多内容可参考man bash

 

一个例子

vim `which -a which | grep -v shell | head -n 1`

自制工具 = 编程!(续)

  • 写C程序
    • 命令行参数 = main()函数的参数
    • getopt()库函数识别并处理参数
    • fopen()打开文件
    • fscanf()/fread()从标准输入读取
    • fprintf()/fwrite()将结果写入到标准输出
    • main()函数的返回值 = 命令的返回值

 

main()函数的原型

int main(int argc, char *argv[], char *envp[]);

一个示例: 输出参数(argv.c)

如何学习Linux

1. 卸载Windows

准确地说: 卸载Windows GUI工具给你安装的思想枷锁

  • 没办法, 也只能这样了 vs. 我来试试能不能把事情做得更好
  • 事实上GUI工具确实很难给你做得更好的机会

 

自我觉醒

  • 你不再是计算机的一名普通用户, 你是一名光荣的码农
  • 用编程武装自己, 提升技术能力和做事效率
  • 思考是否能用命令行更高效地完成一件事情
    • Windows下也有PowerShell, 需要适应不同的使用习惯

 

如果你不玩现代游戏, 可以考虑装个Windows虚拟机

2. RTFM

最重要的Linux命令: man

  • 查阅命令/库函数/系统文件等内容的手册
  • man man - 学习如何RTFM
  • man ls - 查看如何使用ls命令
  • man 3 printf - 学习如何使用库函数printf
  • man -k xxx - 检索含有关键字含有xxx的命令

 

学会使用man, 你就能学会使用Linux上的一切

3. 学习新工具

以下工具覆盖了程序员绝大部分的需求

文件管理 - cd, pwd, mkdir, rmdir, ls, cp, rm, mv, tar
文件检索 - cat, more, less, head, tail, file, find
输入输出控制 - 重定向, 管道, tee, xargs
文本处理 - vim, grep, awk, sed, sort, wc, uniq, cut, tr
正则表达式
任务管理 - jobs, ps, top, kill, free, lsof

 

用得多就记住了, 如果记不住

  • 尝试-h, --help等选项查看帮助信息
  • man

 

更多工具的介绍

4. STFW

想做一件事, 很大概率别人已经做过了

  • 使用搜索引擎可以帮助你找到解决方案

例1: 想打开pdf文件

  • 搜 “Linux 打开pdf” -> 得知可用evince打开
  • apt-get install evince -> evince a.pdf -> 解决

例2: 想给终端分屏

  • 搜 “Linux 分屏” -> 得知有tmux分屏工具
  • apt-get install tmux -> 不会用
  • 搜 “tmux 教程” -> 阅读教程学习tmux的使用
  • 有的地方还不太明白-> man tmux -> 解决

 

RTFM + STFW能帮你一辈子

STFW警告!!! - 远离百度的毒害

搜索引擎 百科 问答网站
提高效率 www.google.com en.wikipedia.org stackoverflow.com
浪费生命 www.baidu.com baike.baidu.com zhidao.baidu.com
bbs.csdn.net

随着问题技术含量提高, 百度搜索结果越来越不靠谱

  • 搜不到相关结果 -> 挫败
  • 搜到看似相关的结果, 但无法解决问题 -> 挫败 + 浪费生命
  • 即使能解决问题, 也没有原因分析 -> 不知所以然

正确做法

  • 谷歌的搜索结果/英文维基百科的详细说明/stackoverflow的高票回答

 

强烈不建议使用中文关键字/安装中文系统 - 否则你会错过很多

5. 尝试先进的工具

  • 花点时间配置常用工具(shell, tmux, 编辑器等)
  • python vs. 计算器
  • awesome系列
  • thefuck - 输入 “暗号”可智能纠错命令行

  • ChatGPT

ChatGPT警告 - 需要甄别信息的真伪

  • ChatGPT是个智能搜索引擎
    • 不能替代手册 - ChatGPT的回答没有权威性
    • 不能替代网上的高票回答 - ChatGPT的回答没有经过检验
      • 有时候比百度更不靠谱 😂

初学者慎用!

逃避 = 放弃训练的机会

对于未知, 人都有恐惧和懒惰的惯性

对于短期负收益的事情, 人都会聪明地选择逃避

 

  • 对命令行感到陌生和恐惧, 还是GUI点点鼠标更舒服
    • 于是压根没想过怎么提高效率
  • 不懂的命令也不愿意man一下
    • 于是就只会使用cd, ls, exit那么几个命令
  • vim基本操作够用就行, 高级功能太复杂太麻烦
    • 于是只会低效地操作, 体会不到vim的好处(批量操作, 记录回放等)
  • 正则表达式看着头晕, 也不想深入学一学
    • 于是需要进行复杂pattern匹配的时候, 就直接放弃

逃避 = 放弃训练的机会(续)

对于未知, 人都有恐惧和懒惰的惯性

对于短期负收益的事情, 人都会聪明地选择逃避

 

  • 宁愿开多个终端/ssh连接, 也不愿意花时间找找有没有tmux
    • 于是用鼠标来回切换, 浪费不必要的时间
  • 宁愿把项目简单复制好几份, 也不愿意用git来做版本控制
    • 于是版本管理越来越混乱, 将来不得不投入更多时间
  • 宁愿在百度中舒服地浪费生命, 也不想用谷歌快速解决问题
    • 于是搞不定的问题越来越多
  • 宁愿用翻译工具看中文, 也不愿意坚持看英文
    • 于是英文阅读能力没有进步, 更不会想去谷歌搜高质量英文解决方案

“我能把问题搞定”的最原始的信念

学习使用Linux是一个成本低, 成功率高的锻炼机会

  • 愿意STFW + RTFM, 就能解决绝大部分问题
  • 独立解决小问题 -> 消除畏惧 -> 有信心解决更难的问题

 

学校的大部分实验课都会安排助教手把手装系统/配环境

  • 助教/老师: 实验内容才是重点, 赶紧帮学生搞定那些无关的事情

 

在我们看来, 装系统/配环境并不是 “无关的事情”

  • 从小事做起
  • 戒掉 “我不做/不理解这个也行”的侥幸
  • STFW + RTFM + RTFSC, 试图理解一切事情如何发生

带着这种信念做实验, 你会收获很多

总结

工具是第一生产力

使用工具 = 编程

  • 思考哪些事情适合用GUI做, 哪些事情适合 “编程”

 

学习工具首先需要端正心态 - 我真的想提高效率

  • 相信总有对的工具能帮助我做得更好
  • 并愿意付出时间去找到它, 学它, 用它
    • STFW + RTFM + RTFSC, 让计算机为我所用

 

短时间的投入是负收益, 但这些技能会让你终身受益

  • 坚持四周, 就会慢慢适应
  • 坚持半年, 就会有所不同
  • 坚持一年, 就会大有不同