脚本编写与账户安全基础
1. 条件表达式的使用
脚本语言支持多种类型的条件表达式,这些表达式能让脚本根据特定条件(通常是变量的值)执行不同的操作。常见的使用条件表达式的命令是
if
,它能让系统根据某个条件是否为真来执行两个操作中的一个。
if
关键字后的条件表达式放在方括号内,有多种形式。例如:
-
-f file
:如果
file
存在且为普通文件,则为真。
-
-s file
:如果
file
存在且大小大于 0,则为真。
-
string1 == string2
:如果两个字符串的值相同,则为真。
条件表达式可以用逻辑与(
&&
)或逻辑或(
||
)运算符组合。使用
&&
时,运算符两边都为真,整个条件才为真;使用
||
时,只要运算符一边为真,整个条件就为真。
以下是一个使用条件表达式的代码片段:
if [ -s /tmp/tempstuff ]
then
echo “/tmp/tempstuff found; aborting!”
exit
fi
这个代码片段会在
/tmp/tempstuff
文件存在时使脚本退出。
then
关键字标志着只有在条件为真时才会执行的一系列命令的开始,
fi
标志着
if
块的结束。
条件表达式也可以使用
test
关键字,而不是方括号:
if test -s /tmp/tempstuff
还可以使用命令的返回值作为条件:
if [ command ]
then
additional-commands
fi
在这个例子中,只有当
command
成功完成时,
additional-commands
才会运行。如果
command
返回错误代码,
additional-commands
不会运行。
2. 条件表达式的扩展
条件表达式可以通过
else
子句扩展:
if [ conditional-expression ]
then
commands
else
other-commands
fi
这种形式的代码会根据
conditional-expression
的计算结果,执行
commands
或
other-commands
。这在程序的某个部分需要根据特定条件执行不同操作时很有用。
如果有多个可能的结果,可以使用
case
语句:
case word in
pattern1) command(s);;
pattern2) command(s);;
...
esac
对于
case
语句,
word
通常是一个变量,每个
pattern
是该变量的一个可能值。模式可以像文件名一样扩展,使用相同的通配符和扩展规则(例如
*
代表任意字符串)。每个命令集必须以双分号(
;;
)结尾,
case
语句整体以
esac
结尾。执行时,
bash
会执行与
word
匹配的第一个模式关联的命令,然后跳转到
esac
语句后的行,中间的命令不会执行。如果没有模式匹配
word
,
case
语句内的代码不会执行。如果需要默认条件,可以使用
*
作为最后一个模式。
3. 循环的使用
条件表达式有时会在循环中使用。循环是一种结构,它会让脚本重复执行相同的任务,直到满足特定条件(或直到某个条件不再满足)。
例如,以下脚本会播放目录中所有的
.wav
音频文件:
#!/bin/bash
for d in `ls *.wav`; do
aplay $d
done
这里的
for
循环会为
ls *.wav
生成的列表中的每个项目执行一次。每个项目(文件名)会依次赋值给
$d
变量,并传递给
aplay
命令。
seq
命令在创建
for
循环时很有用,它可以生成一个从第一个参数开始到最后一个参数结束的数字列表。例如,
seq 1 10
会生成 10 行,每行一个 1 到 10 之间的数字。可以使用
for x in
seq 1 10
` 让循环执行 10 次,每次迭代
x
的值递增。如果只传递一个参数给
seq`,它会将该数字作为结束点,起始点为 1;如果传递三个值,它会将它们解释为起始值、增量和结束值。
另一种循环是
while
循环,只要条件为真,它就会一直执行:
while [ condition ]
do
commands
done
until
循环形式类似,但只要条件为假,它就会一直执行,直到条件变为真。
4. 函数的使用
函数是脚本中执行特定子任务的部分,可以从脚本的其他部分通过名称调用。函数的定义方式是在函数名后加上括号,并将组成函数的行用花括号括起来:
myfn() {
commands
}
关键字
function
可以可选地放在函数名之前。无论哪种方式,函数都可以像普通的内部或外部命令一样通过名称调用。
函数有助于创建模块化脚本。例如,如果脚本需要执行六个不同的计算,可以将每个计算放在一个函数中,然后按顺序调用它们。以下是一个演示函数使用的脚本:
#!/bin/bash
doit() {
cp $1 $2
}
function check() {
if [ -s $2 ]
then
echo “Target file exists! Exiting!”
exit
fi
}
check $1 $2
doit $1 $2
如果将这个脚本命名为
safercp
,假设
original.txt
存在而
dest.txt
不存在,可以这样使用:
$ ./safercp original.txt dest.txt
$ ./safercp original.txt dest.txt
Target file exists! Exiting!
第一次运行脚本成功,因为
dest.txt
不存在;第二次运行时,目标文件存在,脚本会终止并显示错误信息。
需要注意的是,函数不是直接按它们在脚本中出现的顺序运行的,只有在脚本的主体中调用时才会运行。
5. 设置脚本的退出值
通常,脚本的返回值与脚本调用的最后一个命令相同,即脚本返回
$?
。可以使用
exit
命令控制退出值,或在任何时候退出脚本。不使用任何选项时,
exit
会立即终止脚本,返回通常的退出值
$?
。这在错误处理或因任何原因中止正在进行的操作时很有用。
如果给
exit
传递一个 0 到 255 之间的数值,脚本会终止并返回指定的值作为脚本自己的退出值。可以使用这个功能向可能调用自己脚本的其他脚本发出错误信号,但可能需要额外的代码来跟踪异常终止的原因。例如,可以设置一个变量(如
$termcause
)来保存脚本终止的原因,在脚本开始时将其设置为 0,如果脚本检测到会导致终止的问题,将
$termcause
重置为非 0 值。退出时,确保将
$termcause
传递给
exit
:
exit $termcause
6. 账户相关知识
Linux 是多用户操作系统,提供了账户和组的功能。账户使多个用户可以共享一台计算机而不会相互造成太多麻烦,也使系统管理员能够跟踪谁在使用系统资源,以及谁在做不该做的事情。
6.1 账户特征
大多数账户特征在
/etc/passwd
文件中定义,该文件由冒号分隔的行组成,每行定义一个账户。例如:
rich:x:1003:100:Rich Blum:/home/rich:/bin/bash
各字段信息如下:
| 字段 | 说明 |
| ---- | ---- |
| 用户名 | 账户的用户名是其最相关的特征,大多数 Linux 账户用户名由小写字母和偶尔的数字组成,下划线(
_
)、破折号(
-
)和结尾的美元符号(
$
)在某些发行版中也是有效的。 |
| 密码 | 用户账户通常由密码保护,登录计算机需要密码。大多数系统账户的直接登录被禁用,因此它们没有密码。
/etc/passwd
文件中的密码字段通常包含
x
,表示密码存储在
/etc/shadow
文件中。 |
| UID | 实际上,用户名只是计算机显示给人类的标签,计算机使用用户标识(UID)号来跟踪账户。UID 号从 0 开始(指
root
账户),在大多数发行版中,用户账户的 UID 号从 1000 及以上开始,较低的号码保留给系统账户。 |
| GID | 账户与一个或多个组相关联,组是账户的集合。每个账户通过组 ID(GID)号直接与一个主组相关联。 |
| 注释字段 | 通常包含用户的全名,也可以包含其他信息。 |
| 主目录 | 用户账户和一些系统账户有主目录,主目录是账户的“大本营”,通常属于该账户。使用波浪号(
~
)在文件名开头可以方便地访问用户的主目录。 |
| 默认 shell | 每个账户都关联一个默认 shell,在 Linux 中通常是 Bash(
/bin/bash
),但用户可以更改。大多数非
root
系统账户将默认 shell 设置为
/usr/sbin/nologin
或
/sbin/nologin
以增加安全性。 |
6.2 密码存储
/etc/passwd
文件由于历史原因必须对所有用户可读,因此存储密码存在风险。现在,密码存储在
/etc/shadow
文件中,普通用户无法读取该文件。一个典型的
/etc/shadow
条目如下:
rich:$1$E/moFkeT5UnTQ3KqZUoA4Fl2tPUoIc:16860:5:30:14:-1:-1:
各字段含义如下:
| 字段 | 说明 |
| ---- | ---- |
| 用户名 | 每行以用户名开头,通过用户名将该文件中的条目与
/etc/passwd
文件中的条目关联。 |
| 密码 | 密码以加盐哈希的形式存储,与实际密码没有明显相似之处。星号(
*
)或感叹号(
!
)表示账户没有密码(即账户被锁定)。 |
| 上次密码更改日期 | 表示上次密码更改的日期,以自 1970 年 1 月 1 日以来的天数存储。 |
| 允许更改的天数 | 表示在允许更改密码之前的天数,用于防止用户按要求更改密码后又改回原密码。 |
| 需要更改的天数 | 表示自上次密码更改以来,需要再次更改密码的天数。 |
| 密码过期前的警告天数 | 如果系统配置为使密码过期,可以设置在过期日期临近时警告用户。 |
| 过期与停用之间的天数 | Linux 允许账户过期和完全停用之间有一个间隔。过期的账户要么不能使用,要么登录后需要立即更改密码。停用的账户密码被删除,需要系统管理员重新激活才能使用。值为 -1 表示此功能禁用。 |
| 过期日期 | 表示账户将过期的日期,以自 1970 年 1 月 1 日以来的天数表示。值为 -1 表示此功能禁用。 |
| 特殊标志 | 保留供将来使用,通常不使用或包含无意义的值。 |
对于与天数相关的字段,值为 -1 或 99999 通常表示相关功能已禁用。
/etc/shadow
文件通常以严格的权限存储,由
root
拥有,这对于影子密码系统的实用性至关重要,因为它可以防止非
root
用户读取文件并获取密码列表,即使是加盐哈希形式。相比之下,
/etc/passwd
必须对普通用户可读,通常权限限制较少。
账户信息分散在多个配置文件中,如
/etc/passwd
、
/etc/shadow
、
/etc/group
等,用户文件可能位于用户的主目录或其他地方。因此,管理账户可能需要做的不仅仅是维护一两个文件,为此存在各种实用程序来帮助创建、管理和删除账户。
以下是一个简单的 mermaid 流程图,展示
if-else
条件判断的流程:
graph TD;
A[开始] --> B{条件表达式是否为真};
B -- 是 --> C[执行 commands];
B -- 否 --> D[执行 other-commands];
C --> E[结束];
D --> E;
通过以上内容,我们了解了脚本编写中条件表达式、循环、函数的使用,以及如何设置脚本的退出值,同时也掌握了 Linux 系统中账户和密码存储的相关知识。这些知识对于 Linux 用户和管理员来说是非常重要的基础。
脚本编写与账户安全基础
7. 账户安全与管理的重要性
账户安全是 Linux 系统安全的重要组成部分。由于账户信息分散在多个配置文件中,且用户文件可能位于不同位置,管理账户需要综合考虑多个方面。例如,如果
/etc/shadow
文件的权限设置不当,非
root
用户可能会获取到加密后的密码信息,从而增加系统被破解的风险。
在管理账户时,需要注意以下几点:
-
定期检查账户信息
:查看
/etc/passwd
和
/etc/shadow
文件,确保账户信息的准确性和安全性。例如,检查是否有异常的 UID 或 GID 分配,以及密码是否正确存储在
/etc/shadow
中。
-
及时更新密码策略
:根据系统的安全需求,调整
/etc/shadow
文件中的密码更改时间限制、警告天数等参数。例如,缩短密码需要更改的天数,增加密码的安全性。
-
合理分配账户权限
:根据用户的工作职责,为账户分配适当的权限。避免给予普通用户过高的权限,防止误操作或恶意行为对系统造成损害。
8. 脚本编写与账户管理的结合应用
在实际工作中,脚本编写可以与账户管理相结合,提高工作效率和系统的安全性。以下是一些常见的应用场景:
8.1 批量创建账户
可以编写一个脚本来批量创建账户,避免手动输入大量信息。以下是一个示例脚本:
#!/bin/bash
# 定义用户名列表
usernames=("user1" "user2" "user3")
# 循环创建账户
for username in "${usernames[@]}"
do
useradd $username
echo "账户 $username 创建成功"
done
在这个脚本中,我们定义了一个用户名列表,然后使用
for
循环遍历列表,使用
useradd
命令创建账户。
8.2 检查账户密码过期情况
可以编写一个脚本来检查账户密码的过期情况,并及时提醒用户更改密码。以下是一个示例脚本:
#!/bin/bash
# 获取所有用户的用户名
users=$(cut -d: -f1 /etc/passwd)
# 循环检查每个用户的密码过期情况
for user in $users
do
passwd_info=$(chage -l $user)
days_to_expire=$(echo "$passwd_info" | grep "Days until password expires" | awk '{print $NF}')
if [ $days_to_expire -lt 7 ]
then
echo "用户 $user 的密码将在 $days_to_expire 天内过期,请及时更改"
fi
done
在这个脚本中,我们首先使用
cut
命令从
/etc/passwd
文件中获取所有用户的用户名,然后使用
chage -l
命令获取每个用户的密码信息,提取密码过期的天数。如果过期天数小于 7 天,则输出提醒信息。
9. 总结与实践建议
通过本文的介绍,我们了解了脚本编写中的条件表达式、循环、函数的使用,以及如何设置脚本的退出值,同时也掌握了 Linux 系统中账户和密码存储的相关知识。为了更好地应用这些知识,以下是一些实践建议:
- 多实践脚本编写 :通过编写不同类型的脚本,如文件处理脚本、账户管理脚本等,加深对脚本编写的理解和掌握。在编写脚本时,可以参考本文中的示例代码,结合实际需求进行修改和扩展。
-
定期备份账户信息
:由于账户信息分散在多个配置文件中,定期备份这些文件可以防止数据丢失。可以使用
cp命令或其他备份工具进行备份,备份文件可以存储在外部存储设备或远程服务器上。 - 加强账户安全意识 :作为系统管理员或普通用户,要时刻保持账户安全意识。不随意泄露账户密码,定期更改密码,避免使用弱密码。同时,要注意查看系统日志,及时发现异常的账户登录行为。
以下是一个 mermaid 流程图,展示批量创建账户的流程:
graph TD;
A[开始] --> B{定义用户名列表};
B --> C{循环遍历用户名列表};
C -- 是 --> D[使用 useradd 命令创建账户];
D --> E[输出创建成功信息];
E --> C;
C -- 否 --> F[结束];
希望本文的内容能够帮助你更好地掌握脚本编写和账户管理的知识,提高 Linux 系统的使用效率和安全性。在实际应用中,要不断学习和实践,根据具体情况灵活运用这些知识。
超级会员免费看
2378

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



