-
Linux 系统中,用户和组的定义以及密码信息存放于哪四个核心配置文件中?请用表格详细说明每个文件各字段的含义,并解答:为什么有了 /etc/passwd 还需要 /etc/shadow?/etc/shadow 中用户的密码字段以 $6$ 开头,这代表什么加密算法?后面的字符串是如何构成的?
用户和组的核心文件:
[root@Rocky-01 ~]# ll /etc/passwd //用于存放用户基本信息 -rw-r--r--. 1 root root 2028 May 30 16:04 passwd [root@Rocky-01 ~]# ll /etc/shadow //用于存放用户密码及安全属性相关信息 ----------. 1 root root 1104 May 30 16:04 shadow [root@Rocky-01 ~]# ll /etc/group //用于存放用户组基本信息 -rw-r--r--. 1 root root 790 May 30 16:04 group [root@Rocky-01 ~]# ll /etc/gshadow //用于存放用户组组密码、组管理员信息 ----------. 1 root root 633 May 30 16:04 gshadow
各字段详细信息说明:

/etc/passwd 、 /etc/shadow:
分开存放是为了保护密码密文,拆分敏感数据,提升系统安全性。
/etc/passwd默认全局可读(权限644),所有用户都能查看密文,暴力破解风险极高。/etc/shadow,该文件权限为000,仅 root 用户可读取,普通用户无法访问。shadow 额外提供密码有效期、过期提醒、账号失效等安全策略,单纯 passwd 无法实现复杂密码安全管控。[root@Rocky-01 ~]# ll /etc/passwd -rw-r--r--. 1 root root 2028 May 30 16:04 passwd [root@Rocky-01 ~]# ll /etc/shadow ----------. 1 root root 1104 May 30 16:04 shadow
$6$表示使用 SHA-512 哈希算法(Linux 默认主流密码加密算法)。常见标识:
$1$:MD5$5$:SHA-256$6$:SHA-512构成:
$6$xx$xxxx $算法标识$盐值$加密密文
-
详细说明 r (读)、w (写)、x (执行) 权限在文件和目录上的本质区别?如果一个普通用户对某个目录仅有 w 权限,但没有 x 权限,他能在这个目录下创建文件吗?为什么?
针对文件以及目录的区别:
文件:权限控制文件内容的访问、修改、运行
目录:权限控制目录本身的查看、增删、进入
普通用户只有
w权限时无法在目录下创建文件,经过测试只有对目录同时具有w、x权限时才能创建文件,目录的x权限是路径访问权限。没有x,系统不允许cd进入该目录,也无法定位、操作该目录内部。哪怕有w权限,系统也无法完成 “在该目录下写入新文件条目” 的底层寻址,创建操作直接失败。[g@Rocky-01 tmp]$ ll /tmp/ | grep test drwxrw-rw-. 2 root root 19 Jun 10 15:27 test [g@Rocky-01 tmp]$ touch /tmp/test/b.txt touch: cannot touch '/tmp/test/b.txt': Permission denied [g@Rocky-01 tmp]$ ll /tmp/ | grep test drwx--x--x. 2 root root 19 Jun 10 15:27 test [g@Rocky-01 tmp]$ touch /tmp/test/b.txt touch: cannot touch '/tmp/test/b.txt': Permission denied [g@Rocky-01 tmp]$ ll /tmp/ | grep test drwxr-xr-x. 2 root root 19 Jun 10 15:27 test [g@Rocky-01 tmp]$ touch /tmp/test/b.txt touch: cannot touch '/tmp/test/b.txt': Permission denied [g@Rocky-01 tmp]$ ll /tmp/ | grep test drwx-wx-wx. 2 root root 19 Jun 10 15:27 test [g@Rocky-01 tmp]$ touch /tmp/test/b.txt
-
什么是 umask?说明其计算逻辑。若系统全局默认 umask 为 022,为什么新创建的文件默认权限是 644,而新建目录是 755?如果是 umask 023 呢?
umask是用户文件创建掩码,是Linux系统的默认权限,采用减法规则。当新建目录或文件时,用最大权限-umask=最终权限 ,系统默认最大权限文件为777,目录为666
新建文件:777-022=755 新建目录:666-022=644
如果umask为023时:
新建文件:777-023=754 新建目录:666-023=643
-
详解 Linux 的三种特殊权限:SUID、SGID、Sticky(粘滞位)的作用、表现形式(在 ls -l 输出中的字符位置及大小写区别)以及它们各自的生产应用场景。
SUID:Set User ID 让普通用户在执行时临时拥有属主的权限,主要用于需要临时提升权限的可执行文件,如
passwd、su、sudo等,表现形式体现在 文件属主的 x 执行权限位,有x权限时小写s,无x权限时大写S,如下:-rwsr-xr-x (有SUID,且有x权限) -rwSr--r-- (有SUID,但无x权限)
SGID:Set Group ID 让文件执行时临时拥有所属组的权限,目录下创建文件或目录自动继承目录所属组,主要作用于需要团队共享目录、协作开发目录、公共数据目录等场景,表现形式体现在 所属组的 x 执行权限位,有
x权限时小写s,无x权限时大写S,如下:drwxr-sr-x (有SGID,且有x权限) drwxr-Sr-x (有SGID,但无x权限)
Sticky Bit:当设置粘滞位权限时,目录下的文件或文件夹只允许所有者、目录所有者、root 能删除 / 重命名,其他用户即使有
w权限也不能删除别人的文件,主要用于需要多人可写但不能互删文件的公共目录,如/tmp,/var/tmp。表现形式体现在其他人的 x 权限位,有x权限时小写t,无x权限时大写T,如下:drwxrwxrwt (有Sticky,且有x权限) drwxrwxrwT (有Sticky,且无x权限)
-
对比 locate 和 find 命令的工作机制、优缺点及适用场景。为什么新建一个文件后,立刻用 locate 搜不到?如何解决?
对比项 find 命令 locate 命令 工作机制 实时遍历目录 / 磁盘,逐个文件检查 读取系统预生成的文件路径数据库,不查真实磁盘 速度 慢(遍历磁盘) 极快(查数据库) 准确性 100% 准确,查到就是真实存在 不一定实时,数据库没更新就搜不到新文件 搜索范围 可指定任意目录、条件(权限、大小、时间) 只能搜文件名 / 路径 功能强弱 强(可按权限、类型、时间、大小搜索) 弱(仅文件名模糊匹配) 系统资源 高(大量 I/O) 极低 是否实时 实时 非实时 因为 locate 不搜索真实磁盘,只搜索系统数据库。新建的文件还没被收录到数据库里,所以搜不到。系统默认每天自动更新一次数据库,未更新前,新文件都查不到。手动执行
updatedb,执行完再用locate,就能搜到刚创建的文件了。 -
在 ubuntu 环境中,如何使用 cat 和 EOF 标志,非交互式地向系统配置文件 /etc/hosts.bak 中追加以下三行内容?
192.168.1.100 k8s-master 192.168.1.101 k8s-node1 192.168.1.102 k8s-node2
cat << EOF >>/etc/hosts.bak 192.168.1.100 k8s-master 192.168.1.101 k8s-node1 192.168.1.102 k8s-node2 EOF

