一、前言

在学习 C 语言之后,如果希望进一步进行嵌入式开发、服务器开发或者 Linux 下的 C/C++ 开发,仅仅掌握 C 语言语法是不够的。

我们还需要了解:

  • Linux 操作系统的基本概念;

  • Linux 文件系统;

  • Linux 常用命令;

  • Shell;

  • GCC 编译器;

  • GDB 调试工具;

  • Valgrind 内存检测工具;

  • 静态库和动态库;

  • Makefile;

  • 多文件程序编译。

这些内容共同构成了 Linux 软件开发的基础。

本文主要根据学习资料中的 Linux软件编程部分进行整理,将这些知识串联起来,形成一套比较完整的 Linux 软件开发入门知识体系。


二、什么是操作系统?

操作系统本质上也是一种软件。

它的一个重要作用是:

屏蔽底层不同硬件平台的差异,为上层应用程序提供统一的接口。

例如我们编写一个 C 程序时,并不需要直接操作 CPU、内存控制器、硬盘控制器等硬件,而是通过操作系统提供的接口完成相关操作。

常见的 PC 操作系统主要包括:

操作系统
├── Windows
├── Linux
└── Unix

Linux 在服务器和嵌入式领域具有非常广泛的应用。资料中也将 Linux 的典型应用场景归纳为服务器和嵌入式系统


三、Linux操作系统

Linux 最重要的部分就是:

Linux Kernel(Linux内核)

Linux 内核主要负责管理计算机的各种硬件资源,并向上层软件提供服务。

根据学习资料,Linux 内核主要涉及以下五个方面:

Linux内核
│
├── 内存管理
├── 多任务调度
├── 文件系统管理
├── 多任务间通信
└── 网络通信

其中 Linux 文件系统有一个非常经典的特点:

Linux系统中一切皆是文件。

也就是说,普通文件、设备以及某些通信资源等,都可以通过文件的形式进行统一管理。


四、Linux内核、系统调用、Shell和库函数

学习 Linux 软件编程时,一个非常重要的概念就是:

应用程序
    ↓
库函数
    ↓
系统调用
    ↓
Linux内核
    ↓
硬件

4.1 Linux内核

Linux 内核负责:

  • 内存管理;

  • 进程调度;

  • 文件管理;

  • 网络通信;

  • 进程间通信等。

应用程序一般不能直接操作硬件,而是通过内核提供的功能完成操作。


4.2 系统调用

系统调用是 Linux 内核向用户程序提供的接口。

例如:

open()
read()
write()
close()
fork()

这些接口可以让应用程序请求操作系统完成相应任务。

资料中将系统调用概括为:

Linux 内核中的函数接口,功能强大,但比较简练。


4.3 库函数

库函数可以理解为对系统调用进行进一步封装。

例如 C 语言中的:

printf()
scanf()
malloc()
free()

这些函数使用起来比直接进行底层系统调用更加方便。

因此可以简单理解为:

系统调用:更底层
    ↑
库函数:更加方便
    ↑
应用程序:直接使用

库函数通常具有更好的通用性,而系统调用则与具体操作系统关系更加密切。


五、什么是Shell?

Shell 可以理解为:

用户与 Linux 操作系统之间的命令解释器。

用户在终端输入:

ls

Shell 接收到命令之后进行解释,再调用相应的系统功能。

因此可以理解为:

用户
 ↓
Shell
 ↓
系统调用
 ↓
Linux内核
 ↓
硬件

Shell 的主要作用包括:

  1. 保护内核

  2. 命令解释器

学习资料中也将 Shell 定义为通过一系列命令完成 Linux 内核功能的命令解释器。


六、Linux常用Shell命令

掌握 Linux 软件编程之前,首先需要熟悉一些基本命令。


6.1 ls:查看文件

ls

查看当前目录下的文件。

常用:

ls -l

查看详细文件信息。

ls -a

查看包括隐藏文件在内的所有文件。


6.2 touch:创建文件

touch test.txt

创建一个普通文件。


6.3 mkdir:创建目录

mkdir test

创建 test 目录。


6.4 rm:删除文件

rm test.txt

删除普通文件。

如果需要删除目录及其内部内容:

rm -rf test

