跳到主要内容

Git 常用命令

· 阅读需 2 分钟

git log

--since 语法

  1. 绝对日期格式
    • YYYY-MM-DD
    • Month Day, Year
    • YYYY-MM-DD HH:mm:ss
  2. 相对时间格式
    • N year/months/weeks/days/hours/minutes/seconds ago
    • yesterday/today
  3. --until --before 结合
    • --since>=
    • --until, 即 <

从今天开始,过去 1 个月的提交

git log --since="1 month ago"

一行显示

git log --since="2025-06-01" --until="2025-07-01" --oneline

自定义输出

# %h commit hash 的缩写
# %an 作者
# %ar 提交的相对时间
# %s 提交信息
git log --since="1 month ago" --pretty=format:"%h - %an, %ar : %s"

图形化显示

git log --since="1 month ago" --graph --oneline

--pretty=format

--pretty:format"- %s" 格式化输出

  • %h commit hash
  • %an author name
  • %ad author date(format respects --date=option) 搭配 --date 使用--date=format:"%Y-%m-%d %H:%M:%S"
  • %ar author date, relative (相对时间)
  • %at author date, UNIX timestamp
  • %ai author date, ISO 8601
  • %ae author email
  • %s subject

查询指定日期之后提交记录并格式化显示

git log --since="2025-11-31" --author="wangzhy" --pretty=format:" - %s %ad" --date=format:"%Y-%m-%d %H:%M:%S"

git config

pull.rebase

git pull 命令的行为方式。

  • git config pull.rebase true 表示使用 rebase 方式来合并远程代码 (要求有干净的工作区,即没有未提交的代码)
  • git config pull.rebase false 表示使用 merge 方式来合并远程代码

自解释代码

· 阅读需 2 分钟

summary

  1. 使用命名常量而非晦涩的错误代码 | Using named constants instead of cryptic error codes
  2. 将复杂逻辑抽离成独立函数 | Extracting complex logic and putting it in its own function
  3. 运用短路求值使代码流程线性化 | Using short-circuit evaluation to make the code flow linear
  4. 引入类型注解辅助静态检查与实时编码反馈 | Introducing type annotations to help with static type checking and real-time coding feedback

original code

async function createUser(user) {
if (!validateUserInput(user)) {
throw new Error('u105');
}

const rules = [/[a-z]{1,}/, /[A-Z]{1,}/, /[0-9]{1,}/, /\W{1,}/];
if (user.password.length >= 8 && rules.every((rule) => rule.test(user.password))) {
if (await userService.getUserByEmail(user.email)) {
throw new Error('u212');
}
} else {
throw new Error('u201');
}

user.password = await hashPassword(user.password);
return userService.create(user);
}

命名常量与单一职责原则

const err = {
userValidationFailed: 'u105',
userExists: 'u212',
invalidPassword: 'u201',
};

function isPasswordValid(password) {
const rules = [/[a-z]{1,}/, /[A-Z]{1,}/, /[0-9]{1,}/, /\W{1,}/];
return password.length >= 8 && rules.every((rule) => rule.test(password));
}

async function createUser(user) {
if (!validateUserInput(user)) {
throw new Error(err.userValidationFailed);
}

if (isPasswordValid(user.password)) {
if (await userService.getUserByEmail(user.email)) {
throw new Error(err.userExists);
}
} else {
throw new Error(err.invalidPassword);
}

user.password = await hashPassword(user.password);
return userService.create(user);
}

短路求值

function throwError(error) {
throw new Error(error);
}

async function createUser(user) {
validateUserInput(user) || throwError(err.userValidationFailed);
isPasswordValid(user.password) || throwError(err.invalidPassword);
!(await userService.getUserByEmail(user.email)) || throwError(err.userExists);

user.password = await hashPassword(user.password);
return userService.create(user);
}

Keeping a Mistake Journal

· 阅读需 1 分钟

Entry Format