-
创建一个名为 sysadm 的系统用户组,指定 GID 为 2000。创建一个名为 ops_user 的系统用户,要求:其主组为 sysadm,附加组为 wheel(或 sudo)。其家目录指定为 /data/home/ops_user,且在创建时自动建立家目录。指定其登录 Shell 为 /bin/bash。生产中需要临时禁用和启用用户 ops_user 的登录权限,分别写出锁定和解锁的命令。如何利用非交互式命令(如 chpasswd)将用户 ops_user 的密码修改为 Ops@2026#Sec?
groupadd -g 2000 sysadm ///创建用户组 useradd -g sysadm -G wheel -m -d /data/home/ops_user -s /bin/bash ops_user ///创建用户 passwd -l ops_user ///临时锁定该用户 passwd -u ops_user ///解除用户锁定 echo "ops_user:Ops@2026#Sec" | chpasswd ///设置用户密码
-
现有一个目录 /data/shares。为了防止被普通用户误删,我们需要保证:所有用户都可以在该目录下创建文件 and 目录。用户只能删除自己创建的文件,不能删除其他用户的文件。请写出创建该目录并设置相应权限的完整命令。
[root@Rocky-01 /]# mkdir -p /date/shares [root@Rocky-01 /]# cd /date/ [root@Rocky-01 date]# ll total 0 drwxr-xr-x. 2 root root 6 Jun 11 16:09 shares [root@Rocky-01 date]# chmod +t shares/ [root@Rocky-01 date]# ll total 0 drwxr-xr-t. 2 root root 6 Jun 11 16:09 shares
-
为了防止恶意软件或人为失误修改系统核心文件 /etc/resolv.conf,我们需要将其设置为“即使是 root 用户也无法修改和删除,只能读取”。请写出设置和撤销此状态的命令。
[root@Rocky-01 ~]# lsattr /etc/resolv.conf ---------------------- /etc/resolv.conf [root@Rocky-01 ~]# chattr +i /etc/resolv.conf [root@Rocky-01 ~]# lsattr /etc/resolv.conf ----i----------------- /etc/resolv.conf [root@Rocky-01 ~]# chattr -i /etc/resolv.conf
-
很多时候在编写 Python 脚本或 YAML 配置文件时,我们希望将 Vim 的 Tab 键自动转换成 4 个空格,并且显示行号。请写出要在当前用户的家目录下的配置文件中添加哪些属性行?
cat <<EOF >> ~/.vimrc " 显示行号 set number " Tab 转为空格 set expandtab " 一个 Tab 对应 4 个空格 set tabstop=4 " 缩进时也使用 4 个空格 set shiftwidth=4 " 智能缩进对齐 set softtabstop=4 EOF
-
在 Vim 中,如何非交互地将当前打开的文件中,第 10 行到第 50 行之间的所有 http:// 字符串替换为 https://?
:10,50s/http:\/\//https:\/\//g
-
生产环境磁盘空间告急,请写出一条命令:在 /var/log/目录中,查找所有文件名以 .log 结尾、大小大于 50MB 且在 7 天以前修改过的普通文件,并将它们打包压缩备份至 /tmp/log_backup.tar.gz,随后将原文件安全删除。
find /var/log/ -type f -name "*.log" -size +50M -mtime +7 -print0 |tar -czf /tmp/log_backup.tar.gz --null -T - && find /var/log/ -type f -name "*.log" -size +50M -mtime +7 -delete
-
演示如何使用 tar 工具打包 /etc 目录,但是排除掉 /etc/udev 和 /etc/selinux 这两个子目录。
tar -czf etc_backup.tar.gz --exclude=/etc/udev --exclude=/etc/selinux /etc ///打包/etc目录 tar -tzf etc_backup.tar.gz | grep -E "udev|selinux" ///检查打包文件是否含有排除目录
-
假设有一个名为 user_info.txt 的文件,每行格式如下:username:department:phone_number:address。请分别使用以下工具提取:
-
使用 cut 提取第一列的用户名。
[root@Rocky-01 etc]# cat /home/user_info.txt alice:Engineering:555-1234:123 Maple St, Springfield bob:Sales:555-5678:456 Oak Ave, Metropolis carol:Human Resources:555-8765:789 Pine Rd, Gotham dave:Engineering:555-4321:101 Elm Dr, Star City eve:Marketing:555-9999:202 Birch Ln, Smallville [root@Rocky-01 etc]# cut -d ':' -f 1 /home/user_info.txt alice bob carol dave eve [root@Rocky-01 etc]# cut -d ':' -f 1,4 /home/user_info.txt alice:123 Maple St, Springfield bob:456 Oak Ave, Metropolis carol:789 Pine Rd, Gotham dave:101 Elm Dr, Star City eve:202 Birch Ln, Smallville
-
使用 tr 将文本中的 : 替换为空格。
[root@Rocky-01 etc]# tr ':' ' ' < /home/user_info.txt alice Engineering 555-1234 123 Maple St, Springfield bob Sales 555-5678 456 Oak Ave, Metropolis carol Human Resources 555-8765 789 Pine Rd, Gotham dave Engineering 555-4321 101 Elm Dr, Star City eve Marketing 555-9999 202 Birch Ln, Smallville
-
-
有些同学在删除查找到的千万级临时文件时,直接运行 find /tmp -name "*.tmp" -exec rm -f {} \;,请解答:
-
该命令有什么性能弊端?
-
每个文件都启动一个
rm进程-exec ... {} \;会为每一个匹配到的文件单独执行一次rm命令。这意味着要创建、运行并销毁千万次进程,系统调用开销(fork()/exec())极大,CPU 上下文切换频繁,执行时间会非常长(可能数小时甚至更久)。 -
无法利用批量删除
rm本身可以一次删除多个文件,但该写法强制一次只处理一个文件,完全放弃了批量化操作的优势。 -
内存与 I/O 压力
find在遍历大型目录树时本身会消耗 I/O 和目录项缓存,加上逐文件启动rm,会使磁盘 I/O 模式变得碎片化,进一步降低效率。
-
-
如何使用 xargs 进行优化?其运行原理是什么?
find /tmp -name "*.tmp" -print0 | xargs -0 rm -f
-
find -print0将匹配的文件路径以 null 字符(\0) 分隔输出,而非默认的换行符。这样可以避免文件名中特殊字符(空格、换行等)导致的解析歧义。 -
xargs -0表示从标准输入读取以 null 分隔的参数列表,并按批次构建命令行。 -
xargs会尽量将多个文件名填入一个命令行(受系统ARG_MAX限制,通常可达几 MB),然后一次性执行rm -f 文件1 文件2 ...。 -
对于千万级文件,
xargs会分批执行多次rm,但执行的次数仅为(文件总数) / (每批数量),相比每个文件一次rm减少了 千万倍 的进程创建开销,因此效率大幅提升。
-
-
若文件名包含空格,优化命令会有何安全隐患?如何彻底规避?
-
find默认以换行符分隔文件名输出,而xargs默认以空白字符(空格、换行、制表符)作为分隔符。 -
以
my tmp file.tmp为例,文件名会被xargs拆分成 三个独立参数:my、tmp、file.tmp。 -
结果:
rm会尝试删除当前目录下名为my、tmp的文件(很可能不存在),而真正的文件my tmp file.tmp不会被删除。这不仅导致删除失败,还可能误删其他同名文件(如果恰好存在名为my或tmp的文件),造成数据丢失或遗漏。 -
-print0保证文件名内的任何字符(包括空格、换行、引号、反斜杠)都原样输出,并以\0作为唯一分隔符。 -
xargs -0采用相同的\0分隔方式解析输入,确保每个文件名作为一个完整的参数传递给rm。
-
-
-
研发部要求在 Rocky 环境下,导入 1000 个格式为 testuser001 到 testuser1000 的测试账号,并要求设置不同的初始随机密码。请回答:
-
为什么不能直接写 for 循环调用 useradd + passwd?
-
性能极低:循环体内每次调用
useradd和passwd都会启动一个独立的进程。创建 1000 个用户需要执行 2000 次外部命令,频繁的fork()/exec()系统调用和进程上下文切换会消耗大量 CPU 时间,尤其是在虚拟机或容器环境下可能耗时数分钟甚至更久。 -
密码设置非交互不便:
passwd命令默认需要交互式输入,虽然--stdin选项可以接受管道输入,但不同发行版支持情况不同(Rocky Linux 中passwd默认不支持--stdin,需使用chpasswd或openssl配合)。强行使用管道还可能暴露密码在命令行参数中(通过/proc可被其他用户窥探)。 -
错误处理困难:若循环中某个用户创建失败(例如用户名已存在),后续用户仍会尝试创建,且难以回滚。
-
-
请使用 newusers 和 chpasswd 给出一种高效率的一体化解决方案。
#!/bin/bash PASSWD_FILE="/tmp/user_passwords.txt" NEWUSERS_FILE="/tmp/newusers_input.txt" > "$PASSWD_FILE" > "$NEWUSERS_FILE" #for u in $(seq -f "%03g" 1 1000); do # userdel -r "testuser$u" 2>/dev/null #done for i in $(seq -f "%03g" 1 1000); do username="testuser$i" # 生成 12 位随机密码 password=$(tr -dc 'A-Za-z0-9!@#$%^&*' < /dev/urandom | head -c 12) echo "$username:$password" >> "$PASSWD_FILE" # 正确格式:用户名:密码:UID:GID:GECOS:家目录:shell echo "$username:x::::/home/$username:/bin/bash" >> "$NEWUSERS_FILE" done newusers < "$NEWUSERS_FILE" || { echo "newusers 失败"; exit 1; } chpasswd < "$PASSWD_FILE" || { echo "chpasswd 失败"; exit 1; } rm -f "$NEWUSERS_FILE" echo "成功创建 1000 个用户,密码保存在 $PASSWD_FILE"
-
[5]
-
基础正则表达式(BRE)与扩展正则表达式(ERE)在元字符支持上有何本质区别?请举例说明在 grep 和 sed 命令中,若使用 ERE 应如何加选项或进行转义?
基础正则表达式 (BRE) 和 扩展正则表达式 (ERE) 的核心区别在于:部分元字符需要反斜杠
\来激活其特殊含义。元字符 BRE 中的含义 ERE 中的含义 ?字面问号(需转义 \?表示“零次或一次”)直接表示“零次或一次” +字面加号(需转义 \+表示“一次或多次”)直接表示“一次或多次” {n,m}字面花括号(需转义 \{n,m\}表示重复次数)直接表示重复次数 ( )字面括号(需转义 \( \)用于分组)直接用于分组 |字面竖线(需转义 |表示“或”)直接表示“或” 总结:
-
BRE 将大部分扩展元字符视为普通字符,需要用反斜杠转义才能获得特殊功能。
-
ERE 将上述字符视为内建元字符,直接使用即可,反斜杠反而会取消其特殊含义(使其变成字面字符)。
注:
*和^$.[]等基础元字符在两种模式中无需转义,始终有特殊含义。tar -tzf etc_backup.tar.gz | grep "udev\|selinux" //grep默认使用BRE tar -tzf etc_backup.tar.gz | grep -E "udev|selinux" //-E参数使用ERE echo "hello world" | sed 's/\([a-z]\+\) \([a-z]\+\)/\2 \1/' echo "hello world" | sed -E 's/([a-z]+) ([a-z]+)/\2 \1/'
-
-
简述 sed 命令的模式空间(Pattern Space)和保持空间(Hold Space)的概念,它是如何实现流编辑的?并简述 awk 的工作循环(即 BEGIN、主输入循环、END 的执行顺序和优先级),并列出其至少 5 个常用内置变量的含义。
-
模式空间(Pattern Space) sed 读取输入文件的每一行(去掉尾部换行符)后,将其存放在一个内存缓冲区中,该缓冲区称为“模式空间”。sed 的所有编辑命令(如
s/old/new/、d、p等)都默认作用于模式空间中的内容。处理完成后,模式空间的内容会被打印到标准输出(除非使用-n抑制),然后清空,再读取下一行。 -
保持空间(Hold Space) 另一个独立的、可持久化存储的缓冲区,用于暂存数据。默认情况下保持空间是空的。通过特定的命令(
h、H、g、G、x等)可以在模式空间和保持空间之间复制或追加数据,从而实现跨行、多行模式匹配或数据暂存。流编辑:
-
从输入流中读取一行,去掉尾随换行符,存入模式空间。
-
依次执行脚本中所有的编辑命令(这些命令可能根据条件修改模式空间,也可能与保持空间交互)。
-
若未使用
-n选项,则将模式空间的内容打印到输出(自动补回换行符);若使用了-n,则仅当遇到p命令时才打印。 -
清空模式空间,重复上述步骤,直到文件结束。
awk 的工作循环:
-
BEGIN最先且只一次 → 主循环对每一行执行 →END最后且只一次。 -
如果没有
BEGIN或END,对应部分直接跳过。 -
主循环中的“模式”可以是正则表达式、关系表达式、范围模式或
BEGIN/END保留字。
变量名 含义 NR已经读取的记录数(默认记录以换行符分隔,即当前行号),从 1 开始累计所有文件。 FNR当前文件的记录数(当前文件内的行号),每个文件重新从 1 开始。 NF当前记录中字段的数量(即当前行被分隔符切分出的列数)。 $0当前记录的整行内容(原始文本,未切分)。 $1, $2, ...当前记录的第 1、2 … 个字段(按 FS分隔符切分)。FS输入字段分隔符(默认为空格或制表符,可自定义为任意正则表达式,如 FS=":")。OFS输出字段分隔符(默认为空格, print打印多个字段时用此连接)。RS输入记录分隔符(默认为换行符 \n,可修改为其他字符实现以空行等为记录分隔)。ORS输出记录分隔符(默认为换行符, print在每个输出后追加此字符)。FILENAME当前正在处理的输入文件名。 -
-
-
对比 MBR 分区方案与 GPT 分区方案,并解答:在生产环境中面对 4TB 大容量磁盘,应该选择哪种分区方案?为什么?简述 Ext4 文件系统与 XFS 文件系统的差异,它们在进行逻辑卷缩减时有什么重大区别?
MBR 分区方案与 GPT 分区方案对比:
对比维度 MBR (主引导记录) GPT (GUID 分区表) 最大容量支持 2.2 TB(受 32 位 LBA 地址限制) 18 EB(受 64 位 LBA 地址限制,约 1800 万 TB) 分区数量 最多 4 个主分区,或 3 个主分区 + 1 个扩展分区(其下可再分逻辑分区) 理论无限制(Windows 限制为 128 个),Linux 下可更多 数据结构 位于磁盘首部扇区(0 扇区),无冗余备份 磁盘首部和尾部各保存一份分区表副本,具有 CRC 校验 功能,抗损坏能力更强 引导模式 依赖 BIOS + Legacy 引导 依赖 UEFI 引导(兼容模式除外) 适用场景 老旧系统、小于 2TB 的启动盘 现代系统、所有大于 2TB 的数据盘、高可靠性服务器 选择GPT分区方案,原因如下:
-
硬性容量限制:MBR 的 32 位地址空间最多只能寻址 2.2TB 空间。在 4TB 磁盘上使用 MBR,系统只能识别并使用约 2TB 的容量,剩余空间完全浪费。
-
数据安全性:生产环境数据无价。GPT 在磁盘末尾备份了分区表,且带有 CRC 校验,当磁盘头部出现坏道或数据损坏时,GPT 能自动从备份恢复,避免了整个磁盘分区表丢失导致的数据灾难。
ext4 文件系统与 XFS 文件系统的差异:
对比维度 Ext4 XFS 最大文件系统容量 1 EB 8 EB 最大单文件大小 16 TB 8 EB 元数据操作 中等(使用日志,但目录查找随文件数增加线性增长) 极快(使用 B+ 树索引,在大目录下性能衰减极小) 数据一致性 默认 有序日志(ordered),兼顾性能与安全 高级日志,支持增量备份和在线碎片整理 在线扩容 支持( resize2fs)支持( xfs_growfs)适用场景 通用场景、中小型文件数、系统盘 大型数据库、大数据存储、大量小文件或超大文件、高并发读写的服务器 恢复工具 e2fsck恢复能力较强xfs_repair恢复较慢且依赖日志逻辑卷缩减时的区别:
-
Ext4(支持缩减):
-
resize2fs工具支持将文件系统在线(已挂载)扩容,但缩减必须卸载(umount)文件系统。 -
特点:支持在线缩减,但操作步骤复杂且必须停机卸除。
-
-
XFS(完全不支持缩减):
-
XFS 文件系统设计的核心理念是 “只能扩大,不能缩小”。
xfs_growfs命令仅支持扩容。 -
特点:绝对禁止对 XFS 逻辑卷执行缩减操作。
-
-
-
物理卷(PV)、卷组(VG)、逻辑卷(LV)和物理盘区(PE)这四个概念是如何层层关联的?相比传统物理分区,LVM 的核心优势是什么?说明 RAID-0, RAID-1, RAID-5, RAID-10 的区别,并从“容错性、磁盘利用率、读写性能、最少盘数”这几个维度进行横向对比。
LVM:
物理卷(PV,Physical Volume):最底层,是物理磁盘(或磁盘分区、RAID阵列)被 LVM 初始化处理后的标记。执行
pvcreate时,会在磁盘头部写入 LVM 元数据。物理盘区(PE,Physical Extent):PV 被分割成的固定大小块(默认为 4MB)。PE 是 LVM 中最小的物理存储单元,类似于文件系统中的 Block。
卷组(VG,Volume Group):资源池。由一个或多个 PV 组合而成的存储仓库。VG 将所有加入的 PV 的 PE 汇集在一起,形成可分配的存储空间池。
逻辑卷(LV,Logical Volume):最终卷。从 VG 的 PE 池中按需分配一定数量的 PE 组成 LV。用户最终在 LV 上格式化文件系统并挂载使用。
磁盘(/dev/sdb)→ PV(转换成 PE 块)→ VG(将多个 PV 的 PE 汇聚成池)→ LV(从 VG 中分配若干 PE 块组成逻辑连续空间)→ 用户文件系统
LVM支持在线扩容(Ext4/XFS)不用停机,LV 可以跨多块物理磁盘,将多块小盘合并成一个大容量逻辑空间。可动态调整 LV 大小(XFS只能扩不能缩,Ext4支持双向调整),支持 LVM 快照(Snapshot),可以在秒级创建系统状态镜像,动态灵活,易于管理大规模服务器
RAID:
RAID 级别 容错性 磁盘利用率 读写性能 最少磁盘数 RAID-0 无(任意一块盘坏,全部数据丢失) 100%(N块盘容量全部可用) 读写最高(并发 I/O) 2 块 RAID-1 优秀(允许坏 1 块,仅镜像组内损坏不超过 1 块) 50%(N块盘仅能使用 N/2 容量) 写性能略降(需写两份),读性能提升(可并发读) 2 块 RAID-5 良好(允许坏 1 块) (N-1)/N(N块盘损失一块容量存校验位,利用率约 66%~94%) 读快;写性能较差(每次写需要读取旧数据+计算异或+写入新校验,有“写惩罚”) 3 块 RAID-10 极佳(最多可坏 N/2 块盘,但镜像组内不能同时坏两块) 50%(同 RAID-1,容量浪费一半) 读写性能均为最优(镜像提供读并发,条带提供写并行) 4 块 -
现有一个网页服务器访问日志文件,请编写一个 sed 语句:将文件中被注释的行(以 # 开头)和空行全部过滤掉,直接在终端打印剩下的内容。并写出安全的 sed 命令(要求原地修改并生成备份 .bak 文件),将配置文件 /etc/ssh/sshd_config 中的 #Port 22 替换为 Port 2222。
sed -n '/^$/!{ /^#/!p }' file.log sed -i.bak 's/#Port 22/Port 2222/' /etc/ssh/sshd_config -
假设 Nginx 的日志文件 /var/log/nginx/access.log 中,第一列为客户端的 IP 地址,第九列为 HTTP 状态码。请写出 awk 一行命令:
[root@Rocky-01 nginx]# cat access.log 192.168.1.101 - - [17/Jun/2024:10:15:32 +0000] "GET /index.html HTTP/1.1" 200 6123 "-" "Mozilla/5.0" 192.168.1.102 - - [17/Jun/2024:10:16:45 +0000] "POST /api/login HTTP/1.1" 404 1024 "-" "curl/7.68.0" 192.168.1.101 - - [17/Jun/2024:10:17:01 +0000] "GET /about.html HTTP/1.1" 200 4532 "-" "Mozilla/5.0" 192.168.1.103 - - [17/Jun/2024:10:18:22 +0000] "GET /images/logo.png HTTP/1.1" 200 8912 "-" "Mozilla/5.0" 192.168.1.104 - - [17/Jun/2024:10:19:33 +0000] "GET /products/ HTTP/1.1" 500 0 "-" "Mozilla/5.0" 192.168.1.101 - - [17/Jun/2024:10:20:10 +0000] "GET /contact.html HTTP/1.1" 404 512 "-" "Mozilla/5.0" 192.168.1.105 - - [17/Jun/2024:10:21:55 +0000] "GET /index.html HTTP/1.1" 200 6123 "-" "Mozilla/5.0" 192.168.1.102 - - [17/Jun/2024:10:22:18 +0000] "GET /favicon.ico HTTP/1.1" 200 1500 "-" "Mozilla/5.0" 192.168.1.103 - - [17/Jun/2024:10:23:44 +0000] "POST /api/order HTTP/1.1" 502 0 "-" "curl/7.68.0" 192.168.1.106 - - [17/Jun/2024:10:24:09 +0000] "GET /index.html HTTP/1.1" 200 6123 "-" "Mozilla/5.0" 192.168.1.101 - - [17/Jun/2024:10:25:30 +0000] "GET /admin/ HTTP/1.1" 403 0 "-" "Mozilla/5.0" 192.168.1.104 - - [17/Jun/2024:10:26:15 +0000] "GET /about.html HTTP/1.1" 200 4532 "-" "Mozilla/5.0" 192.168.1.107 - - [17/Jun/2024:10:27:41 +0000] "GET /products/ HTTP/1.1" 404 1024 "-" "Mozilla/5.0" 192.168.1.102 - - [17/Jun/2024:10:28:03 +0000] "GET /index.html HTTP/1.1" 200 6123 "-" "Mozilla/5.0" 192.168.1.108 - - [17/Jun/2024:10:29:22 +0000] "GET /images/banner.jpg HTTP/1.1" 200 15678 "-" "Mozilla/5.0" 192.168.1.105 - - [17/Jun/2024:10:30:11 +0000] "GET /contact.html HTTP/1.1" 200 512 "-" "Mozilla/5.0" 192.168.1.109 - - [17/Jun/2024:10:31:54 +0000] "GET /index.html HTTP/1.1" 200 6123 "-" "Mozilla/5.0" 192.168.1.101 - - [17/Jun/2024:10:32:20 +0000] "GET /assets/css/style.css HTTP/1.1" 200 2048 "-" "Mozilla/5.0" 192.168.1.110 - - [17/Jun/2024:10:33:45 +0000] "GET /index.html HTTP/1.1" 304 0 "-" "Mozilla/5.0" 192.168.1.102 - - [17/Jun/2024:10:34:12 +0000] "GET /test.html HTTP/1.1" 404 0 "-" "Mozilla/5.0"
1.统计并输出每个 IP 的请求总次数,按降序排列,取前 10 名。
awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -nr | head -10 5 192.168.1.101 4 192.168.1.102 2 192.168.1.105 2 192.168.1.104 2 192.168.1.103 1 192.168.1.110 1 192.168.1.109 1 192.168.1.108 1 192.168.1.107 1 192.168.1.106 awk '{count[$1]++} END {for (ip in count) print count[ip], ip}' /var/log/nginx/access.log | sort -nr | head -10 {count[$1]++} //对第一行的IP进行计数 for (ip in count) //将索引赋值给ip变量 print count[ip], ip //输出计数值,再输出ip 疑问:ip值从哪儿来?为什么能输出对应得ip? awk主循环对$1进行计数并将计数结果进行封装,外层索引使用$1的数值,for (ip in count) 将count的索引依次赋值给ip变量,count[ip]等于前面的计数次数,ip等于count的索引2.统计并输出每个 HTTP 状态码(如 200, 404, 500 等)出现的次数。
awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c 12 200 1 304 1 403 4 404 1 500 1 502 awk '{status[$9]++} END {for (s in status) print status[s], s}' /var/log/nginx/access.log | sort -nr -
生产环境中新加入了一块物理硬盘 /dev/sdb,要求对其使用 GPT 方案,并划分一个容量为 100GB 的主分区 /dev/sdb1。请分别给出使用:
-
parted 命令行的一体化分区命令。
parted -s /dev/sdb mklabel gpt mkpart primary 0% 100GB
-
cat << EOF 配合 fdisk / gdisk 的非交互式分区方案。 并写出将新建的 /dev/sdb1 格式化为 xfs 文件系统,并指定卷标(Label)为 DATA_PART 的命令。
gdisk /dev/nvme0n2 <<EOF o y n 1 +100GB w y EOF
mkfs.xfs -L DATA_PART /dev/nvme0n2
-
-
写出将 /dev/sdb1 挂载到 /data 目录下的命令。获取 /dev/sdb1 的 UUID,并写出在 /etc/fstab 中新增一行以实现“系统开机时自动将其以 defaults 选项挂载到 /data” 的配置字段。
[root@Rocky-01 ~]# mkdir /data [root@Rocky-01 ~]# mount /dev/nvme0n2 /data/ [root@Rocky-01 ~]# df -Th Filesystem Type Size Used Avail Use% Mounted on devtmpfs devtmpfs 4.0M 0 4.0M 0% /dev tmpfs tmpfs 872M 0 872M 0% /dev/shm tmpfs tmpfs 349M 5.7M 344M 2% /run /dev/mapper/rl-root xfs 17G 4.7G 13G 28% / /dev/nvme0n1p1 xfs 960M 304M 657M 32% /boot tmpfs tmpfs 175M 52K 175M 1% /run/user/42 tmpfs tmpfs 175M 36K 175M 1% /run/user/0 /dev/nvme0n2 ext4 20G 24K 19G 1% /data [root@Rocky-01 ~]# blkid /dev/nvme0n2 /dev/nvme0n2: UUID="a4a319e3-5ec9-4ae4-bad7-2dfec37a6443" TYPE="ext4" [root@Rocky-01 ~]# vim /etc/fstab [root@Rocky-01 ~]# grep -vE '^$|^#' /etc/fstab /dev/mapper/rl-root / xfs defaults 0 0 UUID=157ff871-a0a6-4c92-a3fd-a02e2c302848 /boot xfs defaults 0 0 /dev/mapper/rl-swap none swap defaults 0 0 UUID=a4a319e3-5ec9-4ae4-bad7-2dfec37a6443 /data ext4 defaults 0 0
-
现系统内存不足,需要紧急扩容交换空间。请写出以下操作命令:
-
在单盘上新建一个物理分区 /dev/sdc1,大小为 4GB。
echo -e "n\np\n1\n\n+4G\nt\n82\nw" | fdisk /dev/sdc
-
将该分区格式化为交换分区类型并启用它。
mkswap /dev/sdc1 swapon /dev/sdc1
-
通过配置文件 /etc/fstab 实现开机自动启用,并设置其优先级为 10。
vim /etc/fstab /dev/sdc1 swap swap defaults,pri=10 0 0 # 查看当前 swap 设备及优先级 swapon --show # 查看总内存 free -h
-
-
现有一个卷组 vg_data,其中已包含物理卷 /dev/sdb1。在该卷组中有一个名为 lv_store 的逻辑卷,采用 xfs 文件系统,挂载在 /store。由于空间爆满,需要从物理盘 /dev/sdc2 处对其进行扩容。请写出:
-
将 /dev/sdc2 初始化为 PV 并扩展到卷组 vg_data。
pvcreate /dev/sdc2 vgextend vg_data /dev/sdc2
-
扩展逻辑卷 lv_store,将卷组剩余所有空间全部加给它。
lvextend -l +100%FREE /dev/vg_data/lv_store
-
在线扩容其 xfs 文件系统。
xfs_growfs /dev/vg_data/lv_store
# 查看卷组剩余空间 vgdisplay vg_data # 查看逻辑卷新大小 lvdisplay /dev/vg_data/lv_store # 查看文件系统大小 df -h /store
-
-
写出为 /dev/vg_data/lv_store 创建一个只读快照 lv_store_snap` 的命令,快照预留大小为 500MB。在逻辑卷上进行测试后发现数据损毁,请写出卸载原逻辑卷、恢复快照并重新挂载验证的完整命令。
lvcreate -s -n lv_store_snap -L 500M /dev/vg_data/lv_store #创建快照 umount /store #逻辑卷故障,先卸载逻辑卷 lvconvert --merge /dev/vg_data/lv_store_snap #恢复快照 mount /dev/vg_data/lv_store /store #重新挂载 ls -l /store # 检查数据是否恢复 df -h /store # 查看挂载情况
-
在对新磁盘配置持久挂载时,某管理员将 /etc/fstab 中的 UUID 输错了一个字符,重启后系统直接卡在了 Emergency Mode。此时根分区变为了只读。请回答:
-
在此终端下如果直接编辑 /etc/fstab 会遇到什么报错?(提示:只读文件系统)、
E212: Can't open file for writing 或 Read-only file system
-
请给出能够解除只读限制、恢复系统挂载并修复该配置文件的完整命令步骤。
mount -o remount,rw / cp /etc/fstab /etc/fstab.bak vim /etc/fstab
-
在修改 /etc/fstab 之后重启前,应运行哪条命令验证配置正确性?
mount -a
-
-
开发部门在清理旧分区时,要求运维将一个容量为 500GB 的 LVM 逻辑卷缩减到 200GB。该卷上挂载的是 xfs 文件系统。请回答:
-
这个任务在 xfs 文件系统上可行吗?如果执行 lvreduce 会发生什么灾难?
-
XFS 文件系统设计上不支持缩容(shrink),只支持在线扩容(grow)。
-
如果直接对承载 XFS 的逻辑卷执行
lvreduce(缩小 LV),逻辑卷的大小会被强行截断至 200GB,但文件系统元数据仍认为整个 LV 为 500GB。这会导致:-
文件系统元数据与底层存储空间不匹配。
-
后续任何读写操作都可能访问到被截断的物理区域,造成文件系统元数据损坏、数据丢失、甚至卷无法挂载。
-
即使使用
xfs_repair也无法恢复,因为 XFS 没有设计收缩功能,损坏通常是永久性的。
-
-
-
如果文件系统是 ext4,缩减逻辑卷的正确安全步骤是怎样的?为什么缩容必须“先缩减文件系统,再缩减逻辑卷”?
逻辑卷(LV)是底层块设备,文件系统是上层抽象。如果先缩减 LV,文件系统还认为自己占据 500GB 的空间,就会尝试访问已被裁剪掉的区域,导致元数据损坏和数据丢失。先缩文件系统,是让文件系统知道自己即将变小,并安全地移动数据,然后告诉 LV 可以回收空间。
# 1. 卸载文件系统(必须卸载,ext4 不支持在线缩减) umount /store # 2. 强制检查文件系统,确保一致性 e2fsck -f /dev/vg_data/lv_store # 3. 缩小文件系统到目标大小(先缩文件系统) # 大小可以指定为 200G 或更小,但必须小于等于最终 LV 大小 resize2fs /dev/vg_data/lv_store 200G # 4. 缩小逻辑卷(再缩 LV) # -L 指定新大小,注意单位与 resize2fs 保持一致 lvreduce -L 200G /dev/vg_data/lv_store # 5. 重新检查文件系统(可选但推荐) e2fsck -f /dev/vg_data/lv_store # 6. 重新挂载并验证 mount /dev/vg_data/lv_store /store df -h /store
-
[6]
-
解释 ABI 与 API 的概念与区别。静态链接与动态链接有何异同?在排查动态链接库丢失引起的软件运行报错时,应如何使用 ldd 命令?
ABI 与 API 的概念与区别:
对比维度 API(应用程序编程接口) ABI(应用程序二进制接口) 定义层级 源代码级别的约定。定义了“如何写代码”来调用某个功能(函数名、参数类型、返回类型)。 二进制机器码级别的约定。定义了“编译后的代码如何交互”(调用约定、寄存器使用、系统调用号、内存对齐、符号命名规则)。 关注对象 开发者(人类可读)。 编译器和操作系统内核(机器可读)。 破坏性变更 修改 API(如改函数名、加参数)会导致编译错误(编译阶段报错)。 修改 ABI(如改结构体成员顺序、改系统调用号)不会报编译错,但会导致运行时崩溃(Segfault)或奇怪的未定义行为。 跨平台性 标准 API(如 POSIX)可跨操作系统,只需重新编译即可运行。 ABI 严格绑定操作系统发行版、CPU 架构(x86_64 vs ARM)和编译器版本。即便 API 相同,ABI 不同,二进制也无法互通(如 Windows .exe 无法在 Linux 运行)。 静态链接与动态链接有何异同:
| 维度 | 静态链接(Static Linking) | 动态链接(Dynamic Linking) |
|---|---|---|
| 时机 | 发生在编译/构建阶段(ld 链接器将库代码打包进可执行文件)。 | 发生在程序加载或运行时(由动态链接器 /lib/ld-linux.so 加载 .so 库)。 |
| 可执行文件大小 | 巨大(整个 libc.a 都复制进去)。 | 极小(仅包含重定位和符号表)。 |
| 内存占用 | 高(同一库被多个进程重复加载到物理内存)。 | 低(共享库在内存中只存一份,通过页表映射给多进程)。 |
| 更新升级 | 极难(必须重新编译链接整个程序)。 | 极方便(只需替换 .so 文件,重启程序即可,如 OpenSSL 漏洞修复)。 |
| 环境依赖 | 无依赖(打包即运行,移植性强)。 | 强依赖(缺少 .so 或版本不匹配直接报错 cannot open shared object file)。 |
| 启动速度 | 快(无需外部解析)。 | 稍慢(运行时需符号查找与重定位,但通常可忽略)。 |
动态链接库丢失引起的软件运行报错:
ldd /path/to/your_program //诊断 linux-vdso.so.1 (0x00007ffe...) libssl.so.1.1 => not found <-- 这就是缺失的库! libc.so.6 => /lib64/libc.so.6 (0x00007f...) find /usr -name "libssl.so*" //检查系统是否有该文件 export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH //若库在 /usr/local/lib,需加入环境变量 ./your_program ls -l /usr/lib64/libssl.so* //查看动态库是否为软连接文件,并坚持指向文件是否被删除
-
简述 Rocky 环境下 yum/dnf 客户端与软件源服务端的工作机制。自建私有 YUM 仓在企业内部有何实际意义?说明 Ubuntu 下的 dpkg 和 apt 的层级关系。在卸载软件时,apt remove、apt purge 与 apt autoremove 三者之间有何区别?
yum/dnf 客户端与软件源服务端的工作机制:
-
客户端配置:
/etc/yum.repos.d/*.repo文件中定义仓库的baseurl(或mirrorlist)和gpgkey。 -
元数据下载:执行
dnf update或dnf install时,客户端会下载仓库中的repodata/repomd.xml文件,该文件包含所有软件包的元数据(名称、版本、依赖关系、文件列表、校验和等)。 -
本地缓存:客户端将元数据缓存在
/var/cache/dnf/下,后续操作优先使用缓存(可设置过期时间)。 -
依赖解析:客户端根据用户请求(安装/更新/删除)和本地元数据,利用 libsolv 库计算完整的依赖树,确保无冲突。
-
包下载与事务执行:确定需下载的包列表后,从
baseurl或镜像下载.rpm包到本地,校验 GPG 签名和校验和,然后执行 RPM 事务(安装/升级/删除)。 -
服务端:通常是 HTTP 服务器(如 nginx)提供静态文件服务,目录结构为
repodata/子目录和.rpm包。管理员使用createrepo或dnf reposync生成并更新repodata。自建私有 YUM 仓在企业内部有何实际意义:
-
内网加速:避免数百台服务器同时访问公网源,节省带宽,提升部署速度。
-
版本锁定与合规:可冻结某个稳定版本的软件包,防止生产环境因外部源更新导致意外不兼容。
-
定制化包分发:可放置企业内部开发的
.rpm包(如定制版的 nginx、监控 agent),统一分发。 -
安全可控:只允许内部仓库,可做漏洞扫描和安全审核,避免使用未授权的第三方源。
-
离线环境支持:物理隔离网络下,私有仓库是唯一可行的软件安装来源。
-
简化运维:结合
dnf update和内网仓库,实现统一版本管理和补丁发布。dpkg 和 apt 的层级关系:
层级 工具 职责 底层 dpkgDebian 包管理器的核心工具,直接处理 .deb包文件(安装、卸载、查询元数据、解包等),但不自动处理依赖关系。它操作本地数据库(/var/lib/dpkg/status)。上层 apt(含apt-get,apt-cache)基于 dpkg构建的高级包管理工具,自动处理依赖解析,从远程仓库下载包,然后调用dpkg执行安装/卸载。还提供搜索、更新、升级等高级功能。统一入口 apt命令(新版)整合了 apt-get和apt-cache的常用子命令,提供更友好的进度条和输出,但功能子集略小。关系:
apt是前端,dpkg是后端。apt负责网络、仓库、依赖,dpkg负责实际安装/卸载包文件。操作.deb文件时直接使用dpkg -i,但需要自己解决依赖;推荐用apt install ./package.deb,会自动处理依赖。apt remove、apt purge 与 apt autoremove 的区别:
命令 行为 保留配置文件? 处理依赖 典型场景 apt remove <pkg>删除软件包本身(二进制文件、库等),但保留该软件包的配置文件(位于 /etc下的配置)。是(保留) 删除包后,若其他包依赖它,会阻止删除;若该包依赖的其他包未被其他包使用,则会一并标记为自动依赖,但不会自动删除。 临时移除软件,但保留配置以便日后重装恢复原配置。 apt purge <pkg>删除软件包,并同时删除其所有配置文件(包括 /etc下的配置和用户家目录中的配置)。否(彻底清除) 同上,但会彻底清理残留。 彻底卸载软件,消除所有痕迹,适合清理不用的服务。 apt autoremove不指定包名,此命令用于删除不再被任何已安装包所依赖的自动安装的包(即作为依赖引入但现已多余的包)。 不涉及 自动计算依赖树,清理孤儿包。 定期清理系统,释放磁盘空间。常与 remove/purge配合使用,在删除主包后执行autoremove清理其依赖。 -
-
什么是 systemd?它相比于传统的 SysV init 机制,最显著的优势是什么?说明服务控制单元文件中,[Unit]、[Service]、[Install] 三个配置段的核心作用。
systemd 是 Linux 系统中 PID 为 1 的初始化系统(init 进程),也是系统的服务管理器。它不仅负责系统内核启动后的第一个用户态进程,还承担着管理所有系统服务(daemon)、挂载点、设备、套接字、定时任务等资源的全生命周期管理。目前,Rocky Linux、CentOS、Ubuntu、Debian 等主流发行版均已将 systemd 作为默认 init 系统。
维度 SysV init systemd 启动方式 串行顺序启动:严格按照 /etc/rc?.d/中的数字序号(S01, S02...)逐一执行,速度极慢。并行按依赖启动:根据单元文件中的 After/Before/Requires构建依赖关系图,同时启动无依赖的服务,启动速度极快(可缩短数十秒)。进程管理 进程组管理松散,孤儿进程易失控(必须依赖 pidfile追踪)。集成 cgroups:每个服务独立拥有 cgroup,可精确控制资源(CPU/内存),并可自动重启崩溃进程( Restart=always)。启动方式灵活性 仅支持“启动时运行或完全禁用”。 支持 Socket 激活、总线激活、设备激活、路径激活(按需启动),例如:sshd 可在第一个请求到达时才启动。 日志管理 日志分散在 /var/log/下多个文件中,格式不一。集成 journald:统一收集所有服务日志( journalctl),支持结构化存储、过滤和远程转发。统一管理 繁杂的 shell 脚本( start/stop/status需自定义)。标准化声明式单元文件( .service),所有服务状态查询(systemctl)统一,支持快照、目标(target)管理等高级特性。1.
[Unit]段 —— 通用元数据与依赖定义-
作用:定义服务的描述信息、与其他单元的依赖关系和启动顺序,适用于所有类型的单元(服务、挂载、设备等)。
-
核心指令:
-
Description:人类可读的描述(如Description=My Custom Web Server)。 -
After:启动顺序,不强制依赖,只保证本服务在该单元之后启动(如After=network.target)。 -
Before:本服务在该单元之前启动。 -
Requires:强依赖,若依赖的单元启动失败,本服务也会失败。 -
Wants:弱依赖,依赖单元启动失败不影响本服务启动。
-
2.
[Service]段 —— 进程运行与生命周期控制(仅针对服务类型)-
作用:定义服务如何启动、运行、重启以及运行环境。
-
核心指令:
-
Type:服务类型(simple(默认,主进程在前台)、forking(主进程后台化,需配合PIDFile)、oneshot(一次性任务)、notify(通知 systemd 已就绪))。 -
ExecStart:启动命令(绝对路径,如/usr/bin/python3 /app/server.py)。 -
ExecStop:停止命令(通常缺省时 systemd 发送 SIGTERM,手动指定可做清理)。 -
ExecReload:重载命令(如kill -HUP)。 -
Restart:重启策略(no、on-failure、always、on-success等)。 -
User/Group:指定运行进程的用户和组(安全加固必须设置)。 -
WorkingDirectory:工作目录。 -
EnvironmentFile:加载环境变量文件(如/etc/sysconfig/myservice)。
-
3.
[Install]段 —— 启用(Enable)与开机自启关联-
作用:不决定服务当前是否运行,仅定义在
systemctl enable或disable时,服务与系统启动目标的链接关系。 -
核心指令:
-
WantedBy:最关键。指定该服务被哪个系统目标(target)所“想要”。例如WantedBy=multi-user.target,表示当系统进入多用户模式时,该服务会被自动启动(即enable后会在/etc/systemd/system/multi-user.target.wants/下创建软链接)。 -
RequiredBy:强依赖目标,较少用。 -
Alias:为单元设置别名(systemctl alias)。
-
-
-
Linux 中执行 Shell 脚本有 ./script.sh、bash script.sh、source script.sh。请说明它们在“是否启动子进程”和“对脚本文件的执行权限要求”上的异同。说明 set -e、set -u、set -o pipefail 起到了什么作用?
执行方式 是否启动子进程(子Shell) 对脚本文件的执行权限要求 环境变量影响 典型使用场景 ./script.sh是。内核根据 shebang( #!/bin/bash)调用对应解释器,启动一个全新的子进程(子Shell)来运行脚本。必须有执行权限( chmod +x script.sh)。不影响父Shell。脚本内导出的变量、切换的目录在脚本结束后全部失效。 执行普通应用程序或独立脚本,最标准的运行方式。 bash script.sh是。显式指定 bash命令,bash本身作为一个子进程启动,并读取脚本文件作为参数。不需要执行权限(只需读权限 r)。不影响父Shell。与 ./效果相同(环境隔离)。快速执行脚本而无需修改权限,或用于绕过 shebang 使用不同解释器(如 sh或bash -x调试)。source script.sh(或. script.sh)否。不启动子进程,脚本在当前Shell进程中逐行执行。 不需要执行权限(只需读权限 r)。会影响父Shell。脚本中所有变量、函数、 cd目录变更都会保留在当前终端会话中。加载配置文件(如 ~/.bashrc)、设置环境变量、切换工作目录。-
-e:防止低级错误蔓延。 -
-u:防止变量未定义导致逻辑漏洞。 -
-o pipefail:防止管道中的错误被静默吞噬
-
-
什么是全局变量?简述 /etc/profile、/etc/bashrc、~/.bash_profile、~/.bashrc 这四个配置文件的加载顺序以及在登录与非登录场景下的差异。
-
环境变量(Environment Variables):由父进程导出(
export)并被子进程继承的变量。它对当前 Shell 及其所有子进程可见。例如PATH、HOME。 -
Shell 变量(本地变量):仅在当前 Shell 进程中有效,不会被传递给子进程。
场景 加载文件(按顺序) 是否读 ~/.bashrc登录 Shell(SSH / tty) /etc/profile→~/.bash_profile(→ 通常内含 source~/.bashrc)是(间接通过 profile) 非登录交互式 Shell(终端标签) /etc/bashrc→~/.bashrc是(直接) 非交互式 Shell(脚本执行) 不加载(除非指定 BASH_ENV)否 -
-
某台机器上运行着一个未知服务,其二进制程序路径为 /usr/sbin/httpd。请写出一条命令:查询这个二进制文件是由哪个具体的包(RPM 或 DEB)安装生成的。在未联网的情况下,需要查询本地一个尚未安装的软件包 vsftpd-3.0.3-49.el9.x86_64.rpm 内包含了哪些文件和目录,请写出对应的查询命令。
whereis httpd httpd: /usr/sbin/httpd /usr/lib64/httpd /etc/httpd /usr/share/httpd /usr/share/man/man8/httpd.8.gz rpm -qf /usr/sbin/httpd httpd-core-2.4.62-13.el9_8.1.x86_64 dpkg -S " /usr/sbin/httpd" rpm -qpl vsftpd-3.0.3-49.el9.x86_64.rpm dpkg -c vsftpd_3.0.5-0ubuntu1.1_amd64.deb -
现需要通过源码编译安装 Nginx(以 nginx-1.24.0 为例),请写出其核心的编译部署步骤。编译安装完成在 /usr/local/nginx 目录后,如何在不使用绝对路径的情况下,让系统所有用户都可以直接运行 nginx 命令?请写出环境变量配置的命令。
yum install -y gcc pcre-devel zlib-devel openssl-devel make wget https://nginx.org/download/nginx-1.24.0.tar.gz tar -xzf nginx-1.24.0.tar.gz cd nginx-1.24.0 ./configure --prefix=/usr/local/nginx \ --with-http_ssl_module \ --with-http_v2_module \ --with-stream make -j$(nproc) make install /usr/local/nginx/sbin/nginx -v echo 'export PATH=/usr/local/nginx/sbin:$PATH' > /etc/profile.d/nginx.sh source /etc/profile.d/nginx.sh which nginx nginx -v
-
在 /usr/local/bin/backup.sh 有一个自动备份的脚本。现在要求将其封装为系统服务 backup.service,满足:
-
服务说明为 Daily Backup Service。
-
在 network.target 后启动。
-
类型为 simple。
-
异常退出 5s 内自动重启。
-
允许开机自启。 请完整写出 /etc/systemd/system/backup.service 的配置文件内容,并写出重载配置、开机自启并立刻启动该服务的命令。
cat << EOF >> /etc/systemd/system/backup.service [Unit] Description=Daily Backup Service After=network.target [Service] Type=simple ExecStart=/usr/local/bin/backup.sh Restart=on-failure RestartSec=5s [Install] WantedBy=multi-user.target EOF systemctl daemon-reload && systemctl enable backup && systemctl start backup && systemctl status backup
-
-
定义一个普通本地变量 URL="https://www.sswang.com/index.html",请写出表达式:
-
获取此变量字符串的总长度。
URL="https://www.sswang.com/index.html" echo ${#URL} -
提取出域名部分的子串 "www.sswang.com"。
echo $URL | cut -d'/' -f3 # 或 echo $URL | awk -F '/' '{print $3}' -
并说明如何定义只读变量 PORT 且值为 8080,如果修改或删除会发生什么?
readonly PORT=8080 # 或 declare -r PORT=8080 PORT=9090 # 报错:bash: PORT: readonly variable unset PORT # 报错:bash: unset: PORT: cannot unset: readonly variable
-
-
编写一个 Shell 脚本片段,提示用户输入管理员账号及密码,要求:
-
提示信息 "Please input admin username: "。
-
接收密码时,不回显输入。
-
用户在 10 秒内未输入,则脚本自动超时退出。
#!/bin/bash # 输入用户名 read -t 10 -p "Please input admin username: " username if [ $? -ne 0 ] || [ -z "$username" ]; then echo -e "\nTimeout or empty username. Exiting." >&2 exit 1 fi # 输入密码 read -t 10 -s -p "Please input admin password: " password ret=$? echo >&2 # 输出换行到stderr,但可能不显示,最好用echo echo if [ $ret -ne 0 ] || [ -z "$password" ]; then echo -e "Timeout or empty password. Exiting." >&2 exit 1 fi
-
-
编写代码演示三种不同的整数加法运算方法。并在生产环境需要进行浮点数计算:计算当前磁盘利用率(已用空间 45GB 除以总空间 120GB 的百分比),并保留两位小数。请给出命令。另外,演示逻辑测试 [[]] 表达式:判断用户输入的变量 IP_ADDR 格式是否为有效的 IPv4 地址。
sum1=$((1 + 2)) ; echo "$sum1" let sum2=1+2 ; echo $sum2 sum3=$(expr 1 + 2) ; echo "$sum3" echo "scale=2; 45 * 100 / 120" | bc
#!/bin/bash read -p "请输入一个IPv4地址: " IP_ADDR # 正则:匹配 0-255 的四组数字 ipv4_regex='^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$' if [[ $IP_ADDR =~ $ipv4_regex ]]; then echo "有效的IPv4地址: $IP_ADDR" else echo "无效的IPv4地址: $IP_ADDR" fi -
在 Shell 脚本中,位置参数 $* 与 $@ 到底有什么本质区别?请回答:
-
在没有被双引号括住时行为不同吗?
-
不加引号时(
$*和$@裸写):两者都会将位置参数展开成多个独立的单词,然后对每个单词进行路径名扩展(通配符)和单词分割(分词)。 -
由于它们都被拆散了,如果参数中包含空格或通配符(如
*),它们会被错误地拆分成多个参数或展开成文件名。 -
假设脚本参数为
"hello world"和"*.txt"。不加引号时,无论是$*还是$@,都会被拆成 3 个甚至更多个词(因为空格分词和*被展开了),行为几乎一致。
-
-
当被双引号括住为 "$*" 和 "$@" 时分别是什么逻辑?
-
"$\*":将所有位置参数合并成一个单一的字符串,并用IFS环境变量的第一个字符作为分隔符连接它们(默认是空格)。-
例如:参数为
a、b、c时,"$*"等价于"a b c"(一个字符串,3个字符)。
-
-
"$@":将每个位置参数展开为独立的、被双引号包裹的字符串,保持每个参数的原始边界。-
例如:参数为
a、b、c时,"$@"等价于"a" "b" "c"(三个独立的字符串)。
-
-
-
在处理含有不确定字符或空格的参数传递时选用哪一个?
无引号的
$\*:hello、world、*.txt(如果当前目录有 txt 文件,*.txt会被展开成文件名,严重错误)。"$\*":输出[hello world *.txt](合并成一个字符串,丢失了参数边界,通常用于拼接字符串,而非传递参数)。"$@":输出[hello world]和[*.txt](完美保留了参数原样,不会展开通配符,也不会拆分空格)。#!/bin/bash echo "====== 使用 \$* (不加引号) ======" for arg in $*; do echo "[$arg]" done echo "====== 使用 \$@ (不加引号) ======" for arg in $@; do echo "[$arg]" done echo "====== 使用 \"\$*\" (加引号) ======" for arg in "$*"; do echo "[$arg]" done echo "====== 使用 \"\$@\" (加引号,标准做法) ======" for arg in "$@"; do echo "[$arg]" done bash test.args.sh "hello world" "*.txt" ====== 使用 $* (不加引号) ====== [hello] [world] [1.txt] ====== 使用 $@ (加引号) ====== [hello] [world] [1.txt] ====== 使用 "$*" (加引号) ====== [hello world *.txt] ====== 使用 "$@" (加引号,标准做法) ====== [hello world] [*.txt]
-
-
编译安装软件时遇到依赖缺失,除了去互联网搜索,如何通过包管理器查找依赖文件所归属的软件?
-
请写出 Rocky 环境下,根据文件路径或库文件名称反向搜索对应 RPM 软件包的命令;
rpm -pl /usr/sbin/httpd rpm -qf /usr/sbin/httpd httpd-core-2.4.62-13.el9_8.1.x86_64 yum provides sos yum deplist httpd
-
如果是在 Ubuntu 环境下,又该使用什么命令?
dpkg -S /usr/sbin/sshd apt-cache depends nginx
-
399

被折叠的 条评论
为什么被折叠?



