前言
期末自查用
VMware配置
安装RHEL6.3
虚拟磁盘设置为30G,采用动态分配硬盘方式,并设置为分割多个小文件
DVD 导入准备的光盘,使用 ISO 映像文件
正式进入安装界面
磁盘分区:
自定义软件安装包
网络设置
以 NAT 模式为例,这样子主机相当于路由器,给虚拟机分配一层内网地址(桥接模式则会和主机在同一网段分配 ip 地址)
虚拟机网络设置为 NAT 模式
主机网络适配器启动 VMnet8 网卡
然后保证右下角这个图标处于启动状态
同时虚拟机内连接网络,这里是 System eth0
然后主机和虚拟机之间相互ping一下测试网络连通性(主机需关闭防火墙才能被 ping 通)
ssh远程登录
启动 ssh 服务
debian 系
sudo apt-get update
sudo apt-get install openssh-server
sudo service ssh start # 启动服务
sudo systemctl start ssh # 较新的系统启动服务
sudo /etc/init.d/ssh restart # 重启服务
# 或
sudo systemctl restart ssh
centos 系
sudo yum install openssh-server
sudo service sshd start
# 或
sudo systemctl start sshd
检查是否启动
ps -e | grep ssh
netstat -an | grep 22
配置 ssh
允许密码身份验证:编辑 /etc/ssh/ssh_config 文件
PasswordAuthentication yes
允许root用户登录:编辑 /etc/ssh/ssh_config 文件
# PermitRootLogin prohibit-password
PermitRootLogin yes
重新加载ssh配置:重载或重启
sudo systemctl reload ssh
sudo systemctl restart ssh
Shell命令行
虚拟控制台
除了桌面启动终端窗口,ssh连接终端以外,还可以使用 linux 的虚拟控制台,在 RHEL 6 上对应的设备是 /dev/tty2、/dev/tty3、/dev/tty4、/dev/tty5、/dev/tty6
此种运行等级为 run level 3,纯文本终端 (图形登录环境 tty1 的运行等级为 run level 5)
使用 ctrl+alt+f2/f3/f4/f5/f6 可以切换
alt + f3 可以切换为控制台 tty3
这里登录时间后面显示的是主机地址,如果是远程主机则会显示其 ip
默认登录运行级别的设置可以修改 /etc/inittab 文件:
id:3:initdefault:
Shell 命令提示符
[root@rhelserver /etc]#
[]
内的内容即为 Shell 提示符:格式用户名@主机名 当前目录
~
符号是表示用户主目录的 Shell 变量
Shell 命令提示符的显示内容可以通过修改 Shell 的环境变量 PS1 来实现
一些命令
记一些之前没怎么用过的
reboot
# 重启
halt
shutdown
# 关机
cd
# 直接切换到用户主目录
cd -
# 回到前一次工作目录
mkdir [-p/--parents] [目录]
# -p 建立尚不存在的目录,即多层目录
rmdir [-p] [目录]
dmesg
# 查看内核日志
ls -d
# 显示指定目录的详细信息,不显示子目录及文件
ls -R
# 递归列出所有子目录下的文件和目录
ls -i
# 查询inode号
tail [-n] 文件名
head [-n] 文件名
# 查看某文件的末尾/头几行,-n指定行数,默认10行
cut -d\ -f1 data.txt
# -d指定以空格为分隔符,-f指定显示每行分隔出的第一个字段
使用ls命令查看/root/lab4/file目录下的各个文件的inode编号:
grep
grep [-clnvi] <pattern> <files>
-c # 只显示符合字符串模式的总行数
-l # 只显示符合字符串模式的文件的文件名
-n # 显示匹配行的行号
-v # 反选
-i # 忽略大小写
正则表达式
sed
sed [-hnV][-e<script>][-f<script文件>][文本文件]
-e<script>/--expression=<script> # 以选项中指定的script来处理输入的文本文件。
-f<script文件>/--file=<script文件> # 以选项中指定的script文件来处理输入的文本文件。
-n/--quiet/--silent # 仅显示script处理后的结果
Shell 功能
以 Bash Shell 为准
历史命令记忆功能
前一次登录以前所执行过的 Shell 命令被保存在用户主目录下的 .bash_history 文件中
Tab键补全
文件名通配
符号 含义 * 匹配0个或多个字符 ? 匹配任意一个字符 [list] 匹配 list 中的任意单一字符 [c1-c2] 匹配 c1-c2 中的任意单一字符 [!list] 匹配除 list 中的任意单一字符 {string1,string2,…} 匹配 string1 或 string2 (或更多)其一字符串 命令别名 alias
vi 命令行编辑文件
模式
命令模式 –> 文本编辑模式:i、I、a、A、o、O
扩展命令模式:Esc 回到命令模式,输入:
切换到扩展命令模式
退出vi:
wq
保存文件,wq newfile
或w newfile
另存为新文件名q!
不保存退出- 在命令模式下输入
ZZ
,会保存当前文件的修改,并退出 vi 编辑器
vi 命令
命令模式下
命令模式 –> 文本编辑模式
i:从当前光标位置开始输入字符
I:光标移动到当前光标所在行的行首,开始输入字符
a:从当前光标后开始输入字符,也就是在当前光标所在的字符后开始插入新字符
A:光标移动到当前光标所在行的行尾,开始输入字符
o:在当前光标所在行之下新增一行
O:在当前光标所在行之上新增一行
光标移动命令
h:左移,如果在 h 前输入数字 n,则光标左移 n 个字符,下同
l:右移
j:上移
k:下移
0:移到行首
$:移到行尾
G:移动到文件的最后一行的行首
nG:移到第n行的行首
H:移到屏幕上显示的第一行
L:移到屏幕上显示的最后一行
M:移到屏幕的中间一行
w或W:右移至下一个单词的词首
e或E:移动到单词尾,若已处于当前的单词尾则移动到下一个单词尾
b或B:移动到词首,若已处于当前的单词首则移动到上一个单词首
此外,还有扩展模式命令
:n
:光标移到文件的第n行:$
:光标移到文件的最后一行替换删除命令
r:使用随后输入的字符替换当前光标所在的字符
剪切命令
d:剪切选定块到缓冲区
复制命令
y:复制选定块到缓冲区
粘贴命令
p:粘贴到当前光标后
P:粘贴到当前光标前
v 命令进入可视模式,用于选定区域
u 命令撤销前一次修改
查找命令
/pattern:从光标开始处向后搜索 pattern 字符串
?pattern:从光标开始处向前搜索 pattern 字符串
n:在同方向重复上一次搜索命令
N:在反方向重复上一次搜索命令
扩展命令模式中——替换命令s
:s/p1/p2
:将当前行第一次出现的 p1 用 p2 替代:s/p1/p2/g
:将当前行中所有 p1 均用 p2 替代
扩展 Shell 命令
Shell 命令替换
在Bash Shell中,反引号 ` 作为命令替换功能使用,具有内联执行的功能
于是就有了这样的用法:
cd /lib/modules/`uname -r`
Shell 输入/输出的重定向与管道
标准输入/输出
在 Linux 系统中,每条 shell 命令对应的进程都有三个与之相关的输入/输出流,对应特殊的文件描述指针:
- 标准输入,文件描述指针为0:执行该进程时,进程获得用户从键盘输入的数据
- 标准输出,文件描述指针为1:命令执行后传回的正确信息
- 标准错误输出,文件描述指针为2:命令执行失败后传回的错误信息
以 cat 命令为例,如果 cat 的命令行中没有参数,它就会从标准输入中读取数据,并将其送到标准输出,用户输入的每一行都立刻被 cat 命令输出到屏幕上,直到 ctrl+d 结束输入,cat 命令运行结束
输入/输出重定向
输入重定向:把命令(或可执行程序)的标准输入重定向为从指定的文件获取输入数据
命令<文件名
常用于不接受文件名作为输入参数的命令,要输入的内容又存在一个文件时
输出重定向:把命令(或可执行程序)的标准输出或标准错误输出重定向到指定文件中
命令>文件名 1> #stdout 2> #stderr 命令>>文件名 #追加到文件尾
Here Documents 输入重定向:将一对分隔符之间的正文重定向输入给命令
在
<<
操作符后面,任何字符都可以作为正文开始前的分隔符,Here 文档的正文一直延续到另一个分隔符为止,第二个分隔符应出现在新行的开头,即分隔符前面不能有空格,分隔符后面必须是回车符command<<[-] limit_string msg_body limit_string
如果使用
<<-
,则 msg_body 和 limit_string 行中的所有前缀 Tab 字符都将被忽略(但空格不会被忽略)
管道
将一个 shell 命令的输出结果传递给另一个 shell 命令作为输入时,可以使用 linux shell 提供的管道功能
使用管道符|
来建立一个多条 shell 命令联合执行的命令
管道可以把一系列命令连接起来,第一个命令的输入会作为第二个命令的输入通过管道传给第二个命令
Shell 变量
实验
开启一个终端程序,执行命令
echo $PATH
,查看Linux环境变量PATH的值。新建目录“/opt/arm-linux/bin”,在Shell终端中执行以下命令:
export PATH=$PATH:/opt/arm-linux/bin
执行完毕后检查PATH变量的值,是否有加入路径“/opt/arm-linux/bin”,执行exit退出当前Shell,然后再次启动一个终端,查看PATH路径列表,是否有“/opt/arm-linux/bin”
用全屏幕编辑工具vi编写一个文件setenv.sh,在setenv.sh写入能够为环境变量PATH新增路径“/opt/arm-linux/bin”的命令:
export PATH=$PATH:/opt/arm-linux/bin
保存退出vi,然后执行“source setenv.sh”命令,执行完成后再次查看PATH 的结果,检查PATH变量设置效果;关闭当前终端,再次启动一个终端,检查PATH变量是否还有路径“/opt/arm-linux/bin”。
新建目录“/opt/bin”,使用全屏幕编辑工具vi修改系统环境配置文件中PATH变量设置,使得新修改后的PATH变量新增路径“/opt/bin”,要求修改后的PATH路径对每个用户都能生效。保存后注销当前用户登录,并使用root帐号重新登陆一次,再次开启终端并检查PATH变量的路径列表中是否有添加新的路径“/opt/bin”。
把实验5的sdl-image-view.tar.gz中的可执行文件viewimage复制到/opt/bin,测试一下当/opt/bin目录添加到PATH路径后,能否在shell任意当前目录执行该程序
Linux文件系统
FHS 目录树
/:根目录,通常以独立分区挂载
/bin:命令行工具,不能单独挂载为一个分区
/boot:linux启动文件,包括linux内核文件以及启动引导程序的配置文件
/dev:设备与外设接口
/etc:配置文件
/home:存放所有普通用户主目录的目录
/lib:系统函数库,不要以单独的分区挂载此目录
/media:可移动设备的挂载点,如软驱、光驱和U盘
/mnt:挂载某些额外设备
/opt:放置非原 linux 发行版提供的第三方软件
/root:root 主目录,需要与根分区处于同一目录
/sbin:系统管理命令,不要以单独的分区挂载此目录
/tmp:临时文件目录
/usr:与 UNIX 操作系统软件资源相关的目录
/var:与系统运行过程有关
文件与文件类型
“一切皆文件”
普通文件、目录文件
设备文件:系统把每个I/O设备都看成一个文件,通常在 /dev 下
链接文件:硬链接、软链接
管道文件:当两个进程需要进行数据与信息传递时,可以使用管道文件。写入的数据每次都添加到管道缓冲区的末尾,读数据的时候都是从缓冲区的头部读出数据的,管道文件通常建立在内存中
文件系统访问 Shell 命令
依旧记一些少用的
cp 文件1 文件2 文件3 目录
mv 文件1 文件2 文件3 目录
# 复制/移动多个文件到目录
cp -r 源目录 目标目录
# 以递归形式复制整个目录的文件及其下级子目录
rm -f/--force
# 从不提示,直接删除
rm [-i/--interactive]
# 交互式删除,等待用户确认,需要主动输入y进行确认
rm -r/-R/--recursive
# 将参数中列出的全部目录和子目录均递归删除
cat > filename
# 从键盘创建一个文件,结合输出重定向,ctrl+d结束输入
复制 /etc/fstab、/etc/inittab 文件到 /root/lab4/bak/ 目录:
可用cp /etc/fstab /etc/inittab /root/lab4/bak/
复制/etc/passwd文件到/root/lab4/bak/目录,并把该文件重命名为passwd.bk:
使用cat > hello.txt
命令建立文件hello.txt,输入5行英文:
执行view /root/lab4/file/hello.txt
验证文件内容是否是前一步输入的内容:
把/root/lab4/file/hello.txt文件复制到/root/lab4/temp/目录:
删除非空目录/root/lab4/aa:
复制文件 /root/lab4/file/hello.txt 到 /root/lab4/file/ 目录中并命名为hello-new.txt:
从rpm包安装tree
把树形目录列表显示工具 tree 软件安装包文件 tree-1.5.3-2.el6.i686.rpm 通过 winscp 复制到 Linux 虚拟机,进入该 rpm 包所在的目录,执行 rpm 软件包安装命令rpm -ivh tree-1.5.3-2.el6.i686.rpm
安装 tree 工具软件包
使用外部存储设备
vmware 连接U盘到虚拟机中
mount 挂载
umount 卸载
设U盘安装的加载点为 /media/KINGSTON,识别为 /dev/sdb1
umount /dev/sdb1
# 或
umount /media/KINGSTON
mkdir -p /mnt/usbdisk
mount -t vfat -o iocharset=utf8 /dev/sdb1 /mnt/usbdisk
文件系统权限配置与管理
Linux 文件系统支持 UGO(User, Group, Other)访问控制机制
UGO 访问控制模型通过给linux系统中的文件赋予两个属性来起作用:所有者和访问权限
查看文件所有者与文件权限属性:
文件权限位:drwxr-xr-x 文件拥有者:root 文件所属组:4096
文件权限位示意图:
文件类型:"-"为普通文件,"d"为目录文件,"i"为连接文件,"b”为块设备文件,"c"为字符设备文件
权限的数字表示形式:使用3位八进制的数字形式表示某个文件或目录实际配置的权限
如 rwx r-x r-x,其中转换进制:
rwx —— 111 —— 7(二进制转换为八进制)
r-x —— 101 —— 5
文件权限设置
权限修改命令:
chmod [-R] [who] [+ | - | =] [mode] <file_name>/<directory_name>
-R # 表示递归设置,即整个目录树都使用相同的权限配置
who # 表示操作对象,有u(user)、g(group)、o(others)、a(all)可选
+ # 添加权限
- # 取消权限
= # 直接赋予给定的权限,取消所有以前设置的权限
文件拥有者修改命令:
root 用户可以直接修改文件拥有者
chown [-R] <user_name> <directory_name>
文件所在组修改命令:
chgrp [-R] <group_name> <file_name>
Linux用户账号配置与管理
获取登录用户账号信息
id
# 查看用户账号信息,如用户UID、主组GID、用户所属组的信息
ps -l
# 查看当前正在运行进程的详细信息,包括建立进程的UID、进程PID和创建该进程的父进程PPID
ls -ln
# 查看文件系统中文件与目录的拥有者的UID与文件所处的组的GID信息
用户
Linux 是多用户多任务操作系统,从本地或从远程登录的多个用户可以同时使用同一台运行 Linux 操作系统的计算机
Linux 系统内部使用用户ID(UID)来识别用户
在 Linux 系统中所有进行的工作都是以进程的方式进行的,运行的程序都体现为进程
用户账号分为三类:
- 超级用户:root,UID为0,GID为0,最高权限
- 普通用户:只能管理自己启动的进程,只能操作其拥有权限的文件与目录,通常普通用户默认配置的UID值为500~60000
- 系统用户:伪用户,与系统服务相关,UID值为1~499
用户组
具有相同特征或具有某种特定联系的用户的集合,用于表示该组内所有用户的账号称为组账号
Linux 系统中每个用户账号至少属于一个用户组;一个组中可以有多个用户,一个用户也可以属于多个不同的组;一个用户只能属于一个主组,但可以同时属于多个附加组
主组:用户登录 Linux 系统后的默认组,在 /etc/passwd 中的 GID 字段有记载,用户的主组可以切换,使用newgrp 组名
,切换后原先的组变为附加组
用户组分类:
- 标准组
- 系统组
- 私有组
如要使多个用户能查看、修改某一文件或执行某个命令,可以先把这些用户都定义到同一用户组,然后修改文件或目录的权限,让改用户组具有相应的权限
用户与用户组信息文件
用户账号信息 /etc/passwd
用户名:口令(该字段现已为x或*):UID:GID:注释性描述:主目录:登录shell
用户密码信息及其密码时限文件 /etc/shadow
用户名:加密口令:口令最后修改时间:口令最小有效天数:口令最大有效天数:警告时间:不活动时间:账号过期失效时间:标志
用户组信息文件 /etc/group
组名:口令:GID:组内成员列表
用户组密码文件 /etc/gshadow
组名:口令:组管理者:组成员
建立用户和用户组账号
建立用户组
groupadd 选项 用户组名
groupadd -g GID 用户组名
建立用户账号并设定登录密码
useradd 选项 用户名
-u UID # 指定用户账号对应的UID
-g 组名 # 指定用户账号的初始默认组
-G 组名1,组名2,组名3,... # 指定用户所属的附加组
-m # 创建用户主目录
-M # 不建立用户主目录
设置密码
passwd 选项 用户名
--stdin # 从标准输入读取令牌
echo "" | passwd --stdin 用户名
设定组密码与管理组成员
gpasswd [-a user] [-d user][-A user,...][-M user,...][-r][-R] groupname
修改用户账号
usermod 选项 用户名
usermod -m -d /home/new-dir user1
# 修改用户user1的主目录为/home/new-dir,把原来用户的主目录迁移到新目录中
usermod -l new-username user1
# 修改用户user1的用户名为new-username
-g 组名 # 修改用户账号的初始默认组(主组)
-G 组名1 组名2 组名3 # 修改用户所属的附加组
修改用户组信息
groupmod 选项 用户组
groupmod -g 600 group2
# 将组group2的组标识号修改为600
groupmod -g 10000 -n group3 group2
# 将组group2的标识号改为10000,组名修改为group3
删除用户、删除组
groupdel 用户组
userdel -r 用户名
# -r删除用户时也删除用户相关的文件
实验
建立标准组:account (gid=1200)、admin (gid=1000)、sale (gid=1100)
建立一个主组属于admin的帐号 admin-user1,其uid为1001
建立一个附加组属于admin的帐号 admin-user2,其uid为1002
建立一个主组属于sale的帐号 sale-user1,其uid为1101
建立一个附加组属于sale的帐号 sale-user2,其uid为1102
建立一个主组属于account的帐号 account-user1,其uid为1201
建立一个附加组属于account的帐号 account-user2,其uid为1202
建立一个主组属于admin,附加组属于sale、account的用户帐号 admin-all,uid为1000
建立完用户后 ,给这些用户设定初始密码"123456"
建立两个新组 fjnumcs、fjnu
建立用户 jack、lucy,并把其主组设置为 fjnumcs,附加组设置为 fjnu
口令时限机制
每个用户账号的口令时效配置参数体现在 /etc/shadow
设置口令时效信息有两种方式:
- 对所有新建立的用户自动设置并启动口令时效机制,需要修改建立用户的默认配置文件 /etc/login.defs 以及 /etc/default/useradd
- 对已经建立好的用户账号,可以用
chage
命令修改口令时效参数
在 /etc/login.defs 修改系统关于口令的默认设置,使得密码长度不小于8位,口令有效期为60天
/etc/default/useradd
INACTIVE(口令从过期到锁定的时间)
EXPIRE(失效日期)
情景实验:Linux用户组共享目录权限配置
某公司新来了5个合约为2年的员工(jack、tom、jerry、jason、ketty),这些人员成立了一个研发团队,为这些员工建立一个用户账号,并为建立用户账号把新建立的员工归属到附加组g_deepmind。要求,设定每个员工需要每隔90天修改密码,账号有效期到2023年12月31日。
为研发团队g_deepmind建立一个组共享目录/home/g_deepmind,使得g_deepmind组中的用户能够通过该共享目录/home/g_deepmind相互共享并交换文件,要求用户在该目录中建立的文件能够不能被其他用户随意删除(目录拥有者除外,可以设置目录拥有者为项目组长),并且自动与用户组成员共享。
建立临时用户t_user1、t_user2,配置用户组g_deepmind,使得临时用户也可以切换g_deepmind为主组登陆系统,临时访问组共享目录/home/g_deepmind。
Linux软件包安装与管理
软件包依赖性
任务1:运行预先编译好的jpg图片查看可执行程序viewimage
任务2: 编译运行源码软件,cmatrix-1.2a.tar.gz
软件编译安装
尝试在rhel6.3或者ubuntu18.04系统中编译fswebcam
上传并解压fswebcam_20140113.orig.tar.xz
./configure
报错configure: error: GD graphics library not found
安装 GD 库
yum install gd-devel
不幸的是查无此库
尝试从源码编译 gd-devel,源码包下载:https://github.com/libgd/libgd/releases/download/gd-2.3.2/libgd-2.3.2.tar.xz
./configure
make&&make install
这样就可以编译 fswebcam 了
./configure
make&&make install
尝试以不同分辨率运行
fswebcam -r 800x600 --no-banner d1.jpg -d /dev/video0
fswebcam -r 960x720 --no-banner d2.jpg -d /dev/video0
fswebcam -r 640x480 --no-banner d3.jpg -d /dev/video0
fswebcam -D 10 -r 640x480 --no-banner d3.jpg -d /dev/video0
fswebcam -D 2 --title "welcome" -r 640x480 d3.jpg -d /dev/video0
执行时报错fswebcam: error while loading shared libraries: libgd.so.3: cannot open shared object file: No such file or directory
,没找到库文件
全局搜索对应文件并添加 LD_LIBRARY_PATH
find / -name "libgd.so.3"
export LD_LIBRARY_PATH=/root/ex_lab/libgd-2.3.2/src/.libs:$LD_LIBRARY_PATH
然后就可以成功运行了
RPM&YUM(CentOS系)
启动RHEL6.3虚拟机,使用root登陆,加载RHEL6.3安装光盘
使用“rpm -qa | grep -i SDL” 查看Linux系统中已经安装的软件包列表中是否包括有SDL、SDL-devel(SDL是一种游戏引擎开发库,SDL-devel是其对应开发包),如果有安装SDL-devel软件包,请使用rpm工具的卸载命令SDL-devel软件包;
使用rpm查询系统已经安装软件的命令查看Linux系统中是否已经安装SDL_image、SDL_image-devel软件包
进入光盘安装加载目录,在RHEL6.3安装光盘Packages目录中的查找SDL、SDL-devel以及alsa-lib-devel对应的rpm安装文件
使用查询rpm软件包中文件列表的命令
rpm -qpl
查看实验资源目录lab6中的SDL_image-1.2.12-9.el6.i686.rpm、SDL_image-devel-1.2.12-9.el6.i686.rpm两个rpm文件中包含有哪些文件使用查询rpm软件包中文件列表的命令
rpm -qpl
查看SDL-1.2.14-3.el6.i686.rpm、SDL-devel-1.2.14-3.el6.i686.rpm 两个rpm软件包安装文件中包含有哪些文件找出RHEL6.3安装光盘Packages目录中的libjpeg、libjpeg-devel软件包对应的rpm文件,使用rpm查询命令并找出当安装这2个rpm包将会向Linux文件系统安装了哪些文件?
尝试使用rpm工具的安装命令安装SDL_image库对应的两个软件包: SDL_image-1.2.12-9.el6.i686.rpm、SDL_image-devel-1.2.12-9.el6.i686.rpm。
尝试使用rpm工具的安装命令安装SDL_image库对应的两个软件包: SDL-1.2.14-3.el6.i686.rpm、SDL-devel-1.2.14-3.el6.i686.rpm。
使用提供的yum本地源配置文件rhel-local.repo,配置RHEL6.3的安装光盘成为yum的本地源,并使用yum工具安装SDL-devel-1.2.14-3.el6.i686.rpm。
复制rhel-local.repo到/etc/yum.repos.d目录;
执行yum repolist查看yum是否正确配置本地yum源;
使用rpm工具查询当前系统是否安装软件包tree,如果已经安装,请尝试使用yum命令卸载tree,然后使用yum install tree命令安装tree软件包;
进入实验目录/root/lab6-xxx-xxx,执行以下命令安装rpm软件SDL-devel,注意观察安装过程中都安装了哪些软件包:
“yum install SDL-devel-1.2.14-3.el6.i686.rpm”
Linux Shell脚本编程
系统变量
${n}
:位置变量
$?
:保存前一条 Shell 命令的执行返回值。通常0代表执行成功,非0代表执行有误
$*
:以"$1 $2” 形式保存的所有的命令行参数,作为一个单独的变量
$@
:以"$1” "$2” 形式保存的所有命令行参数,作为一个集合使用
$0
:当前运行的脚本路径
$$
:返回当前进程的PID
数组
name=(value0 value1 value2 value3 ...)
name[0]=value0
name[1]=value1
${ARRAY_NAME[n]}
:取得数组中的元素
${ #ARRAY_NAME[@]}
或${ #ARRAY_NAME[*]}
:取得数组元素的个数
${ #ARRAY_NAME[n]}
:取得数组中单个分量的长度
键入
内部命令 read
,用于从键盘读入变量
read -p "提示语句" varname、
read -n 字符个数 varname
read -t 时间 varname # 等待时间
read -s varname # 关闭回显
read -a arrayname # 输入数组
数学运算
let
命令:在完整的赋值型数学表达式前加上 let 命令,就可以完成整数运算表达式的计算并赋值
expr
命令:
expr 操作数 运算符 操作数
$(())
与$[]
:数学表达式计算
bc
:浮点数计算
实验
编写shell脚本count-fix.sh,实现计算1+2+3+4+5+6+7+8+…+100的和,并输出到屏幕上,分别使用for循环,while循环编写
#!/bin/bash sum_for=0 for ((i=1; i<=100; i++)) do sum_for=$((sum_for + i)) done echo "for: $sum_for" sum_while=0 j=1 while [ $j -le 100 ] do sum_while=$((sum_while + j)) j=$((j + 1)) done echo "while: $sum_while"
使用bash的for循环语句编写一脚本batchmkdir.sh,能实现以下功能:在当前目录中建立10个目录,目录的命名形式为dir-1、dir-2、dir-3、…..dir-20,在程序中注意先判断待建立的目录是否已经存在。
#!/bin/bash for ((i=1; i<=10; i++)) do dir_name="dir-$i" # 检查目录是否已存在 if [ ! -d "$dir_name" ]; then mkdir "$dir_name" fi done
编写一个shell脚本count.sh,实现如下功能,用户可以在count.sh脚本后面跟不同数字的命令行参数,使得脚本能计算不同数字的连加和,并在脚本中注意判断用户是否输入了一个参数,如当用户以“./count.sh 30”运行脚本时,能计算1+2+3+4+…+30,如果用户没有输入参数,则默认计算1到10的连加和。
#!/bin/bash if [ $# -eq 0 ]; then end_num=10 else end_num=$1 fi sum=0 for ((i=1; i<=$end_num; i++)) do sum=$((sum + i)) done echo "和为: $sum"
编写一个脚本batchuser.sh,能批量建立10个用户帐号,并给用户帐号设定8位的随机密码,同时把该用户名与密码保存到指定的文件中/root/user-pass.txt,以便管理员分发密码;其中帐号的形式为user1、user2、…user10;保存用户名与密码的文件的每行的格式形式为:user1:ChczVZww
#!/bin/bash for ((i=1; i<=10; i++)) do username="user$i" password=$(openssl rand -base64 6) useradd -m $username echo -e "$password\n$password" | passwd $username --stdin echo "$username:$password" >> /root/user-pass.txt done
编写一个shell脚本,实现以下功能:该脚本能读取usernamelist.txt中的用户列表(一行一个用户名)建立帐号,并给每个帐号设置8位随机密码,同时把该用户名与密码保存到指定userpass.txt 文件中,密码文件的格式同第4题的要求。要求要跳过空行。
#!/bin/bash while IFS= read -r username do if [ -z "$username" ]; then continue fi password=$(openssl rand -base64 6) useradd -m $username echo -e "$password\n$password" | passwd $username --stdin echo "$username:$password" >> userpass.txt done < "usernamelist.txt"
脚本capprintfile.sh
for file in "$@" do echo $file|tr a-z A-Z done
建立目录 /root/lab-shell/,并使用 touch 命令建立一些空文件或者使用 mkdir 建立一些目录,然后以
./capprintfile.sh / /root/lab-shell/*
的形式运行脚本,观察结果编写一个脚本,能把指定目录/root/lab-shell/中的文件的文件名全改名为大写,并测试运行
#!/bin/bash cd /root/lab-shell/ for file in * do if [ -f "$file" ]; then new_name=$(echo "$file" | tr '[:lower:]' '[:upper:]') mv "$file" "$new_name" fi done echo "Finished"
设计一个脚本checkmd5.sh,实现用于检测Linux系统某些特定重要文件是否被修改的功能
#!/bin/bash if [ "$#" -ne 1 ]; then echo "Usage: $0 <file_list_with_md5sum>" exit 1 fi if [ ! -f "$1" ]; then echo "Error: 文件列表不存在." exit 1 fi while IFS= read -r line do file=$(echo "$line" | awk '{print $1}') expected_md5=$(echo "$line" | awk '{print $2}') current_md5=$(md5sum "$file" | awk '{print $1}') if [ "$current_md5" != "$expected_md5" ]; then echo "文件 $file 已被修改!" else echo "文件 $file 未被修改。" fi done < "$1"
#!/bin/bash
# 检查参数是否正确
if [ $# -ne 1 ]; then
echo "Usage: $0 <ip_list_file>"
exit 1
fi
ip_list_file=$1
# 检查文件是否存在
if [ ! -f "$ip_list_file" ]; then
echo "Error: File $ip_list_file not found."
exit 1
fi
# 逐行读取 IP 地址并进行 ping 测试
while IFS= read -r ip; do
echo "Pinging IP: $ip"
ping -c 1 $ip > /dev/null
if [ $? -eq 0 ]; then
echo "Ping successful"
else
echo "Ping failed"
fi
done < "$ip_list_file"
Linux gcc源码编译
环境配置
在新版本的Linux发行版中,这里选择银河麒麟,安装配置vscode,尝试配置好c/c++的编程开发环境
在vscode官网上下载deb:https://code.visualstudio.com/docs/?dv=linux64_deb
然后安装
sudo dpkg -i code_1.95.3-1731513102_amd64.deb
接下来配置c/c++的开发环境
先准备好 gcc , g++ 和 gdb
然后在vscode扩展商店下载相关扩展
接下来在工作区生成launch.json和tasks.json
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "g++ - Build and debug active file",
"type": "cppdbg",
"request": "launch",
"program": "${fileDirname}/${fileBasenameNoExtension}",
"args": [],
"stopAtEntry": false,
"cwd": "${fileDirname}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
],
"preLaunchTask": "C/C++: g++ build active file",
"miDebuggerPath": "/usr/bin/gdb"
}
]
}
{
"version": "2.0.0",
"tasks": [
{
"type": "cppbuild",
"label": "C/C++: g++ build active file",
"command": "/usr/bin/g++",
"args": [
"-g",
"${file}",
"-o",
"${fileDirname}/${fileBasenameNoExtension}"
],
"options": {
"cwd": "${fileDirname}"
},
"problemMatcher": [
"$gcc"
],
"group": {
"kind": "build",
"isDefault": true
},
"detail": "compiler: /usr/bin/g++"
}
]
}
然后f5调试与编译
实验1
math_pic_png.c 是一个能够自动生成一张 1024*1024 的数学分形图像的c代码,生成的图像效果如 math_png_rgb.png 文件所示
尝试在 rhel 6.3、ubuntu18.04 中编译出可执行程序,并测试运行
math_pic_png.c
#include <stdlib.h>
#include <stdint.h>
#include <time.h>
#include <string.h>
#include <png.h>
typedef struct pixel_RGB {
png_byte red, green, black;
} pixel_RGB;
uint8_t random_uint8() {
return rand() % 256;
}
void write_data_to_png(
const char *png_name,
png_uint_32 width,
png_uint_32 height,
png_bytepp data,
int color_type) {
FILE *fp = fopen(png_name, "wb");
png_structp png =
png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
png_infop info = png_create_info_struct(png);
png_init_io(png, fp);
png_set_IHDR(
png,
info,
width,
height,
8,
color_type,
PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
png_write_info(png, info);
png_write_image(png, data);
png_write_end(png, NULL);
png_destroy_write_struct(&png, &info);
fclose(fp);
}
//===Mandelbrot ����ͼ��
unsigned char RD(int i,int j){
float x=0,y=0;int k;for(k=0;k++<256;){float a=x*x-y*y+(i-768.0)/512;y=2*x*y+(j-512.0)/512;x=a;if(x*x+y*y>4)break;}
return log(k)*47;
}
unsigned char GR(int i,int j){
float x=0,y=0;int k;for(k=0;k++<256;){float a=x*x-y*y+(i-768.0)/512;y=2*x*y+(j-512.0)/512;x=a;if(x*x+y*y>4)break;}
return log(k)*47;
}
unsigned char BL(int i,int j){
float x=0,y=0;int k;for(k=0;k++<256;){float a=x*x-y*y+(i-768.0)/512;y=2*x*y+(j-512.0)/512;x=a;if(x*x+y*y>4)break;}
return 128-log(k)*23;
}
int main(int argc, char **argv) {
srand(time(NULL));
png_uint_32 x,y;
png_uint_32 png_size ;
if(argc<2)
{
printf("using defalut 1024,you can input png_size,usage: %s png_size\n",argv[0]);
png_size = 1024;
}
else
{
png_size = strtoul(argv[1], NULL, 10);
}
const char *math_png_rgb = "math_png_rgb.png";
pixel_RGB *image_data_rgb = calloc(png_size * png_size, sizeof(pixel_RGB));
pixel_RGB **row_ptrs_rgb = calloc(png_size, sizeof(pixel_RGB *));
for ( y= 0; y < png_size; y++) {
row_ptrs_rgb[y] = &image_data_rgb[y * png_size];
for (x = 0; x < png_size; x++) {
row_ptrs_rgb[y][x].red = RD(x,y)&255;
row_ptrs_rgb[y][x].green = GR(x,y)&255;
row_ptrs_rgb[y][x].black = BL(x,y)&255;
}
}
write_data_to_png(
math_png_rgb,
png_size,
png_size,
(png_bytepp)row_ptrs_rgb,
PNG_COLOR_TYPE_RGB);
free(row_ptrs_rgb);
free(image_data_rgb);
return 0;
}
直接编译会报错:
[root@rhel6 ex7]# gcc -o math_pix_png math_pix_png.c
math_pix_png.c: 在函数‘RD’中:
math_pix_png.c:55: 警告:隐式声明与内建函数‘log’不兼容
math_pix_png.c: 在函数‘GR’中:
math_pix_png.c:60: 警告:隐式声明与内建函数‘log’不兼容
math_pix_png.c: 在函数‘BL’中:
math_pix_png.c:65: 警告:隐式声明与内建函数‘log’不兼容
/tmp/ccPI6QFP.o: In function `write_data_to_png':
math_pix_png.c:(.text+0x5b): undefined reference to `png_create_write_struct'
math_pix_png.c:(.text+0x69): undefined reference to `png_create_info_struct'
math_pix_png.c:(.text+0x7e): undefined reference to `png_init_io'
math_pix_png.c:(.text+0xc5): undefined reference to `png_set_IHDR'
math_pix_png.c:(.text+0xd7): undefined reference to `png_write_info'
math_pix_png.c:(.text+0xe9): undefined reference to `png_write_image'
math_pix_png.c:(.text+0xfc): undefined reference to `png_write_end'
math_pix_png.c:(.text+0x10e): undefined reference to `png_destroy_write_struct'
/tmp/ccPI6QFP.o: In function `RD':
math_pix_png.c:(.text+0x1c7): undefined reference to `log'
/tmp/ccPI6QFP.o: In function `GR':
math_pix_png.c:(.text+0x297): undefined reference to `log'
/tmp/ccPI6QFP.o: In function `BL':
math_pix_png.c:(.text+0x367): undefined reference to `log'
collect2: ld 返回 1
很明显缺头文件了,在 c 文件头部引入一个<math.h>
,然后需要链接 libpng 库进行编译
gcc -o math_pix_png math_pix_png.c -lpng
实验2
使用gcc命令把hello-c.tar.gz中的hello.c编译成可执行程序hello,运行查看效果,并使用ldd命令查看hello调用的相关外部函数库信息、使用file命令查看hello的信息。
把第一步编译生成的可执行程序hello删除,查看编译hello.c对应的Makefile,使用make工具编译该程序,检查编译结果。
解压并使用make命令编译math-c.tar.gz代码,阅读该压缩包中的Makefile,尝试直接使用gcc命令把mathtest.c编译成可执行程序mathsqrtdemo
使用rpm -q查询sqlite函数库以及sqlite开发库是否已经安装,如果没有安装,请从光盘安装sqlite函数库及其开发包对应的rpm文件,并查询这2个rpm软件安装包向Linux系统安装了哪些文件。
编译调用了轻量级数据库sqlite3函数库的C程序代码。
sqlite-test-2目录中的源码文件sqlite-test.c为一个使用C语言结合sqlite api编写的sqlite3数据库访问程序使用make命令编译生成可执行程序
提示:编译成功后,按“sqlite-test a.db”格式运行该程序,查看运行效果阅读分析sqlite-test.c对应的Makefile文件,理解pkg-config命令的作用
pkg-config 的作用是帮助 gcc 命令获取关于 SQLite3 库的编译和链接信息,包括需要添加的头文件路径和库文件路径
使用make clean清除现有的编译成功的可执行程序sqlite-test
阅读sqlite-test-demo.tar.gz压缩包中的Makefile,对比两个版本的Makefile的写法差异。
-lsqlite3
选项会直接链接 SQLite3 库前者使用
pkg-config --cflags --libs sqlite3
来获取 SQLite3 库的编译和链接信息
尝试编译 hello-gtk-2.0目录中的代码并运行,阅读并理解该代码及其Makefile文件
这个 Makefile 文件的作用是编译 hello-gtk2.c 文件,并链接 gtk+-2.0 库,以生成可执行文件 hello-gtk2。使用 pkg-config 可以方便地获取所需库的编译和链接信息
aes-demo.tar.gz是一个调用openssl库进行aes加密解密的C源代码,尝试编译运行该代码,并阅读Makefile文件,分析其编译gcc命令。
gcc命令中用
-l
链接 ssl 库和 crypto 库