Name:名称,简明扼要的标题。
Tags:标签,分类
Context:背景,错误发生的具体环境或情境。
Problem:问题,对错误本身的描述。
Impacts:影响,可能导致的后果。
Lessons learned:经验总结,从这次错误中学到了什么。
Correction plan: 改进方案,今后如何避免重蹈覆辙。
Latest occurrence:最近发送,上次犯这个错误的时间。
Repetition: 重复次数,这个错误发送的概率。

Linux Shell 常用命令

· 阅读需 6 分钟

du

1、查看指定文件夹的大小

-h 以K,M,G为单位,提高信息的可读性。
-s 仅显示总计。

du -sh dir_path

2. 查询当前文件夹总大小

du -sh .

3. 查看当前文件夹所有子项的大小

du -sh *

df

df (disk filesystem)用于显示文件系统的磁盘空间使用情况.

查看 block 使用情况

df -h

查看 inode 使用情况

df -i

alias

alias gg='gg'
alias cls='clear'
alias ls='ls -alFh --ignore=. --ignore=.. --color=auto --group-directories-first'
alias acme.sh=~/.acme.sh/acme.sh

ln

ln -s source_file target_file

nginx

ln -s /wangzhy/cloud-conf/nginx/etc/nginx/conf /etc/nginx/conf
ln -s /wangzhy/.config/nginx_ip_conf /etc/nginx/ip-conf

把程序添加到 /usr/bin 下面

ln -s /source_path/source_name /usr/bin/target_name 

find

find 语法

find [path] [expression]

path:是要查找的目录路径,可以是一个目录或文件名,也可以是多个路径,多个路径之间用空格分隔,如果未指定路径,则默认为当前目录。

expression:是可选参数,用于指定查找的条件,可以是文件名、文件类型、文件大小等等。

-name pattern:按文件名查找,支持使用通配符 * 和 ?。

pattern 用引号括起来,例如

# 查找所有的 pdf 文件
find / -name '*.pdf*'

-type type:按文件类型查找,可以是 f(普通文件)、d(目录)、l(符号链接)等。

查看大于 100M 的文件

find / -type f -size +100M

-size [+-]size[cwbkMG]:按文件大小查找,支持使用 + 或 - 表示大于或小于指定大小,单位可以是 c(字节)、w(字数)、b(块数)、k(KB)、M(MB)或 G(GB)。

-mtime days:按修改时间查找,支持使用 + 或 - 表示在指定天数前或后,days 是一个整数表示天数。

-user username:按文件所有者查找。

-group groupname:按文件所属组查找。

find 命令中用于时间的参数如下:

-amin n:查找在 n 分钟内被访问过的文件。

-atime n:查找在 n*24 小时内被访问过的文件。

-cmin n:查找在 n 分钟内状态发生变化的文件(例如权限)。

-ctime n:查找在 n*24 小时内状态发生变化的文件(例如权限)。

-mmin n:查找在 n 分钟内被修改过的文件。

-mtime n:查找在 n*24 小时内被修改过的文件。

在这些参数中,n 可以是一个正数、负数或零。正数表示在指定的时间内修改或访问过的文件,负数表示在指定的时间之前修改或访问过的文件,零表示在当前时间点上修改或访问过的文件。

+n : n 天之前修改的文件 -n : n 天内修改的文件 n : n 天前修改的文件(第 n 天前的当天)

find 使用案例

  1. 在脚本中使用

find /opt/oracle/oradata/ORCLCDB/oracle_exp_dir -mtime +1 -name "WIKI_USER*" - rm -f exec {} \;

  1. 在 shell 使用

find /opt/oracle/oradata/ORCLCDB/oracle_exp_dir -mtime +1 -name "WIKI_USER*" - rm -f exec {} +

  1. 查找多种后缀的文件
find ~ \( -name "*.zip" -o -name "*.log" -o -name "*.txt" -o -name "*.jar" -o -name "*.json" -o -name "*.xls" -o -name "*.xlsx" -o -name "*.doc" -o -name "*.docx" \)
  1. 查找大于 10M 的 zip 文件
find /path/to/search -type f -name "*.zip" -size +10M -exec du -h {} + > ~/Desktop/a.txt

watch

每隔 1s 查询一下本目录下的,以 sql 结尾的文件的大小,单位是 MB。

