第一个Linux程序

摘要

1、前言

如果你已经在 Linux 下学过一段时间开发工具,那么你很可能处在这样一个阶段:

你知道如何用 gcc 编译一个 .c 文件,你知道 Makefile 能自动化构建,你用过 gdb 调试程序,你写过一点 Bash 脚本,你也会用 Git 管理代码。

但你依然不确定: "我到底算不算真的会在 Linux 下做开发?"

这并不是你的问题,而是大多数 Linux 新手都会经历的阶段。

1.1、碎片化学习,无法自动拼成 "工程能力"

在学习 Linux 的过程中,我们往往是按工具来学习的

  • 一篇讲 gcc
  • 一篇讲 Makefile
  • 一篇讲 Git
  • 一篇讲 Bash
  • 一篇讲 Python

每一篇单独看,似乎都 "学会了";但当真正让你从零开始做一个小项目时,却会发现:

  • 不知道从哪一步开始
  • 不知道什么时候该引入 Makefile
  • 不知道代码写到什么程度才算 "工程化"
  • 不知道 Git 的提交该如何组织

原因只有一个:工程能力不是工具能力的简单叠加。

1.2、为什么是 "第一个 Linux 小程序"

这篇文章选择带你完成的,并不是一个复杂的系统,也不是一个炫技的项目,而是一个:

  • 需求真实
  • 结构清晰
  • 可运行、可维护、可扩展
  • 完整走完 Linux 开发流程的小程序

它的意义不在于功能本身,而在于------

你将第一次完整经历:从一个想法,到一个 "像样的 Linux 项目" 的全过程。

1.3、这不是 "写代码",而是 "完成一次工程闭环"

在这篇文章中,你将亲手经历:

  • C / C++ 编写核心逻辑
  • gcc / g++ 编译程序
  • Makefile 管理构建
  • gdb 调试问题
  • Bash 把程序放进 Linux 工作流
  • Python 编写辅助工具
  • Git 管理整个项目的演进

这些内容,你可能已经在之前的文章中分别学过,但这是第一次------它们被放进同一个真实项目中。

1.4、本篇文章适合谁阅读

这篇文章非常适合以下读者:

  • 已经学过 Linux 基础命令,但还没做过完整项目
  • 学过 gcc / Makefile / Git,却感觉 "还是不会用"
  • 想把零散知识整合成真正工程能力的开发者
  • 想为后续 CMake、复杂工程、系统编程打基础的人

如果你完全没有接触过 Linux,这篇文章可能会稍显密集;但如果你已经有一定基础,它将恰好把你推过那道关键的门槛

1.5、你将收获什么

读完并亲手完成这个小程序后,你应该能够明确地说出:

  • 一个 Linux 项目从零开始应该如何组织
  • 每一个工具在工程中的 "最佳出场时机"
  • 为什么工程不是 "代码写完就结束"
  • 自己下一步该如何继续进阶

1.6、开始之前的一点提醒

请不要只是 "看完这篇文章"。

请边看,边敲,边犯错,边修正。

因为只有当你亲手完成第一个 Linux 小程序时,你才会真正意识到:

Linux 开发,不是学会工具,而是学会把工具组合成工程。

接下来,让我们从这个小程序的需求开始。

2、这个 "小程序" 要解决什么问题

在真正动手写代码之前,我们必须先回答一个看似简单、但极其重要的问题:

这个小程序,到底要解决什么问题?

很多初学者在练习时,习惯直接写 "演示代码" ------ 打印几行输出、验证语法、跑通编译流程。这些练习当然有价值,但它们有一个致命缺陷: **它们不像"真实世界中的程序"。**而我们这一篇文章的目标,恰恰相反。

2.1、为什么一定要有 "真实问题"

真实问题意味着:

  • 有明确输入
  • 有明确输出
  • 有失败情况
  • 有使用场景

只有在这样的前提下,后续的工具 ------ gcc、Makefile、gdb、Bash、Git ------ 才会自然地登场,而不是被强行展示。如果程序本身没有复杂度,那么工程工具也就失去了意义。

2.2、我们选择解决的问题:一个 Linux 命令行小工具

综合 "新手友好性" 和 "工程完整度",本文选择实现这样一个小程序:

一个用于统计文件或目录信息的 Linux 命令行工具

