嵌入式 - Linux软件编程
目录
一、Linux 系统概述
1.1 操作系统的核心使命
1.2 从 Unix 到 Linux 的演化
1.3 Linux 的应用场景
二、Linux 系统核心:内核与 Shell
2.1 常见的 Linux 发行版
2.2 内核:Linux 的 "大脑"
2.3 Shell:用户与内核的 "翻译官"
三、Shell 命令
3.1 基本文件 / 目录操作命令
3.2 文件内容查看命令
3.3 通配符:批量操作的 "利器"
3.4 管道与重定向:命令协作的 "纽带"
3.5 文件查找命令
3.6 其他常用命令
3.7 压缩与解压命令
3.8 用户与权限管理命令
四、Shell 脚本编程:自动化任务的 "引擎"
4.1 编程语言分类:编译型 vs 解释型
4.2 Shell 脚本编写步骤
4.3 输入与输出
4.4 引号的用法
4.5 变量:数据存储的 "容器"
4.6 分支结构:根据条件执行不同逻辑
4.7 循环结构:重复执行命令
4.8 数组与函数
4.9 实战练习
在当今的软件开发与服务器运维领域,Linux 系统占据着不可替代的地位。从大型服务器集群到嵌入式设备,从云计算平台到移动操作系统(如 Android 基于 Linux 内核),Linux 的身影无处不在。其开源、稳定、高效的特性,使其成为技术从业者必须掌握的技能之一。本文将从 Linux 系统基础讲起,逐步深入到 Shell 命令与脚本编程,帮助你快速入门 Linux 软件编程世界。
一、Linux 系统概述
1.1 操作系统的核心使命
操作系统的本质是 "硬件与应用程序的桥梁"—— 它屏蔽了底层不同硬件平台的差异,为上层应用提供统一的接口,让开发者无需关注硬件细节即可编写程序。这种抽象能力,是现代计算机系统高效运行的基础。
1.2 从 Unix 到 Linux 的演化
世界上第一款操作系统是 Unix,诞生于 20 世纪 60 年代的贝尔实验室。而 Linux 则是对 Unix 的 "致敬与超越"——1991 年,芬兰大学生林纳斯・托瓦兹(Linus Torvalds)为了打造一个 "自由的类 Unix 系统",重写了 Unix 内核,由此诞生了 Linux。
与 Unix 不同,Linux 的发展紧密依托开源社区。其中,GNU 项目(GNU's Not Unix)功不可没 —— 它是一个旨在开发自由软件的运动,其遵循的 GPL 协议(通用公共许可证)确保了软件的开源性:任何人可以自由使用、修改和分发,但衍生作品必须保持开源。如今,Linux 内核与 GNU 组件(如 gcc 编译器、bash shell 等)共同构成了我们日常使用的 Linux 系统,因此也常被称为 "GNU/Linux"。
1.3 Linux 的应用场景
Linux 的灵活性使其能适应多种场景:
- 服务器领域:全球超 80% 的服务器采用 Linux 系统(如阿里云、AWS 等云计算平台),因其稳定性和安全性远超其他系统;
- 嵌入式设备:智能手表、路由器、车载系统等多采用 Linux 内核,轻量化版本(如 Buildroot)可满足资源受限需求;
- 开发环境:程序员常用的 Ubuntu、CentOS 等发行版,提供了丰富的开发工具链,支持 C/C++、Python 等主流语言。
二、Linux 系统核心:内核与 Shell
2.1 常见的 Linux 发行版
Linux 本身指的是内核,而我们日常使用的 "Linux 系统" 是 "内核 + 应用程序" 的发行版(Distribution)。常见的有:
- Ubuntu:桌面用户友好,社区活跃,适合初学者;
- Debian:以稳定性著称,是许多发行版的基础(如 Ubuntu);
- Redhat/CentOS:企业级首选,支持长期维护,适合服务器;
- Fedora:前沿技术尝鲜,更新快,适合开发者。
2.2 内核:Linux 的 "大脑"
内核是操作系统的核心,负责管理硬件资源和提供基础功能,主要包括:
- 内存管理:分配 / 回收进程内存,防止内存泄漏;
- 多任务管理:通过进程调度实现多程序并发(如 CPU 时间片分配);
- 文件系统管理:支持 ext4、btrfs 等格式,管理文件的创建 / 删除 / 读写;
- 多任务通信:提供管道、信号、共享内存等机制,实现进程间协作;
- 网络管理:支持 TCP/IP 协议栈,处理网络数据包;
- 硬件设备管理:通过驱动程序与硬盘、网卡等硬件交互。
2.3 Shell:用户与内核的 "翻译官"
Shell 是包裹在内核外层的命令解释器,其核心作用有两点:
- 保护内核:防止用户直接操作内核导致异常(如误删系统文件);
- 命令翻译:将用户输入的命令转换为内核能理解的代码,再将执行结果返回给用户。
常见的 Shell 有 bash(Bourne Again SHell,大多数 Linux 默认)、zsh(功能更丰富,支持插件)、ksh 等。用户通过 Shell 与系统交互的流程为:用户输入命令→Shell 解析→内核执行→Shell 返回结果。
三、Shell 命令
Shell 命令是操作 Linux 的基础,掌握常用命令能极大提升效率。以下按功能分类整理:
3.1 基本文件 / 目录操作命令
命令 | 功能 | 示例 |
---|---|---|
ls | 查看目录下文件 / 文件夹 | ls -l (显示详细信息)、ls -a (显示隐藏文件) |
cd | 切换目录 | cd /home (进入 /home 目录)、cd ~ (回到家目录) |
touch | 创建空文件 | touch test.txt (创建 test.txt) |
rm | 删除文件 | rm test.txt (删除文件)、rm -f test.txt (强制删除,不提示) |
mkdir | 创建文件夹 | mkdir demo (创建 demo 文件夹)、mkdir -p a/b/c (递归创建多级目录) |
rmdir | 删除空文件夹 | rmdir demo (删除空的 demo 文件夹,非空需用rm -r ) |
cp | 拷贝文件 / 目录 | cp src.txt dest.txt (拷贝文件)、cp -r src_dir dest_dir (拷贝目录) |
mv | 移动 / 重命名 | mv file.txt dir/ (移动文件到 dir)、mv old.txt new.txt (重命名) |
3.2 文件内容查看命令
- cat:查看文件全部内容,适合小文件。
cat 文件名
- 示例:
cat README.md
(直接显示内容)、cat -n test.txt
(显示行号); - head:查看文件开头内容,默认前 10 行。
head -n 行数 文件名
- 示例:
head -n 5 log.txt
(查看前 5 行); - tail:查看文件末尾内容,默认后 10 行,常用于跟踪日志。
tail -n 行数 文件名
- 示例:
tail -n 20 access.log
(查看后 20 行)、tail -f log.txt
(实时刷新最新内容)。
3.3 通配符:批量操作的 "利器"
通配符用于匹配多个文件,常与 ls、rm 等命令搭配:
*
:匹配任意长度、任意字符。- 示例:
ls *.sh
(列出所有.sh 脚本);
- 示例:
?
:匹配 1 个任意字符。- 示例:
ls file_??.txt
(匹配 file_后接 2 个字符的 txt 文件,如 file_ab.txt);
- 示例:
[]
:匹配 1 个指定字符。- 示例:
ls file_[1-5].txt
(匹配 1-5 数字,如 file_3.txt) ls file_[^3].txt
(排除 3,如 file_1.txt、file_2.txt)ls file_[1,3,5].txt
(指定 1、3、5,如 file_5.txt)。
- 示例:
3.4 管道与重定向:命令协作的 "纽带"
- 管道(|):将前一个命令的输出作为后一个命令的输入。
- 示例:
ls /usr/bin | grep "python"
(在 /usr/bin 下查找含 python 的文件)ps aux | grep "nginx"
(查看 nginx 进程);
- 示例:
- 重定向:将输出内容定向到文件(默认输出到终端):
- 覆盖重定向(>):清空原文件内容,写入新内容。示例:
echo "hello" > test.txt
(test.txt 内容变为 hello); - 追加重定向(>>):在原文件末尾添加内容。示例:
echo "world" >> test.txt
(test.txt 变为 hello\nworld)。
- 覆盖重定向(>):清空原文件内容,写入新内容。示例:
3.5 文件查找命令
- find:在指定目录下查找文件,功能强大。
- 示例:
find . -name "*.c"
(当前目录查找所有.c 文件) find /home -type f -mtime -7
(/home 下查找 7 天内修改的普通文件)find . -type f -print0 | xargs -0 grep -l "printf(字符串)"
(查找含 printf 的文件);
- 示例:
- whereis:查找二进制程序(命令)的位置。
- 示例:
whereis gcc
(显示 gcc 的安装路径)。
- 示例:
3.6 其他常用命令
- echo:在终端输出内容,常用于打印变量。
- 示例:
echo "Hello Linux"
、echo $PATH
(打印环境变量 PATH);
- 示例:
- grep:查找文件中含指定字符串的行,支持正则。
- 示例:
grep "error" log.txt
(查找 error 行)、grep -i "Warning" test.txt
(忽略大小写)。
- 示例:
3.7 压缩与解压命令
Linux 中常见压缩格式为.tar.gz(兼顾速度与压缩率)和.tar.bz2(压缩率更高):
- .tar.gz:
- 压缩:
tar -zcvf docs.tar.gz ./documents
(将 documents 目录压缩为 docs.tar.gz); - 解压:
tar -zxvf docs.tar.gz
(解压到当前目录);
- 压缩:
- .tar.bz2:
- 压缩:
tar -jcvf data.tar.bz2 ./data
; - 解压:
tar -jxvf data.tar.bz2
。
- 压缩:
3.8 用户与权限管理命令
Linux 是多用户系统,权限管理是安全的核心:
- 用户管理:
useradd
:创建用户- 示例:
sudo useradd -m tom
(-m 自动创建家目录);
- 示例:
userdel
:删除用户- 示例:
sudo userdel -r tom
(-r 删除家目录);
- 示例:
passwd
:修改密码- 示例:
sudo passwd tom
(为 tom 设置密码);
- 示例:
su
:切换用户- 示例:
su root
(切换到 root,exit
退出当前用户);
- 示例:
- 权限管理:
chmod
:修改文件权限,权限用 3 组 rwx(读写执行)表示,对应数字为 r=4、w=2、x=1。示例:chmod 755 script.sh
(所有者 rwx,同组 r-x,其他人 r-x);
chmod 权限值 文件名
0664
110 110 100
rw- rw- r--
rwx:创建该文件的用户对文件是否拥有读写执行权限
rwx:创建文件同组的用户对文件是否拥有读写执行权限
rwx:其余人是否拥有读写执行权限
chown
:修改文件所属用户,示例:sudo chown tom file.txt
(file.txt 归属 tom);c
hgrp
:修改文件所属组,示例:sudo chgrp devs file.txt
(file.txt 归属 devs 组)。
四、Shell 脚本编程:自动化任务的 "引擎"
Shell 脚本是一系列 Shell 命令的集合,可实现任务自动化(如批量处理文件、定时任务等)。
4.1 编程语言分类:编译型 vs 解释型
- 编译型:先通过编译器将代码转换为机器码,再运行(如 C、C++、Java)。优点是执行效率高,适合计算密集型任务;缺点是开发效率低,需重新编译才能生效;
- 解释型:边解释边执行,无需编译(如 Shell、Python)。优点是开发效率高,适合系统管理;缺点是执行效率较低。
4.2 Shell 脚本编写步骤
- 编写脚本文件:用 vim 创建.sh 文件,首行指定解释器(
#!/bin/bash
表示用 bash 执行); 示例:vim hello.sh
,内容:#!/bin/bash echo "Hello Shell!"
- 添加执行权限:用
chmod +x hello.sh
赋予可执行权限; - 运行脚本:
./hello.sh
(当前目录执行)或bash hello.sh
(指定解释器)。
4.3 输入与输出
- 输入(read):从终端获取用户输入并赋值给变量。示例:
- #从终端接收用户输入放入filename变量中
- read filename
-
read -p "请输入文件名:" filename # -p显示提示信息 echo "你输入的文件是:$filename"
- 输出(echo):打印变量或字符串。示例:
echo "当前目录:$PWD"
($PWD 是环境变量,表示当前路径)。 - #将变量filename中的内容打印在屏幕上
- echo $filename
4.4 引号的用法
Shell 中引号功能不同,需注意区分:
- 单引号('):原样输出内容,不解析变量。
- 示例:
echo '$filename'
(输出 $filename); - 双引号("):解析变量后输出。
- 示例:
echo "$filename"
(输出变量值); - ** 倒引号(`)
**:执行引号中的命令,返回结果。
示例:
echo `seq 10`
4.5 变量:数据存储的 "容器"
- 环境变量:Shell 自带的变量,如
$HOME
(家目录)、$PATH
(命令搜索路径)、$PWD
(当前目录); - 位置变量:执行脚本时传入的参数,
$0
为脚本名,$1
-$n
为参数,$#
为参数个数,$?
为上一条命令的返回值(0 表示成功);
$0 :脚本的名称
$1 :执行脚本时传入的参数1
$2 :执行脚本时传入的参数2
$# :传入参数的个数
$? :上一条shell语句的执行结果
$$ :脚本运行的进程编号
-
count=10; echo $count
(输出 10)。
4.6 分支结构:根据条件执行不同逻辑
- if 分支:基本结构:
条件可用 test 命令或if [ 条件 ]; then# 条件为真时执行 else# 条件为假时执行 fi
[]
(注意空格),常用判断符:-gt
(大于)、-lt
(小于)、-eq
(等于)、-e 文件
(文件存在)等;
-gt #大于
-lt #小于
-ge #大于等于
-le #小于等于
-eq #等于
-ne #不等于
-b #检测文件是否存在,并判断是否为块设备
-c #检测文件是否存在,并判断是否为字符设备
-d #检测文件是否存在,并判断是否为目录文件
-e #检测文件是否存在
-f #检测文件是否存在,并判断是否为普通文件
-L #检测文件是否存在,并判断是否为链接文件
-p #检测文件是否存在,并判断是否为管道文件
-S #检测文件是否存在,并判断是否为套接字文件
- case 分支:多条件匹配,适合枚举场景:
case $num in1) echo "选择1" ;;2) echo "选择2" ;;*) echo "其他" ;; # 默认分支 esac
4.7 循环结构:重复执行命令
- while 循环:条件为真时重复执行:
i=1 while [ $i -le 5 ]; doecho $ii=$((i+1)) # 变量自增 done
- until 循环:条件为假时重复执行(与 while 相反);
- for 循环:遍历数据集:
# 遍历列表 for fruit in apple banana orange; doecho $fruit done# 数字范围 for ((i=1; i<=3; i++)); doecho $i done
4.8 数组与函数
- 数组:存储多个元素,示例:
array=("a" "b" "c") echo ${array[0]} # 输出a(下标从0开始) echo ${array[*]} # 输出所有元素:a b c echo ${#array[@]} # 输出长度:3
- 函数:封装可复用的代码块,示例:
add() {sum=$(( $1 + $2 )) # $1、$2为参数echo $sumreturn $sum # 返回值(0-255) }add 3 5 # 调用函数,输出8
4.9 实战练习
需求:在 stdio.h 的后 200 行中查找含 "extern" 的内容,写入 record.txt。
命令:tail -n 200 stdio.h | grep "extern" > record.txt
解析:tail -n 200
取后 200 行,管道传给grep "extern"
筛选行,>
重定向到 record.txt。