watch -n 1 -d ls -lh --block-size=M *.sql

vim

1、vim 显示隐藏行号

# 显示行号
set number
set nu
# 隐藏行号
set nonumber
set nonu

2、vim 删除以 XX 开头的行

# 按 esc 进入命令输入模式
# 删除以 XX 开头的行
:g/^XX/d

tee

tee 的主要功能是从标准输入读取数据,然后将数据写入标准输出(即输出到终端上面)和文件。

echo 'hello world' | tee -a xxx.txt

tee>> 的区别?

tee 可以一次写入多个文件,并且可以在终端显示写入的内容。 >> 是静默的写入。

tar 压缩/解压文件

# 压缩
tar -zcvf test.tar.gz test
# 解压
tar -zxvf file.tar.gz

五选一

-c 压缩 -x 解压 -t 查看内容 -r 追加文件 -u 更新原压缩包的文件

可选

-z gzip -j bz2 -Z compress -v 显示过程 -O 标准输出

必选

-f 使用档案名字,这个参数是最后一个参数,后面只能接档案名。

systemd

Ubuntu 16.04 不再支持 rc.local 了。开机自启只能通过 systemd 来实现。

# 查看systemd 版本
systemctl --version
# 查看服务是否启用
systemctl is-enabled SERVICE_NAME

scp

[root@VM-16-10-centos ~]# scp
usage: scp [-12346BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file]
[-l limit] [-o ssh_option] [-P port] [-S program]
[[user@]host1:]file1 ... [[user@]host2:]file2

scp 命令传输文件

# 复制远程机器上的 xxx.zip 到本地
scp cloud:/wangzhy/xxx.zip ~/backups/
# 复制远程机器上的文件夹到本地
# -r 表示递归复制整个目录
scp -r cloud:/wangzhy ~/backup/
  • -C:开启压缩传输

passwd

1、设置简单的密码

# 方法一
echo '123456' | passwd --stdin username
# 方法二
echo username:password | chpasswd

2、删除用户的登录密码

passwd -d root

3、清除 last、lastb 的信息

# 清除登录记录
echo > /var/log/wtmp # last
echo > /var/log/btmp # lastb

查看 linux 版本信息

# 查看架构信息
uname -a
# 查看发行版本信息
cat /etc/os-release
# 输出机器的体系结构
arch

ntp

同步操作系统的时间

# 安装 ntp
yum -y install ntp
# 同步时间,这个只是修改操作系统的时间,重启之后就会失效
ntpdate -u cn.pool.ntp.org
# 查看当前硬件时间
clock -r
# 把当前操作系统的时间写入硬件中
clock -w

curl

curl -L 参数的作用是让 curl 在遇到 HTTP 3xx 状态码(重定向)时,自动跟随新的位置(URL)

curl -L www.sina.com

使用 -k--insecure 参数让 curl 忽略 SSL 证书验证

curl -k https://wangzhy.com 

下载文件

-o 需要指定文件名

-O 使用 URL 中的文件名

brew

安装 xcode 才能升级 brew

xcode-select --install

brew 升级

brew update
brew upgrade

brew 查看安装的软件

brew list

brew 卸载软件

brew uninstall software_name

查看磁盘读写总量

brew install smartmontools

smartctl -a /dev/disk2

安装 svn

brew install subversion

svn help

grep

egrep 是 grep 的增强版本,支持更多的正则表达式

-v 告诉 egrep ,不现实匹配的行,即反向匹配。

egrep -v "^*#|^$" filebeat.yml

wget

-i 下载本地或外部文件中的 URL,如: wget -i file.txt

-O 将输出写入指定文件。 sh -c "$(wget https://xxx.sh -O -)", 末尾的 - 表示标准输出(stdout) 这句命令的作用是,通过 sh 执行 https://xxx.sh 脚本。

-b 后台下载。

-d 调试模式。

awk 命令基本使用

· 阅读需 3 分钟

awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。

默认分隔符是:空白键或者 tab 建,以 \n 为一行

$0:所有域
$n:第 n 个域

1、显示出最近登录成功的用户

使用默认分隔符