它的职责并不复杂,但足够真实:

  • 接收命令行参数
  • 读取文件或遍历目录
  • 统计并输出结果
  • 在错误发生时给出合理提示

你可以把它理解为一个 "简化版的 Linux 系统工具"

2.3、功能范围的明确界定(非常重要)

为了避免项目失控,我们必须明确做什么、不做什么

2.3.1、本程序"要做的事"

  • 接收一个路径作为参数
  • 判断该路径是文件还是目录
  • 如果是文件:
    • 统计行数、字符数、字节数
  • 如果是目录:
    • 遍历目录下的普通文件
    • 汇总统计信息
  • 将结果输出到终端

2.3.2、本程序"刻意不做的事"

  • 不做图形界面
  • 不处理网络
  • 不考虑多线程
  • 不追求极致性能

这些内容不是不重要,而是现在不重要

2.4、使用方式设计:先像用户一样思考

在写任何一行代码前,我们先定义程序的 "使用方式"。

例如:

复制代码
$ mytool test.txt
Lines: 120
Words: 856
Bytes: 6231

或者:

复制代码
$ mytool ./src
Files: 12
Lines: 3450
Words: 21034
Bytes: 154320

这样做有两个好处:

  1. 程序接口在一开始就被固定下来
  2. 后续模块划分会更自然

2.5、错误场景同样是需求的一部分

一个 "真实程序" 必须考虑失败情况:

  • 参数缺失
  • 路径不存在
  • 权限不足
  • 读取失败

例如:

复制代码
$ mytool
Error: missing path argument
$ mytool /root/secret
Error: permission denied

这些输出,同样属于程序功能的一部分

2.6、为什么这个问题非常适合新手工程实践

选择这个小程序,并不是偶然。

它天然适合串联我们之前学过的所有内容:

能力 在本程序中的体现
C/C++ 文件操作、字符串处理
gcc/g++ 多文件编译
Makefile 自动化构建
gdb 调试文件读取问题
Bash 管道、重定向、批量执行
Python 辅助测试与分析
Git 管理整个开发过程

它小,但不 "玩具";它简单,但不 "随意"。

2.7、小结:从 "写代码" 转向 "做程序"

在这一章,我们并没有写一行代码,却做了三件非常重要的事:

  1. 明确了程序的存在意义
  2. 固定了程序的使用接口
  3. 控制了项目的复杂度边界

这正是工程开发的第一步。

接下来,我们将真正进入编码阶段,从一个最小可运行的程序开始,一步步把它打磨成一个真正的 Linux 小项目

3、准备开发环境(复习 + 实战)

在真正开始写这个 Linux 小程序之前,我们需要先停下来,认真完成一件事:

把开发环境准备成 "随时可以写工程" 的状态。

这一步看似基础,却往往决定了后面整个学习过程是顺畅,还是不断被打断。

3.1、为什么开发环境不是 "装完就算"

很多新手会认为:

"我已经装了 gcc,也能编译 hello world,环境应该没问题了。"

但真正做项目时,你很快会发现:

  • 缺调试符号,gdb 无法使用
  • make 存在,但版本不一致
  • Git 已装,却没有配置身份
  • Bash 脚本执行失败,不知道为什么

环境不完整,工程就无法完整。

3.2、Linux 系统与基础要求

本文默认你已经具备以下条件:

  • 一个主流 Linux 发行版(Ubuntu / Debian / CentOS / Arch 等)
  • 能熟练使用终端
  • 能进行基本的软件安装

如果你使用的是虚拟机、WSL 或远程服务器,本章内容同样适用。

3.3、编译工具链:gcc / g++

3.3.1、安装与版本确认

检查 gcc 是否存在:

复制代码
gcc --version

同样检查 g++:

复制代码
g++ --version

如果不存在,需要安装编译工具链:

复制代码
sudo apt install build-essential

或对应发行版的包管理命令。

3.3.2、为什么版本并非 "越新越好"

在工程实践中,更重要的是:

  • 稳定
  • 可复现
  • 与系统库兼容

因此,新手阶段不建议频繁更换编译器版本。

3.4、Make 与构建环境准备

确认 make 是否可用:

复制代码
make --version

make 是后续工程化构建的基础,它的存在意味着:

  • 构建步骤可以被脚本化
  • 编译逻辑可以被管理

如果你只能靠手敲 gcc,那么你还停留在 "练习阶段"。