⚠️ rm -rf 删除操作具有较高风险,使用时一定要确认路径。


6.5 cp:复制文件

复制普通文件:

cp a.txt /home/linux/

复制目录:

cp test /home/linux/ -rf

6.6 mv:移动和重命名

移动文件:

mv a.txt /home/linux/

重命名:

mv old.txt new.txt

因此 mv 既可以用于移动文件,也可以用于修改文件名。


6.7 cd:切换目录

cd 目录

例如:

cd /home/linux

返回上一级:

cd ..

进入当前用户家目录:

cd ~

进入根目录:

cd /

6.8 pwd:查看当前路径

pwd

可以查看当前所在目录的绝对路径。


七、Linux文件类型

Linux 中可以通过 ls -l 查看文件的详细信息。

例如:

ls -l

可能看到:

drwxr-xr-x
-rw-r--r--

第一个字符表示文件类型。

常见类型:

符号 含义
- 普通文件
d 目录
l 链接文件
b 块设备文件
c 字符设备文件
s Socket文件
p 管道文件

资料中也特别强调了 Linux 中的 socketpipe 文件,它们与进程间通信密切相关。


八、Linux文件权限

Linux 文件权限主要有三类:

r —— read    读
w —— write   写
x —— execute 执行

例如:

rwxr-xr--

可以拆成:

rwx | r-x | r--
 ↓     ↓     ↓
用户   用户组  其他用户

含义:

用户:   读 + 写 + 执行
用户组: 读 + 执行
其他人: 读

8.1 chmod修改权限

例如:

chmod 0664 filename

也可以使用符号方式:

chmod +x filename

给文件增加执行权限。


九、Shell中的管道和重定向

Shell 中非常实用的两个功能:

  • 管道

  • 重定向


9.1 管道 |

管道的作用是:

将前一个命令的输出作为后一个命令的输入。

例如:

ps -ef | grep "bash"

执行过程:

ps -ef
  ↓
输出所有进程
  ↓
grep "bash"
  ↓
筛选包含 bash 的内容

这也是 Linux 命令组合非常重要的一种方式。


9.2 输出重定向 >

例如:

ps -ef > file.txt

表示:

ps -ef
   ↓
输出内容
   ↓
file.txt

如果文件已经存在,> 会覆盖原有内容。


9.3 追加重定向 >>

ps -ef >> file.txt

> 不同:

>   覆盖
>>  追加

9.4 管道 + 重定向

例如:

tail -n 200 /usr/include/stdio.h | grep "extern" > file.txt

这条命令可以拆成三个步骤:

stdio.h最后200行
        ↓
grep查找extern
        ↓
保存到file.txt

这就是 Linux Shell 非常典型的命令组合方式。


十、文件查看与查找命令

10.1 cat

cat filename

直接查看文件内容。


10.2 more / less

用于分页查看较大的文件。

more filename

或者:

less filename

10.3 head / tail

查看文件开头:

head filename

查看文件末尾:

tail filename

例如查看最后 20 行:

tail -n 20 filename

10.4 find

查找文件:

find . -name "test.txt"

表示在当前目录及其子目录中查找 test.txt


10.5 grep

搜索文件中的指定字符串:

grep "hello" test.txt

可以查找 test.txt 中包含 hello 的行。


十一、通配符

Shell 中常用的通配符包括:

*

匹配任意长度的字符。

例如:

file_*.txt

可以匹配:

file_1.txt
file_abc.txt
file_test.txt

?

匹配一个字符。

file_??.txt

[]

匹配指定范围或者指定字符。

例如:

file_[1-5].txt

可以匹配:

file_1.txt
file_2.txt
...
file_5.txt

十二、文件压缩与解压

Linux 中常用 tar 进行文件打包和压缩。

压缩:

tar -zcvf filename.tar.gz dirname/*

解压:

tar -zxvf filename.tar.gz

另外也可以使用:

tar -jcvf filename.tar.bz2 dirname/*

解压:

tar -jxvf filename.tar.bz2

十三、其他常用Linux命令

查看日期

date

查看系统信息

uname -a

可以查看 Linux 内核版本、系统架构等信息。

查看网络信息

ifconfig

测试网络连通性

ping www.baidu.com

查看历史命令

history

查看磁盘空间

du -m filename

或者:

du -k filename

十四、Linux软件安装

Linux 下常见的软件安装方式包括 dpkgapt-get


14.1 dpkg安装

对于 .deb 软件包:

sudo dpkg -i 软件包名.deb

卸载:

sudo dpkg -P 软件名

查看是否安装:

dpkg -l 软件名

十五、apt-get软件管理

如果使用 Ubuntu,可以使用:

sudo apt-get install 软件名

安装软件。

例如:

sudo apt-get install valgrind

安装 Valgrind。

安装 Wireshark:

sudo apt-get install wireshark

更新软件源:

sudo apt-get update

修复软件依赖:

sudo apt-get install -f

资料中还整理了 autocleanupdateinstall -f 等常用软件管理操作。


十六、Shell脚本

前面介绍的:

ls
cd
mkdir
cp
mv
grep

都是 Shell 命令。

如果我们把很多命令按照一定的逻辑组织起来,就可以形成:

Shell脚本

资料中将 Shell 脚本定义为:

一系列 Shell 命令的集合。

Shell 与 C 语言有一个明显区别。

C 语言属于:

编译型语言

而 Shell 属于:

解释型语言

简单理解:

C语言:

源代码
 ↓
编译
 ↓
可执行程序
 ↓
运行

Shell:

Shell脚本
 ↓
解释执行

Shell 开发效率较高,但执行效率通常不如编译型语言。


十七、编写第一个Shell脚本

首先创建文件:

vim test.sh

编写 Shell 代码。

然后增加执行权限:

chmod +x test.sh

执行:

./test.sh

资料中给出的基本流程就是:

创建脚本
 ↓
vim filename.sh
 ↓
chmod +x filename.sh
 ↓
./filename.sh


十八、Shell变量

Shell 中可以定义变量:

name=linux

使用变量:

echo $name

需要注意:

等号两边不能随意添加空格。

错误:

name = linux

正确:

name=linux

十九、Shell环境变量

常见环境变量:

PWD
HOME
PATH

例如:

echo $HOME

查看当前用户的家目录。

echo $PATH

查看系统的环境变量 PATH。


二十、Shell位置变量

Shell 脚本可以接收命令行参数。

例如:

./test.sh hello 123

脚本中:

$0
$1
$2

分别表示:

$0 → 脚本文件名
$1 → 第一个参数
$2 → 第二个参数

此外:

$# → 参数个数
$$ → 当前Shell脚本进程ID
$? → 上一条命令的返回结果

这些变量在 Shell 脚本开发中非常常用。


二十一、Shell中的引号

Shell 中常见三种引号:

" "     双引号
' '     单引号
` `     反引号

21.1 双引号

双引号中的变量会被解析。

例如:

name=Linux
echo "hello $name"

输出:

hello Linux

21.2 单引号

单引号中的内容一般按照原样处理。

name=Linux
echo 'hello $name'

不会按照变量值进行替换。


21.3 反引号

反引号可以将其中内容作为命令执行。

例如:

date=`date`
echo $date

它的作用可以理解为:

执行 date 命令
      ↓
获得命令结果
      ↓
赋值给变量

资料中也对这三种引号的作用进行了区分。


二十二、Shell输入与输出

Shell 中最常用的输入输出命令:

echo → 输出
read → 输入

22.1 echo

echo "Hello Linux"

输出:

Hello Linux

22.2 read

read name

从终端接收用户输入。

完整示例:

echo "请输入你的名字:"
read name
echo "你好,$name"

二十三、Shell中的if语句

Shell 中可以使用 if 进行条件判断。

基本结构:

if [ 判断条件 ]
then
    语句
else
    语句
fi

例如:

if [ -f test.txt ]
then
    echo "文件存在"
else
    echo "文件不存在"
fi

这里:

-f

用于判断指定路径是否为普通文件。


二十四、Shell中的case语句

如果需要根据多个不同情况执行不同操作,可以使用 case

基本结构:

case 变量 in
    值1)
        语句
        ;;
    值2)
        语句
        ;;
    *)
        语句
        ;;
esac

例如:

case $score in
    90)
        echo "优秀"
        ;;
    80)
        echo "良好"
        ;;
    *)
        echo "其他"
        ;;
esac
Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