last -n 5 | awk '{print $1}'

2、查看用户

通过 -F ':' 指定分隔符

# 下面两个命令等效
cat /etc/passwd | awk -F ':' '{print $1}'
cat /etc/passwd | awk -F: '{print $1}'

3、查看用户的时候显示出 bash

通过双引号对 \t 转义

cat /etc/passwd | awk -F ':' '{print $1"\t"$7}'

4、BEGIN、END 使用

cat /etc/passwd | awk -F ':' 'BEGIN {"name,bash"} {print $1","$7} END {print "blue,/bin/nosh"}'

5、匹配含有关键字的行

'/pattern/action' 指定正则表达式和 action

awk -F ':' '/root/' /etc/passwd
awk -F ':' '/root/{print $7}' /etc/passwd

6、awk 内置变量

ARGC               命令行参数个数
ARGV 命令行参数排列
ENVIRON 支持队列中系统环境变量的使用
FILENAME awk浏览的文件名
FNR 浏览文件的记录数
FS 设置输入域分隔符,等价于命令行 -F选项
NF 浏览记录的域的个数
NR 已读的记录数
OFS 输出域分隔符
ORS 输出记录分隔符
RS 控制记录分隔符
awk -F ':' '{print $1 "\tfilename:" FILENAME "\t\tARGC:" ARGC "\tFNR:" FNR}' aa.txt 

7、print、printf

print函数的参数可以是变量、数值或者字符串。字符串必须用双引号引用,参数用逗号分隔。如果没有逗号,参数就串联在一起而无法区分。这里,逗号的作用与输出文件的分隔符的作用是一样的,只是后者是空格而已。

printf函数,其用法和c语言中printf基本相似,可以格式化字符串,输出复杂时,printf更加好用,代码更易懂。

8、自定义变量

awk -F ':' 'BEGIN {count=0; print "[start] user count is "count}{ count++; print $1"\t" count} END {print "user count is " count}' /etc/passwd

统计某个文件夹下的文件占用的字节数

ls -l |awk 'BEGIN {size=0;} {size=size+$5;} END{print "[end]size is ", size}'

如果以M为单位显示:

ls -l |awk 'BEGIN {size=0;} {size=size+$5;} END{print "[end]size is ", size/1024/1024,"M"}'

9、显示账户

awk -F ':' 'BEGIN {count=0;} {name[count] = $1;count++;}; END{for (i = 0; i < NR; i++) print i, name[i]}' /etc/passwd

查看拒绝访问的 IP

awk -F ':' '{print $2}' /etc/hosts.deny| sort | uniq -c | awk '{print $1"\t"$2}' | grep  '^[0-9]' 

MongoDB 常用查询语句/技巧

· 阅读需 2 分钟

转换为 UTC 时间字符串

// 转换为 UTC 时间字符串
db.collection.find({
timestamp: { $gte: new Date( new Date("2025-03-22T00:00:00+08:00").toISOString()) }
});

创建视图

标准视图使用底层集合的索引。

// ==============  AI800 A相进线温度  ==========
db.AI800.drop();
db.createView(
"AI800", // 视图名称
"equipment-1123", // 源集合
[
{ $match: { "code": "AI424" } }, // 过滤条件
]
)

db.AI800.find();

MongoDB 储存空间优化

数据库状态查询

db.status()

db.stats(1024*1024); // 输出单位为 MB

查询结果说明:

{
"db": "tmp_dev",
"collections": Long("275"),
"views": Long("0"),
"objects": Long("7891781"), // 文档总数
"avgObjSize": 234.529085766572, // 单个文档的平均大小,单位是:byte
"dataSize": 1765.11019039154, // 逻辑大小,不压缩的情况下,数据大小
"storageSize": 299.5, // 物理大小
"indexes": Long("281"), // 索引数量
"indexSize": 123.61328125, // 索引占用的存储空间
"totalSize": 423.11328125, // 总存储空间 = storageSize + indexSize
"scaleFactor": Long("1048576"), // 缩放因子, 1048576 = 1024 * 1024, 即 MB
"fsUsedSize": 126627.28515625, // 文件系统已使用的存储空间
"fsTotalSize": 181303.5546875, // 文件系统总存储空间
"ok": 1
}