3.5、调试工具:gdb

检查 gdb:

复制代码
gdb --version

如果没有安装:

复制代码
sudo apt install gdb

提醒

后续编译时一定要记得加 -g,否则 gdb 将无法显示源码信息。

调试工具不是 "出问题再装",而是一开始就必须存在

3.6、版本管理工具:Git

3.6.1、Git 是否已安装

复制代码
git --version

3.6.2、基本配置(新手极易忽略)

复制代码
git config --global user.name "YourName"
git config --global user.email "you@example.com"

没有这一步,Git 依然能用,但提交将是不完整的

3.7、Bash 环境与执行权限

虽然 Bash 是 Linux 默认 shell,但仍需注意:

  • 脚本是否有执行权限
  • #!/bin/bash 是否正确

测试一个最小脚本:

复制代码
#!/bin/bash
echo "Environment ready"

赋予执行权限:

复制代码
chmod +x test.sh
./test.sh

理解权限,是 Linux 工程的基础素养。

3.8、Python:辅助工具而非主角

确认 Python 版本:

复制代码
python3 --version

Python 在本文中的定位是:

  • 自动化测试
  • 数据生成
  • 输出分析

我们不追求复杂语法,只追求快速、稳定、可复用

3.9、建立项目工作目录(实战开始)

现在,我们正式为这个小程序创建一个工作空间:

复制代码
mkdir my_first_linux_tool
cd my_first_linux_tool

建议的初始结构:

复制代码
my_first_linux_tool/
├── src/
├── include/
├── build/
├── scripts/
└── README.md

此时还没有代码,但工程的骨架已经出现

3.10、环境自检清单(强烈建议执行)

你现在应该能顺利完成以下操作:

  • gcc --version
  • make --version
  • gdb --version
  • git status
  • 执行一个 Bash 脚本
  • 运行一个 Python 脚本

如果有任何一步失败,现在解决,永远比后面省时间

3.11、小结

这一章,我们并没有进入代码,却完成了三件关键的事:

  1. 确认所有工程工具都已就位
  2. 建立了一个可扩展的项目目录结构
  3. 从 "试验环境" 切换到 "工程环境"

接下来,我们将真正开始写代码,从一个最小可运行的程序入手,一步步把它发展成一个完整的 Linux 小项目。

4、从一个 .c/.cpp 文件开始

当我们准备好开发环境后,下一步就是开始动手写代码。这一章的目标是:

从一个最简单的 C 或 C++ 文件开始,逐步实现一个最小可运行程序

在这个过程中,我们将专注于最小的可执行程序,并在此基础上打好工程化的基础。

4.1、创建第一个 .c.cpp 文件

对于这个小程序,我们可以选择 CC++,根据个人偏好或者项目需求来定。如果你不确定,建议先用 C 来写,因为它更为简洁,适合用于教学。

示例:main.c

在项目目录中,创建一个名为 main.c 的文件:

复制代码
touch main.c

然后,打开文件并编写一个简单的 main() 函数:

复制代码
#include <stdio.h>

int main(int argc, char *argv[]) {
    printf("Hello, Linux World!\n");
    return 0;
}

这个文件只有一行输出,功能非常简单:

  • printf 输出一行文本:"Hello, Linux World!"
  • main 函数是程序的入口点

4.2、编译并运行第一个程序

4.2.1、手动编译

使用 gcc(或 g++ 如果是 C++)编译这个文件。首先,在终端中运行以下命令:

复制代码
gcc -o hello main.c
  • gcc 是 GNU 编译器
  • -o hello 参数指定了编译后生成的可执行文件名称(这里是 hello
  • main.c 是我们刚才创建的源代码文件

如果没有错误,你将看到一个名为 hello 的可执行文件。现在可以运行它:

复制代码
./hello

你会看到输出:

复制代码
Hello, Linux World!

这就是你编写的第一个 Linux 程序的执行结果。

4.2.2、解释编译过程

在这一步,gcc 完成了以下几个任务:

  1. 预处理 :将所有包含的头文件(如 #include <stdio.h>)替换成相应的代码。
  2. 编译:将 C 代码转换成汇编语言。
  3. 汇编:将汇编语言转化为机器语言(目标文件)。
  4. 链接:将目标文件和库文件链接成最终的可执行文件。

4.3、为什么要从一个 .c 文件开始?

虽然这只是一个简单的 printf 示例,但它有重要的作用:

  1. 熟悉 C 编译流程:从源代码到执行文件的完整流程。
  2. 调试的基础:即使程序非常简单,也能熟悉调试器的使用。
  3. 输出验证:通过简单的输出确认程序能正常工作。

4.4、扩展功能:命令行参数处理

为了让程序更有实际意义,我们将扩展它,使其支持命令行参数。命令行参数可以让用户在执行程序时传递数据。

示例:命令行参数处理

更新 main.c 以支持命令行参数:

复制代码
#include <stdio.h>

int main(int argc, char *argv[]) {
    if (argc < 2) {
        printf("Usage: %s <filename>\n", argv[0]);
        return 1;
    }

    printf("Hello, %s!\n", argv[1]);
    return 0;
}

这个程序实现了以下功能:

  • argc 表示命令行参数的个数(包括程序本身)
  • argv 是一个字符串数组,存储了所有命令行参数
  • 如果没有提供参数,程序会提示用户正确的使用方法
  • 如果提供了参数,程序将打印 "Hello, [参数]!"

运行示例

编译程序:

复制代码
gcc -o greet main.c

执行程序并传递一个参数:

复制代码
./greet World

输出将是:

复制代码
Hello, World!

4.5、代码拆分:从单一文件到模块化结构

随着程序逐渐复杂化,单个文件变得难以管理。我们将 拆分代码,让项目结构更加清晰。

4.5.1、拆分 .h.c 文件

  1. 创建 greet.h 头文件,声明函数:

    #ifndef GREET_H
    #define GREET_H

    void greet_user(char *name);

    #endif

  2. 创建 greet.c 文件,定义函数:

    #include <stdio.h>
    #include "greet.h"

    void greet_user(char *name) {
    printf("Hello, %s!\n", name);
    }

  3. 修改 main.c

    #include <stdio.h>
    #include "greet.h"

    int main(int argc, char *argv[]) {
    if (argc < 2) {
    printf("Usage: %s <name>\n", argv[0]);
    return 1;
    }

    复制代码
     greet_user(argv[1]);
     return 0;

    }

这样,你的项目结构将变成:

复制代码
my_first_linux_tool/
├── src/
│   ├── main.c
│   └── greet.c
├── include/
│   └── greet.h

4.5.2、编译多文件

现在,你有多个源文件。你可以用 gcc 来编译这些文件:

复制代码
gcc -o greet main.c greet.c

通过这种方式,我们已经将功能拆分为模块,并能方便地管理和扩展。

4.6、小结

这一章,我们从头开始:

  • 编写了一个最小的 C 程序
  • 手动编译并运行程序
  • 添加了命令行参数支持
  • 拆分了代码,建立了基本的模块化结构

接下来的步骤,我们将进一步优化构建流程,开始使用 Makefile 管理项目,以实现工程化目标。

通过这一过程,你不仅学到了如何编写一个简单的程序,也为后续的调试、构建和管理打下了坚实的基础。

相关推荐
小白冲鸭11 小时前
苍穹外卖-前端环境搭建-nginx双击后网页打不开
运维·前端·nginx
fiveym12 小时前
CPU睿频与核心核心问题全解析
运维·硬件架构
天码-行空12 小时前
【大数据环境安装指南】HBase集群环境搭建教程
大数据·linux·运维·hbase
天空之外13612 小时前
生成一个带 IP 的自签证书、制作Http证书
linux·运维·服务器
广州服务器托管12 小时前
[2026.1.6]WINPE运维版20260106,带网络功能的PE维护系统
运维·开发语言·windows·计算机网络·个人开发·可信计算技术
希赛网12 小时前
华为认证HCIP数通备考资源、模拟练习题库哪里下载?
服务器·网络工程师·华为认证·hcip
恒创科技HK12 小时前
2026年香港服务器走CN2线路具有哪些优势?
运维·服务器
释怀不想释怀12 小时前
linux常见安装(JDK,mysql,nginx)
linux·运维·服务器
杰克崔12 小时前
do_exit的hungtask问题及coredump的实验及原理分析一
linux·运维·服务器·车载系统
BigBigHang12 小时前
【docker】cloudbeaver的docker-compose及一些踩坑
运维·docker·容器