文章目录
一.Linux操作系统基础命令
Linux文件名称
(-)普通文件
(d)目录文件
(c/b)设备文件
(l)链接文件
(p)管道文件
(f)栈堆文件
(s)共享文件
dev 设备文件
lib 库文件
boot 启动文件
root
sys 内核信息
proc
var 日志文件
etc 配置文件
home 用户家目录
usr 用户安装软件
usr/include 头文件
b 启动文件
bin 用户二进制文件
sbin 高级文件
Linux文件权限操作
-rw-r-r
ls -l 显示权限
rwx可读可写可执行
r 4 w 2 x 1
chmod u+x 1.c 更改文件权限
a+ 所有用户
u+ 文件拥有者
g+ 与user同一个group的其他user
o+ 其他group的user
Linux操作命令
gedit hello.c 打开文本
cat hello.c 显示文本的内容
cd ~ 当前用户主目录
cd / 根目录
cd / home 进入home目录
cd . 进入当前目录
cd … 返回上一级目录
cd - 返回上一次所在目录
ls 查看当前目录中的文件
ls -a 显示隐藏文件
rm 删除
rm -f 强制删除
rm -rf 彻底删除 (递归)
rm *.c 删除所有.c的文件
touch 1.c 新建
mkdir m 新建文件夹
mkdir -p m/n/z 创建多级文件夹
su root 切换管理员用户
sudo 提升权限
man ls 手册
adduser wq 创建用户
userdel wq 删除用户
cp 2.c 1.c 把2.c的文件复制到1.c
mv 2.c 1.c 把2.c移动到1.c 2.c就没了
cp 2.c /home 把2.c复制到home里
cp -r 文件夹
ipconfig 查看网络
exit 退出当前用户
pwd 查看当前路径
ctrl+shift+c 复制
vim 编辑器
vim hello.c 进入命令模式
a 插入模式
esc 返回命令模式
shift+zz 退出
shift+:底行
q+! 强制退出
命令模式 ia 插入模式 esc 命令模式 shift+: 底行模式
命令模式: 选择一行 yy复制 p粘贴 按yy后再按复制行数再按p
dd删除 u撤销 行数+dd
底行模式: s/hello/hi 把那一行hello替换为hi
s/hello/hi/g 把那一行的所有hello替换为hi
wq 保存退出
wq !强制保存退出
二.Linux操作系统编译
编译器 gcc
调试器 gdb
工程管理器 make cmake
版本管理器 git
c过程
1.预处理 # .i后缀
2.编译 语法检查
3.把c程序翻译成汇编语言 汇编 把汇编语言翻译成二进制代码 .o后缀
4.链接:链接需要用到的代码c库或其他文件
gcc hello.c -o hello 编译
./hello 运行
gcc -Wall hello.c 显示警告
交叉编译
条件编译
gcc -E hello.c -o hello.i 预处理 每一步会创建一个文件
gcc -S hello.i -o hello.s 编译
gcc -c hello.s -o hello.o 汇编
gcc hello.o -o hello 链接
./hello
mycode 打开vscode
三.静态库和动态库
库文件:存放函数和变量的仓库,特点:只能使用库里的函数和变量,不能看到其实现
静态库 .a结尾 当使用静态库时,库里的函数和变量只在编译时加载到可执行文件
动态库 .so结尾 当使用动态库时,库里的函数和变量只在运行时加载到可执行文件
可执行文件大小:静态库 > 动态库 静态库缺点:内存使用效率不高
可执行文件速度:静态库 > 动态库 运行效率
可执行文件的功能升级:静态库 < 动态库 功能升级的难易程度
可执行文件的代码部署:静态库 > 动态库 代码部署的位置
“” 访问当前目录 <>访问库文件
a.out 可执行文件
库文件的存放路径: /lib/usr/lib
cp …/add.h . 上一级的add.h复制到当前目录
静态库:.a
- gcc -c 源文件.c
- ar rcs 库文件名 目标文件
- gcc 源文件(主函数) -l 库名 -L库的路径
gcc -c add.c 编译生成add.o
ar rcs libadd.a add.o (libxxx.a) 生成库文件
gcc main.c -ladd -L. (-lxxx) 静态编译 -L.指定当前目录为静态库地址
减法器静态库
gcc -c minus.c
ar rcs libminus.a minus.o
gcc main.c -lminus -L.
./a.out
动态库: .so
- gcc -shared -fPIC 源文件.c -o 库名
- gcc 源文件(主函数) ./库名 -o 可执行文件
gcc -shared -fPIC add.c -o libadd.so 生成.so库文件
gcc main.c ./libadd.so -o main 生成main可执行文件
四.Linux开发工具和makefile
Linux开发工具:调试器gdb
- gdb也是GNU计划 a\启动运行程序 b/设置断点 c/查看变量值
- 使用gdb之前,需要用-g编译
- 学习gdb命令,gdb可执行文件 --tui
- 运行命令:run(r) continue(c)
- 设置断点: break+行号 break+ 函数名 break+ 行号+ 条件
- 查看断点信息 info break
- 删除断点 delete + 断点号
- 单步执行:next step n跳过子函数 s进入子函数
- 查看变量值: print 变量名
-o xxx 生成xxx文件
gdb main 进入gdb
run 运行代码
list 显示代码
break 21 设置断点(行数)
info break 查看断点信息
d 21 删除断点
n s 断点处开始执行
q 退出
gdb main --tui
q
layout src
layout asm
嵌入式Linux开发工具 工程管理器 make
- 什么是工/项目 (项目:多个源文件,资源文件构成的代码项目)
- 如何编译多个源文件的代码 (1000个源文件,并且不在同一目录) --工程管理器make
- 作用:自动编译
- makefile文件的作用:存放编译项目的命令(如何编译这个项目的所有操作)
- makefile是一个脚本文件:批处理
- makefile语法:三要素:目标,依赖,命令(执行命令,根据依赖的文件生成对应的目标)
格式
目标:依赖 (无空格,直接回车)
tab 命令
执行顺序:make 目标名称(从目标名称下开始执行) 如果目标名称不存在就从下一行开始
hello:hello.o 先有hello.o则生成hello 没有则往下 最终目标在最上面 能执行则终止
gcc hello.c -o hello
hello.o:hello.c 先有hello.c则生成hello.o
gcc -c hello.c -o hello.o
+= :=
make clean
make install
hello移到bin文件里 hello成了一个命令
@可隐藏
#可注释内容
四则运算器的makefile:
add.c sub.c mul.c div.c
main.c
main.h (最好不要用关键字做.h的文件名)
makefile
make ./main
obj
-o $@
五.企业级makefile
企业级Makefile编写:
- 总控makefile:进入各个功能子目录执行make命令,并将所有的.o文件生成可执行文件
- 功能目录makefile:将功能目录下的所有.c文件编译成.o文件
- 脚本目录makefile:定义其他makefile文件所用到的变量
阅读makefile顺序 3-1-2
unzip 压缩包名
目录 /mnt/hgfs/ 按tab
scripts 脚本文件
-
( w i l d c a r d 模 式 参 数 ) e g : r e s u l t : = (wildcard 模式参数) eg:result:= (wildcard模式参数)eg:result:=(wildcard *.c)
result=当前目录下所有.c文件 -
( p a t s u b s t 模 式 参 数 , 参 数 1 , 参 数 2 ) e g : r e s u l t : = (patsubst 模式参数,参数1,参数2) eg:result:= (patsubst模式参数,参数1,参数2)eg:result:=(patsubst %.c, %.o, x.c, y.c)
result:=x.o,y.o -
:= 防止变量出现死循环
a1:=a.o
a2:=$(a1) b.o
a1=a.o a2=a.o b.o
a1:=$(a2) b.o
a2:=a.o
a1=b.o a2=a.o
- += 给变量添加值
a1=a.o
a1+=b.o
a1=a.o b.o
a1=a.o
a1:=$(a1) b.o
a1=a.o b.o
-
( a d d s u f f i x 参 数 1 , 参 数 2 ) 参 数 2 中 的 每 个 单 词 都 加 上 参 数 1 的 后 缀 r e s u l t : = (addsuffix 参数1,参数2) 参数2中的每个单词都加上参数1的后缀 result := (addsuffix参数1,参数2)参数2中的每个单词都加上参数1的后缀result:=(addsuffix .c, x y)
result = x.c y.c -
foreach
$(foreach 变量参数, 参数1 ,表达式)
功能:循环取出参数1中的单词赋值给变量参数,然后运行表达式。返回值:表达式运行结果
a:= x y z
result:= $(foreach b, $(a), $(b).c)
result = x.c y.c z.c -
( c a l l 变 量 参 数 , 参 数 . . . . . . . . ) 功 能 : 循 环 把 参 数 依 次 赋 值 给 变 量 参 数 中 的 (call 变量参数 , 参数........) 功能:循环把参数依次赋值给变量参数中的 (call变量参数,参数........)功能:循环把参数依次赋值给变量参数中的(1),$(2)…返回值: 赋值后的变量值
a:= $(2) $(1)
result:= $(call $(a),x y)
result = yx
四则运算makefile
六.Linux开发工具gcc gdb git shell
- 嵌入式Linux开发工具-编译器 gcc (静态库 动态库的制作)可以制作库 库的使用
- 嵌入式Linux开发工具-调试器 gdb (调试方法)目标:可以调试简单的错误以及内存错误
- 嵌入式开发工具-工程管理器make 目标企业级的makefile cmake
- 嵌入式Linux开发工具-git版本管理
- 嵌入式Linux开发工具-shell编程
四则运算器的企业级makefile制作
tree
总控makefile
main.c
scripts脚本
各个函数对应的makefile 其他格式相同
div sub mul 格式相同
main.h
运行结果
七.shell编程
标准输入的文件描述符为0
标准输出的文件描述符为1
标准错误的文件描述符为2
重定向 >
gcc hello.c > hello
command > file 把命令的输出结果重定向到这个文件里
shell就是一个命令解释器,它为用户提供一个向Linux内核发送请求以便运行程序界面系统级程序
目前流行的几种shell:ash,bash,ksh,csh,zsh等 linux用的bash csh相当于Linux的内核
#echo KaTeX parse error: Expected 'EOF', got '#' at position 45: … 管道pipe #̲shell-name comm… 应用变量加$
shell 的常用变量
- HOME: 用来保存注册目录的完全路径名
- PATH: 用于保存用冒号分割的目录路径名,shell将按PATH变量给出的顺序搜索这些目录,找到的第一个与命令名称一致的可执行文件
- TERM:终端的类型
- UID:当前用户的标识符
- PWD:当前工作目录的绝对路径
shell的语法
主要由开头部分,注释部分以及语句执行部分组成
开头部分: #!/bin/bash
#!用来告诉系统它后面的参数是用来执行该文件的程序,在这个例子中使用bin/bash来执行程序
bash *.sh 可以直接运行
bash demo1.sh
shell变量:
1.本地变量
2.环境变量
3.特殊变量
调用变量时则应在变量名前加一个$(美元符号)
使用set命令可以查看所有的本地变量和环境变量
本地变量,也称用户自定义变量,是在当前shell环境,当前进程内有效的变量。当用户注销,或者启用子shell,子进程时该变量不起作用
一.定义本地变量
1.在bash shell环境下,定义本地变量的设置格式如下:
变量名=变量值(若等号两边有空格,则必须使用引号括起来)
#s1=hello
#s2= “hello world” 等号旁边不能有空格
2.变量设置的规定
(1)变量名称只能是英文字母,下划线与数字,但是数字不能是开头字符
(2)若有空格,可以使用双引号或单引号将变量内容连接起来
(3)用户也可以在命令行上同时定义多个变量赋值,赋值语句之间要用空格分开
#x-4 y-5
1.readonly命令
有时需要在说明一个变量并对他设置一个特定值后就不需要它在改变时,可以用readonly保证一个变量的只读性
2.read命令
语法:read[-pt]变量名
功能:读取来自键盘输入的变量
可选项
-p:后面可以接提示信息
-t:后面可以接等待的秒数,为了防止一直等待用户
eg:
让用户通过键盘输入内容,将内容改成atest变量
提示用户30秒内输入自己的名字,将输入字符串做成name变量
八.shell变量
pwd显示当前目录
显示本地变量
echo $变量名 或 echo $(变量名)
eg #num=2
#echo "this is $numnd
#num=2
#echo “this is ${num}nd”
eg2
要将name的内容多出“yes”
#name="KaTeX parse error: Expected 'EOF', got '#' at position 12: name"yes #̲naem={name}yes
eg3
在子shell下变量的作用范围
#aa=11
#bash bash开启一个子shell
#echo $aa
#aa=22
#echo $aa
#22
#exit 退出这个子shell
#echo $aa
#11
eg4
释放本地变量unset
格式 unset 变量名
unset name
环境变量在shell脚本开始执行时就定义了
环境变量也称系统变量
环境变量可用于所有用户进程
PS1:主提示符,在特权用户下,默认的主提示符是#;在普通用户下,默认的主提示符是$
PS1变量的特殊符号
PS1=’[\u@\h\w]$’
\u:当前用户的账号名称
\h:仅取主机名的第一个名字
\w:工作目录名称,仅列出最后一个目录名
$:提示符,如果是root用户就是#否则就是$
#PATH:决定了shell将到哪些目录寻找命令或程序,PATH的值是一系列目录
Linux修改PAYTH变量
只想对本次登录有效的话
PATH=$PATH<路径1><路径2>…
永久有效在bashrc里面加上上面这句话
export
用export可以把本地变量设置为环境变量
格式:export 变量名
也可以在给变量赋值的同时使用export命令
export 变量名=变量值(若等号两边有空格,则必须用引号括起来)
特殊变量
某些变量在一开始执行脚本时就被设定且不在改变,他们被称为特殊变量
用户只能根据shell使用这些变量而不能重新定义他们,所有特殊变量都是由$和另一个符号组成
$#:存储shell程序中命令行参数的个数
$?:存储shell中上一个程序执行的返回值(0表示执行成功,非0错误)
$[1-n]:存储第[1-n]个命令行参数
$0:存储shell程序自己的名称
$:存储shell脚本的所有参数(不包含$0)
∗
*
∗:存储shell脚本的进程号(pid)
练习
设计脚本****要求如下
当输入bash ./***** **** 回车显示*****年头三个月的月历
shift命令
可以移动命令行参数。运行shift后,把每个参数向左移动一个位置,$2 $3 …依次变为$1 $2 … 原先的$1去掉
特殊符号
引用符号
在bash中,许多字符含有特殊含义如果希望忽略某些字符含义,可以使用一种“引用”通知shell暂时忽略被引用字符的特殊含义,将其作为普通字符处理
~: 用户主目录
`: 不会被双引号剥夺含义
#: 注释
$:
&: 将命令在后台执行
*: 通配符 代表任何字符
(: 子shell开始
): 子shell结束
: 不会被双引号剥夺含义
|: 管道
?: 通配符 代表任何单一字符
<: 输入重对象
>: 输出重对象
': 单引号 不具有变量置换的功能
“:双引号 具有变量置换的功能
/:
;:
在shell中的三种引用符号
转义符:
单引号:’
双引号:“
\放在shell特殊字符之前,则shell忽略该字符的特殊含义
用这种方式时,必须在每一个忽略的特殊含义的特殊字符前加\字符
单引号:’
将字符放在一对单引号之间,则单引号内的所有字符的特殊含义都被忽略,只作为普通字符解释
命令替换符 “`“命令替换符 “” (反引号)的作用跟引用字符的作用相反
反引号括起来的字符被shell解释为命令行,执行shell时,首先执行该命令行,并以它的标准输出结果取代整个反引号(包括两个反引号)部分
九.shell中test表达式和语法
- 变量表达式
test是shell程序中的一个表达式,通常用在流程控制for,while,until,if等结构中,用test命令去判断文件的存在与性质,变量的相互关系
语法:test<表达式>
如果<表达式>成立,test返回0,反之返回一个非0值
字符串比较
两个数值比较
逻辑操作,可以进行and/or,与其他条件联合使用
文件操作,例如文件是否存在文件的状态等
字符串比较
test -z<字符串> :比较字符串长度是否为0,如果等于0则为是,返回0
test -n <字符串> :比较字符串的长度是否大于0,如果大于0则为是
test <字符串1> = <字符串2>:比较两个字符串是否相同,相同返回0,等号两边要有空格判断是用==
test <字符串1> != <字符串2>:比较两个字符串是否不同,不同返回0,
数字比较 (数值上的比较)
<数值表达式1><算符><数值表达式2> 算符两边要有空格
-eq:两者相等
-ne:两者不等
-lt: 前者小于后者
-le:前者小于或等于后者
-gt:前者大于后者
-ge:前者大于或等于后者 符合条件则返回0 不符合返回1
文件操作
文件测试表达式通常是为了测试文件的文件操作逻辑
-e:对象是否存在,存在返回值为0
-d:对象存在且为目录,则返回值为0
-f:对象存在且为文件,则返回0
-L:对象存在且为符号连接,则返回0
-r:对象存且可读,则返回0
-s:对象存在且长度非0,则返回0
-w:对象存在且可写,则返回0
-x:对象存在且可执行,则返回0
!:测试条件的否定(与上述的符号用空格给隔开)
逻辑测试
常用于逻辑测试的<表达式>有:
!<表达式>:<表达式> 不成立
<表达式1>-a<表达式2>:<表达式1>与<表达式2>同时成立
<表达式1>-o<表达式2>:<表达式1>或<表达式2>成立
shell流程控制语句
条件控制:if,case等结构
循环控制:for,while,until等结构
在shell中,条件判断语句可以使用if条件语句和case条件语句,case语句的选项比较多
- if条件语句
用法:
if<判别令>;
then{命令清单1}
then{命令清单2} //else语句可以省略
fi
此处判别令通常是上述test<表达式>,如果只写表达式,则用中括号括起来(中括号两边要有空格)
如果<判别令>返回0(对于test命令来说,就是其后的表达式成立),则将执行then后的命令清单;
反之,则执行else后的命令
shell语句中的分号
分号是多个语句之间的分隔符,当只有一个语句的时候,末尾无需分号,最后一个语句后面也无需分号
eg:
if[abcd];then if[abcd]
then
if…
then…
else if…
then…
else if…
then…
else…
fi
fi
fi
if test $ANSWER = N -o $ANSWER = n
- [ ] = -o 两边要有空格, =也可用== (=作为赋值符号时 不能写成==)
- $ANSWER,N两边写不写引号无所谓
eg:使用if-then-else语句创建一个根据输入分数判断分数是否及格的shell程序文件名为ak
case条件语句(猜拳游戏)
if条件语句用于在两个选项中选定一个选项,而case条件选择为用户提供字符串或变量的值从多个选项中选择一项方法。
语法
case<变量>in
<字符串1>){<命令清单1>} ;;
<字符串2>){<命令清单2>} ;;
…
<字符串n>){<命令清单n>} ;;
*){其他命令};;
esac
在case运算式中也可以使用shell的通配符(" * " , “?” , “[]”)
通常用 “ * ”作为case命令的最后运算时以便在前面找不到任何相应的匹配项时,执行“其他命令”的命令
eg:假如给出月份数字作为参数,就能编写一个回送月份名的脚本month。当给出的数字不在1和12之间时,将得到错误信息。
eg:编写shell脚本cjpd,根据输入的学生成绩判断等级。当成绩>=90为A,80<=成绩<90为B,70<=成绩<80为C,60<=成绩<70为D,成绩<60为E。
- for语句循环
for<循环变量> [ in<循环变量取值集>]
do<命令清单>
done
如果for语句的后半部分被省略,则默认的<循环变量取值集>就是命令行参数集
如果命令清单有多条命令,系统会依次执行
expr是求表达式变量的值, 用于整数值
expr <表达式>
十.shell语法
expr命令
格式:expr expression (命令读入expression参数,计算它的值,然后将结果写入标准输出)
参数应用规则:
1.用空格隔开每个项
2.用\(反斜杠)放在shell特定的字符前面
对包含空格和其他特殊字符的字符串要用引号括起来
3.计算字符串长度 length 字符串
4.增量计数
说明:expr在循环中用于增量计算,先将变量初始化为0,然后循环值加1,反引号的用法是命令替代``
- while循环语句
while<判别令>
do<命令清单>
done
当<判别令>返回0时(对于test命令,就是其后的表达式成立),则执行do后的命令清单,然后在重作循环;否则退出循环
while控制常与shift命令结合使用
eg:编写一个shell脚本exist,用于判别其后用参数方式指定的一系列文件是否存在
使用while语句创建一个计算1到5的平方shell
使用while语句创建一个输入exit退出的shell程序
2.until循环语句
until控制流与while控制流用法类似,但作用相反
until<判别令>
do<命令清单>
done
当<判别令>返回值非0值时,执行do后的命令清单,然后检查循环条件;当<判别令>返回0值时,退出循环
3.break和continue
有时需要基于某些准则退出循环或跳过循环shell提供了两个命令实测功能
break 跳出整个循环 continue 跳出本次循环
4.here
在shell中还可以利用所谓的“here文本”功能,即可在脚本文件中嵌入一段文档,作为脚本中所使用的的命令的标准输入
<命令><<!
<作为文本内容>
!
其中“ !”符号也可以使用“ EOF” “ END ”等替换
使用here文本,可以方便的将一些需要进行交互的命令放入shell脚本中
函数
所有函数在使用前必须定义。这意味着必须将函数定义在脚本开始的部分,直到shell解释器首次发现它时,才可以使用
向函数传递参数
向函数传递参数和向普通脚本传递参数是一样的,也是用$1 $2 $3
从函数中返回
当调用完函数,那么主程序可能需要得到函数的返回值。在函数中得到函数返回值可以使用一下方法
1.在函数末尾加return,从函数中返回,用最后的命令状态决定返回值
2.返回数值,如0或1 格式return 0或return 1
获取函数的返回值
用户可以直接在程序调用完函数的时候获取它的返回值
source
source在Linux中也被称为点命令,也就是一个符号(.)
使用source执行脚本时,脚本会在父进程中执行,各种操作都会在原本的bash内生效
source命令通常用于重新执行刚刚修改过初始化文件,使之立即生效,而不必注销并重新登录
用法:source 文件名\ .文件名