空间优化

1. 删除 collection 是可以直接释放空间的

2. 删除 collection 里面的数据是不会直接释放空间,需要执行 db.runCommand({compact:"collectuinName"})

优化脚本

for (var collectionName of db.getCollectionNames()) {
// 清空数据
if (collectionName.startsWith("equipment")
|| collectionName.startsWith("transformer")
|| collectionName.startsWith("circuit-breaker")) {
// db.getCollection(collectionName).deleteMany({});
// db.runCommand({
// compact: collectionName
// })
db.getCollection(collectionName).drop();
}
}

字段排序

.sort(), 1 增序, -1 降序。

db.getCollection("transformer-1000").find({
"code": "AI801"
}).sort({
"dataTime": -1
}).limit(1000);

hacker

· 阅读需 12 分钟
  1. 动手实践,查看文档反复循环。动手实践可以把脑海中陌生知识转为熟悉技能。阅读文档可以补充新的学习素材。
  2. 学会一个 Linux 基本操作(man、grep、vim、输入输出重定向操作符),编辑器工具,要玩的炉火纯青,每个快捷键烂熟于心。
  3. Desk checking,在编译前检查代码。(code review
  4. 出现 bug 时,思考 2 个问题
    • 哪些设计或编程习惯导致了这个 bug ?
    • 哪些习惯能系统性的预防此类 bug ?
  5. 项目延期就要延个彻底,预留足够多的时间来处理未完成的事情
  6. 砍功能也要彻底,不要想着这个功能以后会用。(删除注释掉的代码同理)
  7. 做工程需要清醒的头脑,不要沉迷于长时间解决某个问题。(10:00 am and 2:00 pm 效率最高

原文

Merc Release 2.1   
Sunday 01 August 1993

Furey mec@shell.portal.com
Hatchet hatchet@uclink.berkeley.edu
Kahn michael@uclink.berkeley.edu

我开 MUD 服务器就是为了学 C 语言编程!

Yeah, right.

本文旨在记录我们的知识、经验和理念。无论您处于什么水平,我们都希望这份文档能帮助您成为更优秀的软件工程师。

请记住,工程实践才是根本,任何文档都无法替代您自己的思考、学习和动手实践。

学习之道

(1) 动手实践
(2) 查阅文档
(3) 继续实践
(4) 再读文档
(5) 深入实践
(6) 反复研读
(7) 持续实践
(8) 温故知新
(9) 明白了吗?

人脑在单次学习中能吸收的新知识量是有限的。动手实践虽然不会带来太多新内容,却能把脑海中的" 陌生知识"转化为"熟悉技能"。阅读文档虽无法让知识变熟悉,却能持续补充新的学习素材。

多数人即便看了文档也很少重温,达到基本够用就止步不前。但现代操作系统、编程语言、网络技术乃至应用软件, 都不可能一蹴而就掌握。必须反复经历"学习-实践"的循环才能真正精通。

环境配置

计算机:运行 Merc 程序的各类主机设备,无论体积大小。每台计算机都有其_制造商_和_型号_标识。以下是您可能会遇到的常见厂商及型号列表:

	Manufacturer	Model
------------ -----
Sun Sun-2
Sun Sun-3
Sun Sun-4
DEC Vax 5000
DEC Vax 5900
IBM RS/6000
NeXT NextCube
Sequent Symmetry
Sequent Balance

就硬件而言,Merc 可在任何 32 位硬件上运行。

操作系统:计算机上运行的最低层级程序。大多数常见计算机运行 Unix 或其变种版本,如 SunOSUltrixAIXMachDynix。注意这些变种名称多以 IX 结尾。

Unix 系统主要分为两大"家族":伯克利 Unix(由著名的加州大学伯克利分校开发)和 System 5 Unix(由 Unix 的鼻祖贝尔实验室开发)。

最常见的非 Unix 操作系统是 VMS(DEC 公司为其 VAX 计算机开发的专有系统)。在个人电脑领域,你会看到 IBM PC 及兼容机使用的 MS-DOS 和 OS/2 系统,以及苹果麦金塔电脑的 MacOS 系统。

先说清楚:VAX不是操作系统,而是 DEC 公司一系列计算机的名称。很多 VAX 机运行 VMS 系统,但运行伯克利 Unix 或 Ultrix 系统的 VAX 机更多。运行 Unix 的 VAX 机与其他运行 Unix 的机器共性更多,反而与运行 VMS 的同系列机型差异更大。

就操作系统兼容性而言,Merc 可在支持伯克利 Unix 版 TCP/IP 网络的 Unix 及其变体系统上运行。它也支持 MS-DOS 系统,但仅限于单用户模式。经过适当修改,Merc 可以移植到任何提供 telnet连接 TCP 服务的操作系统。

编程语言:Merc 采用 C 语言编写。美国国家标准协会(ANSI)制定了 C 语言规范,Merc 完全遵循 ANSI 标准 C 语言规范开发。

最流行的 ANSI 标准 C 编译器是自由软件基金会开发的 GNU gcc编译器,可通过 prep.ai.mit.edu 匿名 FTP 获取。Merc 在 Gcc 1.38 版本下编译良好,因此您可以直接使用 1.42版本,无需安装更庞大的 2.X 系列。

您并非必须使用 gcc 编译器。运行 AIX 操作系统的 IBM RS/6000 已预装 ANSI C 编译器,NeXT 工作站亦是如此(其标准cc编译器实际就是 GNU C 编译器)。任何符合 ANSI 标准的编译器都能正常使用。

遗憾的是,目前仍有大量设备未配备 ANSI 标准 C 编译器(Sun工作站在这方面最为典型)。您可以通过mktrad脚本尝试用非 ANSI(传统)C 编译器编译 Merc,具体操作请参阅 trad.txt 文档。

若不清楚电脑的品牌型号、操作系统以及 C 编译器是 Ansi 还是非 Ansi 标准,您需要先查明这些信息。

Unix 基础工具

man -- 提供在线手册页查询功能

grep -- 全称是"全局正则表达式打印"

viemacsjove -- 编辑器随你挑,但必须玩到炉火纯青,每个快捷键都要烂熟于心

ctags -- 为编辑器生成标签索引,让你能通过函数名直接跳转到源码任意位置

>>><| -- 输入输出重定向操作,要么找人演示,要么自己查man csh手册

这些都是程序员吃饭的家伙什。如果连这些基本功都不扎实,就像开车不会换挡一样寸步难行

调试方法论

调试是门科学。你需要建立假设,基于假设做出预测,运行程序并输入测试数据,观察其行为,最终验证或推翻假设。

优秀的假设能做出令人惊喜且最终应验的预测——这是其他假设无法做到的独特预见。

调试的首要原则是从源头避免制造 bug。这话听着简单,可惜人们总是置若罔闻。

编写程序时若出现任何错误或警告,务必先修正再继续。 C 语言的设计允许许多有缺陷的编码方式合法通过,但足够智能的编译器(比如开启-Wall选项的 gcc)会发出警告。花几分钟检查并修复这些警告代码,能为你省下数小时的排错时间。

1993 年时,"Desk checking"(代码审阅)这门手艺几乎失传了,实在可惜。你应当在编译前就进行代码自查,并定期复查以保持思路清晰、发现新问题。如果团队中有人专职审核他人代码,这个人发现的错误会比其他人加起来都多。

人工逐行检查代码每小时能覆盖数百行。顶尖程序员首轮编写的代码准确率约 99%,即每百行仍有一个漏洞。而你并非顶尖选手... 因此通过桌面检查每小时会发现多个漏洞。这堪称最高效的调试手段——比起在崩溃程序中耗费数小时才能揪出一个错误,效率简直天壤之别。

进阶技巧当属历史悠久的"打印语句调试法"——在代码中插入 print 语句追踪变量值。在 Merc 代码体系中,可调用 printffprintf 在关键节点输出关键数值。何时何处输出这些数值堪称调试艺术,唯有实践方能掌握其中精髓。

若尚未掌握操作系统中的输出重定向技巧,现在正是学习良机。Unix 系统下输入 man csh 命令,重点研读 > 操作符章节。同时必须厘清标准输出(如 printf 输出)与错误输出(如 fprintf 输出)的本质区别。

归根结底,如果不先理解程序的运行机制,就无法真正修复它。强大的调试工具能帮你收集数据,但它们既不能解读数据,也无法解决根本问题——这些只有你能做到。

发现 bug 时...你的第一反应往往是修改代码、消除表象就宣布修复完成。且慢!你看到的 bug 通常只是更深层问题的症状。应该追根究底,彻底参透这个 bug 的价值后,再让它"魂飞魄散"。

此外,发现 bug 时要问自己两个问题:"最初是哪些设计和编程习惯导致了这个问题?"以及:"哪些系统性习惯能预防此类 bug 的产生?"

调试工具篇

当 Unix 进程访问无效内存地址时,或(较罕见地)执行非法指令,或(更罕见地)发生其他异常时,Unix操作系统会接管控制权。该进程无法继续执行且必须被终止。但在终止前,系统会执行一项辅助操作:创建一个名为core的文件,并将该进程的完整数据空间写入其中。

因此,dumping core 并非问题的成因,甚至不是问题的直接表现。这是操作系统为帮助开发者定位导致进程崩溃的致命错误而提供的诊断机制。

开发者需使用调试器分析core文件。Unix 系统最常用的调试器是adbgdb ,偶尔也会遇到dbx。典型启动方式如:adb mercgdb merc core

调试时首先要做且往往唯一需要做的就是获取堆栈追踪。在adb中对应命令是$c,gdb 中则是backtrace

堆栈追踪能显示程序崩溃时所在的函数及其调用链,调试器还会列出这些函数的参数。要正确解析这些参数并运用更高级的调试功能,需要扎实的汇编语言编程功底。

如果你能使用名为Purify的程序...务必掌握其用法。

性能分析

程序性能分析步骤如下:

(1) Remove all the .o files and the merc executable:

rm *.o merc

(2) Edit your makefile, and change the PROF= line:

PROF = -p

(3) Remake merc:

make

(4) 照常运行 merc。当运行足够长时间获得良好的性能分析基准后,使用 shutdown 命令关闭游戏。如果游戏崩溃或从外部终止进程,将无法获取性能分析数据。

(5) 运行prof命令:

prof merc > prof.out

(6) 阅读 prof.out 文件。执行man prof命令了解输出格式说明。

要进行高级性能分析,可在步骤(2)中使用PROF = -pg参数,并在步骤 5 执行 gprof命令。gprof分析工具能生成详细报告,精确显示函数间的调用次数。 这些数据对调试和性能优化都极具价值。profgprof工具的可用性因系统而异。几乎所有 Unix 系统都内置 prof工具,但只有部分系统支持gprof

进度、功能与质量的三角博弈

现在简单谈谈项目管理

几乎所有项目最终都会面临进度、功能与质量的取舍困境。就像学生在截止前夜赶论文时,面临三个痛苦选择:要么迟交(牺牲进度),要么缩减内容(阉割功能),要么胡编乱造(降低质量)。

软件开发同样如此,团队常在三种方案间纠结:要么延期发布,要么砍掉功能,要么硬着头皮按时交付——而最后这种情况往往以失败告终。

这个决定最关键的是要意识到它确实是个决定。别指望会有奇迹发生来逃避。如果你不主动应对,外部环境就会替你做出选择。

假设你面临取舍选择了延期,那就别小打小闹——要延就延个痛快。如果想着"解决这个问题就尽快收尾",事后你准会后悔没多留点时间。但如果说"需要多干一天,干脆延期一周",到周末时完成质量反而更有保障。一次性大幅延期,总比重蹈覆辙地每天每小时拖延强。

如果要砍功能,同样要下狠手。别畏首畏尾地幻想"等有空再做"。这个功能已经彻底出局了,抓住需求简化的机会能省则省!

关于如何降低质量我给不出什么建议,这永远是我在项目中最后才会考虑的妥协方案。

睡眠之道

道理简单却深刻:做工程需要清醒的头脑

连续数小时埋头解决问题既轻松又诱人。人们会进入一种"心流"状态,满脑子都是问题,工作成果源源不断地涌现。许多作家描述过这种体验——仿佛亲眼目睹故事展开,只需将所见记录下来,就能一页接一页地创作。软件工程师们也常有类似感受,代码似乎自发地从指尖流淌而出。

我相信最有价值的工作往往诞生于这种状态。

但根据我的经验,"心流"状态往往在不知不觉中悄然消退。等我反应过来时,新工作已经不再行云流水般从手中产出,反而要花大量时间修正刚犯的错误。原本灵光闪现的头脑开始被各种疑虑和问题占据。

这时候很容易产生"再熬几小时"的冲动。"反正都在这儿了,刚才效率那么高,干脆通宵搞定算了?"千万别上当!这绝对是个陷阱!

我的建议是:回家吃饭、冲澡、睡觉,让自己满血复活。第二天再战。睡眠时大脑会自动处理问题,醒来时往往就有新思路。第二天上午10 点到下午 2 点的高效产出,绝对胜过熬夜到凌晨的混沌状态。

这个策略有个难点:如何重燃晨间斗志。如果是自主选择的项目还好说,但面对不得不做的任务时,就得权衡"早起没干劲"和"熬夜低效率"的利弊了。

程序员必读经典书单

在浩如烟海的编程书籍中,这三本堪称经典:

Kernighan and Plaugher, 《编程风格要素》

Kernighan and Ritchie, 《C程序设计语言》

Brooks, 《人月神话》

scoop

· 阅读需 1 分钟

ref

https://linux.do/t/topic/566873

Install

1. 调整执行策略

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

2. 安装

irm get.scoop.sh | iex

3. 检验是否安装成功

Initializing...
Downloading...
Creating shim...
Adding ~\scoop\shims to your path.
Scoop was installed successfully!
Type 'scoop help' for instructions.
scoop help

Usage

Bucket

buckets 是存储应用程序清单的仓库,每个 bucket 包含了一系列 JSON 文件,每个文件对应一个软件包,描述如何下载、安装以及依赖等信息。

需要有 git 环境

scoop install git
scoop bucket add extras
scoop bucket add java
scoop bucket add nerd-fonts
scoop bucket add versions
scoop bucket add nonportable

更新 scoop 和 buckets

scoop update

更新安装的软件

scoop update *

安装软件

scoop install 7zip
scoop install geekuninstaller
scoop install everything
scoop install fastcopy
scoop install apifox
scoop install localsend
scoop install screentogif
scoop install sumatrapdf

TIMESTAMP 的时间范围

· 阅读需 2 分钟

执行 sql 报错。

UPDATE inspection_plans t SET t.plan_end_time = '2041-04-08 10:41:03' WHERE t.id = 1

错误信息:

Data truncation: Incorrect datetime value: '2041-04-08 10:41:03' for column 'plan_end_time' at row 1

问题原因:TIMESTAMP 的范围是 '1970-01-01 00:00:01' UTC '2038-01-19 03:14:07' UTC

解决方法:将 TIMESTAMP 改为 DATETIME 类型。

alter table inspection_plans modify plan_end_time datetime;

总结:

  • DATE 能够表示的时间范围:1000-01-019999-12-31 ,只记录年月日,不存储时分秒
  • TIME 能够表示的时间范围:'-838:59:59''838:59:59' ,只记录时分秒,不存储年月日
  • DATETIME 能够表示的时间范围:1000-01-01 00:00:009999-12-31 23:59:59 推荐
  • TIMESTAMP 能够表示的时间范围:1970-01-01 00:00:01 UTC2038-01-19 03:14:07 UTC
  • YEAR 能够表示的时间范围:19012155
  • TIMESTAMPDATETIME 的区别:
    • TIMESTAMP 是 UTC 时间,存储时会转换为 UTC 时间,取出时会转换为当前时区的时间
    • DATETIME 是本地时间,存储时不会转换为 UTC 时间,取出时也不会转换为 UTC 时间