第一个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 \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 管理项目,以实现工程化目标。

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

相关推荐
AlfredZhao13 小时前
vi 删除指定范围的行,不用再反复按 dd
linux·vi
用户97183563346619 小时前
银河麒麟 KY10 申威(SW64) 安装 nginx-1.16.1-2.p01.ky10.sw_64.rpm 详细步骤
linux
猪脚踏浪20 小时前
linux 拷贝文件或目录到指定的位置
linux
大树882 天前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠2 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
霸道流氓气质2 天前
领域驱动设计(DDD)在 Spring Boot 微服务中的实践指南
运维·spring boot·微服务
bush42 天前
嵌入式linux学习记录十四、术语
linux·嵌入式
载数而行5202 天前
Linux 11 动态监控指令top
linux
小宇宙Zz2 天前
Maven依赖冲突
java·服务器·maven
Inhand陈工2 天前
基于台达PLC与映翰通IG502的智慧水产养殖精准投喂与远程运维解决方案
运维·人工智能·物联网·阿里云·信息与通信