Linux C 基础
文章目录
1 软件包管理机制
1.1 dpkg
- 功能:
dpkg
是一个低级的包管理工具,用于在Debian系统中安装、卸载和管理软件包。 - 使用方式: 典型的使用包括使用
dpkg -i
来安装软件包,dpkg -r
来卸载软件包,以及dpkg -l
来列出已安装的软件包。 - 注意事项:
dpkg
处理软件包的安装和卸载,但不会解决软件包依赖关系,需要手动解决依赖问题。 - 相关命令
dpkg -i <package> 安装一个在本地文件系统上存在的Debian软件包
dpkg -r <package> 移除一个已经安装的软件包
dpkg -P <package> 移除已安装软件包及配置文件
dpkg -L <package> 列出安装的软件包清单
dpkg -s <package> 显出软件包的安装状态
1.2 apt
- 功能:
apt
是一个高级的包管理工具,构建在dpkg
之上,用于简化软件包的安装、升级和依赖关系的管理。 - 使用方式: 典型的使用包括使用
apt install
来安装软件包,apt remove
来卸载软件包,以及apt update
和apt upgrade
来更新软件包。 - 注意事项:
apt
会自动解决软件包之间的依赖关系,提供了更高级、用户友好的接口。 - 工作原理:•在Ubuntu系统中,使用软件源配置文件/etc/apt/sources.list 列出最合适访问的镜像站点地址。软件源配置文件只是告知Ubuntu系统可以访问的镜像站点地址。但那些镜像站点都拥有什么软件资源并不清楚。若是每安装一个软件包,就在服务器上寻找一边,效率是很低的。因而,就有必要为这些软件资源列个清单(建立索引文件),以便本地主机查询。
- 建立文件清单:使用
apt-get update
命令会扫描每一个软件源服务器,并为该服务器所具有软件包资源建立索引文件,存放在本地的/var/lib/apt/lists/
目录中。
常用命令
![[Pasted image 20231228224843.png]]
常用选项
![[Pasted image 20231228225237.png]]
--reinstall
可以修复已损坏的软件包和升级软件包中的文件的最近版本
--purge
不仅卸载软件包及其依赖项,还卸载对应的配置文件
修复软件包依赖关系:
# 先检查软件包之间的依赖关系,再进行修复
apt-get check
apt-get -f install
查看已经软件包缓冲区和清理缓冲区:
ls /var/cache/apt/archives/
apt-get clean
# 只保留最新版本的软件包,其余版本全都清除
apt-get autoclean
查看软件包源
ls /var/lib/apt/lists/*
- 查询软件包信息:使用apt-cache命令完成查询软件源和软件包的相关信息
![[Pasted image 20231228225856.png]]
2 shell基本命令
shell是一个命令行解释器,将用户命令解析为操作系统所能理解的指令,实现用户与操作系统的交互。
命令格式:Command [-Options] Argument1 Argument2
- 多个命令在一行书写:使用’;‘隔开
- 不能写完一行:使用’\'隔开
常用命令:
- 历史命令:
- 查询历史命令:history
->history <number>
- 删除某条历史命令:histroy -d <number>
- 查看历史命令容量:echo $HISTORYSIZE
2.1 通配符
使用场景:对多个文件进行条件筛选
![[Pasted image 20231229151655.png]]
2.2 管道
使用场景:命令的串行使用,一般用于多个命令完成一项任务且命令间有同步关系。关键符号:‘|’
ls /usr/bin | wc -w
2.3 输入\输出重定向
使用场景:将标准的输入、输出和错误信息用于其他设备(不局限于控制台,还有文件、打印机等输入输出设备)
•输入/输出重定向是改变shell命令或程序默认的标准输入/输出目标,重新定向到新的目标。
•linux中默认的标准输入定义为键盘,标准输出定义为终端窗口。
•用户可以为当前操作改变输入或输出,迫使某个特定命令的输入或输出来源为外部文件。
![[Pasted image 20231229152237.png]]
示例:
# cat没有选项和参数时可以作为标准输入/输出使用
$ cat # 键盘输入,屏幕输出
hello!
hello!
$ cat > file.txt # 键盘输入的内容定位到file文件中
$ cat < file.txt # file文件作为输入,cat接收file中的内容并显示到屏幕上
2.4 命令置换
•命令替换是将一个命令的输出作为另一个命令的参数。命令格式如下所示。
格式:
$ command1 `command2`
$ ls `pwd`
3 shell编程
- shell的本质:shell命令的有序集合
3.1 变量
- 所有变量都会被解释为字符串
变量类型:- 用户自定义的变量:
var.sh
# 1 定义使用和不使用变量
#!/bin/sh
COUNT=1
echo $COUNT # 使用变量
DATE=`date` # 命令执行的结果返回给变量
echo $DATE
unset COUNT # 不使用变量
echo $COUNT
# 输出
./var.sh
1
Tue Jan 2 05:40:25 PM CST 2024
- 位置变量或预定义变量
$0 与键入的命令行一样,包含脚本文件名
$1,$2,……$9 分别包含第一个到第九个命令行参数
$# 包含命令行参数的个数
$@ 包含所有命令行参数:“$1,$2,……$9”
$? 包含前一个命令的退出状态
$* 包含所有命令行参数:“$1,$2,……$9”
$$ 包含正在执行进程的ID号
- 环境变量
HOME: /etc/passwd文件中列出的用户主目录
IFS:Internal Field Separator, 默认为空格,tab及换行符
PATH :shell搜索路径
PS1,PS2:默认提示符($)及换行提示符(>)
TERM:终端类型,常用的有vt100,ansi,vt200,xterm等
3.2 功能语句
- 说明性语句(注释):
- 以"#"开头:告诉OS用哪种类型的shell来解释执行该程序
#! /bin/sh
- 功能性语句:
- read:标准输入
#!/bin/sh
echo "input year month day"
read year month day
echo $year $month $day
echo `date`
read -p "Enter your name: " name
echo "Hello, $name!"
./read.sh
input year month day
2023 12 31 # 键盘输入
2023 12 31
Tue Jan 2 08:22:36 PM CST 2024
GXL # 键盘输入
Hello, GXL!
- expr:数学计算
- 算术运算命令expr主要用于进行简单的整数运算,包括加(+)、减(-)、乘(*)、整除(/)和求模(%)等操作
expr.sh
#!/bin/sh
var1=$1
var2=$2
sum=`expr $var1 \* $var2`
echo "$sum"
./expr.sh
8
- 测试语句:
- 测试字符串
s1 = s2 测试两个字符串的内容是否完全一样
s1 != s2 测试两个字符串的内容是否有差异
-z s1 测试s1 字符串的长度是否为0
-n s1 测试s1 字符串的长度是否不为0
test.sh
#!/bin/bash
test $1 = "yes"
echo $?
test $2 -lt 18
echo $?
test -d $3
echo $?
./test.sh
0
0
0
- 测试整数
a -eq b 测试a 与b 是否相等
a -ne b 测试a 与b 是否不相等
a -gt b 测试a 是否大于b
a -ge b 测试a 是否大于等于b
a -lt b 测试a 是否小于b
a -le b 测试a 是否小于等于b
- 文件属性测试
-d name 测试name 是否为一个目录
-e name 测试一个文件是否存在
-f name 测试name 是否为普通文件
-L name 测试name 是否为符号链接
-r name 测试name 文件是否存在且为可读
-w name 测试name 文件是否存在且为可写
-x name 测试name 文件是否存在且为可执行
-s name 测试name 文件是否存在且其长度不为0
f1 -nt f2 测试文件f1 是否比文件f2 更新
f1 -ot f2 测试文件f1 是否比文件f2 更旧
3.3 分支语句
- 结构性语句:
- 条件语句:
if.sh
#!/bin/bash
var1=$1
if [ -f $var1 ]
then
echo "The file is exists: $var1"
elif [-d $var1 ]
then
echo "The diretory is exites: $var1"
else
echo "It is not."
fi
./if.sh if.sh
The file is exists: if.sh
- 多路分支语句:
书写规则
case…esac
多路分支语句case用于多重条件测试, 语法结构清晰自然. 其语法为:
case 字符串变量 in
模式1)
命令表1
;;
模式2 | 模式3)
命令表2
;;
……
模式n)
命令表n
;;
esac
注:
1)case语句只能检测字符串变量
2)各模式中可用文件名元字符,以右括号结束
3)一次可以匹配多个模式用“|”分开
4)命令表以单独的双分号行结束,退出case语句
5)模式 n常写为字符* 表示所有其它模式
6)最后一个双分号行可以省略
case.sh
#!/bin/bash
grade=`expr $1 / 10`
case $grade in
9|10)
echo "A+"
;;
8)
echo "A"
;;
7)
echo "A-"
;;
5|6)
echo "B"
;;
*)
echo "C"
;;
esac
./case.sh 80
A
- 循环语句:
- for
- 1)当循环次数已知或确定时,使用for循环语句来多次执行一条或一组命令。
循环体由语句括号do和done来限定。格式为:
for 变量名 in 单词表
do
命令表
done
2)变量依次取单词表中的各个单词, 每取一次单词, 就执行一次循环体中的命令.
循环次数由单词表中的单词数确定. 命令表中的命令可以是一条, 也可以是由分号或换行符分开的多条。
3)如果单词表是命令行上的所有位置参数时, 可以在for语句中省略 “in 单词表” 部分。
for.sh
#!/bin/bash
if [ ! -d backup ] # backup目录不存在
then
mkdir backup
echo "create d backup success!"
fi
flist=`ls`
echo "$flist"
for file in $flist
do
if [ $file != "backup" ]
then
cp -r $file backup # 递归复制文件
echo "$file backuped."
fi
done
echo "all files backuped."
- while
语法结构为:
while 命令或表达式
do
命令表
done
1)while语句首先测试其后的命令或表达式的值,如果为真,就执行一次循环体中的命令,
然后再测试该命令或表达式的值,执行循环体,直到该命令或表达式为假时退出循环。
2)while语句的退出状态为命令表中被执行的最后一条命令的退出状态。
- 循环控制语句
- break
- continue
#!/bin/bash
if [ $# != 2 ] # 输入参数个数必须为2
then
echo "parameters numbers is not 2."
exit
fi
base_name=$1
number=$2
n=1
while [ $n -le $number ]
do
touch $1_$n
n=`expr $n + 1`
done
3.4 shell函数
- 函数调用
- 直接调用
- 传参:函数内部中的
$1 $2 $3...
就不是命令行传的参数而是函数传的参数
# 调用格式
方式1:
value_name=`function_name [arg1 arg2 … ]`
函数的所有标准输出都传递给了主程序的变量
方式2:
function_name [arg1 arg2 … ]
echo $?
获取函数的返回的状态
func.sh
#!/bin/bash
func()
{
sum=`expr $1 + $2`
echo "$1+$2"
return $sum
}
sum=`func 2 3`
echo $?
echo "$sum"
./func.sh
5
2+3
- 函数变量的作用域
默认是全局变量,若需要缩小作用域则在变量之前加local
关键字
4 gbd调试工具
(1) 调试器–Gdb调试流程
首先使用gcc对test.c进行编译,注意一定要加上选项‘-g’
# gcc -g test.c -o test
# gdb test
(2) gdb调试流程
查看文件
(gdb) l
设置断点
(gdb) b 6(代码行数)
查看断点情况
(gdb) info b(查看所有设置的断点)
运行代码
(gdb) r(开始运行程序)
查看变量值
(gdb) p n(已经运行过的变量)
单步运行
(gdb) n(函数体外的运行)
(gdb) s(进入函数体内)
恢复程序运行
(gdb) c(执行以后的程序,忽略之后的断点)
帮助
(gdb) help [command]
(3)Gdb的使用切记点
在gcc编译选项中一定要加入‘-g’。
只有在代码处于“运行”或“暂停”状态时才能查看变量值。
设置断点后程序在指定行之前停止
(4)gdb调试
运行被调试程序,设置所有的能影响该程序的参数和变量。
保证被调试程序在指定的条件下停止运行。
当被调试程序停止时,让开发工程师检查发生了什么。
根据每次调试器的提示信息来做响应的改变,以便修正某个错误引起的问题
5 条件编译
(1)编译器根据条件的真假决定是否编译相关的代码,
常见的条件编译有两种方法:
一、根据宏是否定义,其语法如下:
#ifdef <macro>
……
#else
……
#endif
compile.c
#include <stdio.h>
#define _DEBUG_
int main(int argc, char *argv[])
{
#ifdef _DEBUG_
printf("The macro _DEBUG_ is defined\n");
#else
printf("The macro _DEBUG_ is not defined\n");
#endif
return 0;
}
gcc complie.c -o compile
./compile
The macro _DEBUG_ is defined
二、根据宏的值,其语法如下:
#if <macro>
……
#else
……
#endif
complie.c
#include <stdio.h>
#define _DEBUG_ 0
int main(int argc, char *argv[])
{
#if _DEBUG_
printf("The macro _DEBUG_ is defined\n");
#else
printf("The macro _DEBUG_ is not defined\n");
#endif
return 0;
}
gcc complie.c -o complie
./compile
The macro _DEBUG_ is not defined