【BASH】回顾与知识点梳理(二十二)

news2025/2/24 11:24:05

【BASH】回顾与知识点梳理 二十二

    • 二十二. Linux 账号管理
      • 22.1 Linux 的账号与群组
        • 使用者标识符: UID 与 GID
        • 使用者账号
          • /etc/passwd 文件结构
          • /etc/shadow 文件结构
        • 关于群组: 有效与初始群组、groups, newgrp
          • /etc/group 文件结构
          • 有效群组(effective group)与初始群组(initial group)
          • groups: 有效与支持群组的观察
          • newgrp: 有效群组的切换
          • /etc/gshadow
      • 22.2 账号管理
        • 新增与移除使用者: useradd, 相关配置文件, passwd, usermod, userdel
          • useradd
          • useradd 参考档(/etc/default/useradd)
          • useradd 参考档(/etc/login.defs)
          • passwd
          • chage

该系列目录 --> 【BASH】回顾与知识点梳理(目录)

二十二. Linux 账号管理

要登入 Linux 系统一定要有账号与密码才行,否则怎么登入,您说是吧?不过, 不同的使用者应该要拥有不同的权限才行吧?我们还可以透过 user/group 的特殊权限设定, 来规范出不同的群组开发项目呢~在 Linux 的环境下,我们可以透过很多方式来限制用户能够使用的系统资源, 包括第十章、bash提到的ulimit限制、还有特殊权限限制,如umask等等。 透过这些举动,我们可以规范出不同使用者的使用资源。另外,还记得系统管理员的账号吗?对! 就是 root 。请问一下,除了 root 之外,是否可以有其他的系统管理员账号? 为什么大家都要尽量避免使用数字型态的账号?如何修改用户相关的信息呢?这些我们都得要了解了解的!

22.1 Linux 的账号与群组

管理员的工作中,相当重要的一环就是『管理账号』啦!因为整个系统都是你在管理的, 并且所有一般用户的账号申请,都必须要透过你的协助才行!所以你就必须要了解一下如何管理好一个服务器主机的账号啦! 在管理 Linux 主机的账号时,我们必须先来了解一下 Linux 到底是如何辨别每一个使用者的!

使用者标识符: UID 与 GID

虽然我们登入 Linux 主机的时候,输入的是我们的账号,但是其实 Linux 主机并不会直接认识你的『账号名称』的,他仅认识 ID 啊 (ID 就是一组号码啦)。 由于计算机仅认识 0 与 1,所以主机对于数字比较有概念的;至于账号只是为了让人们容易记忆而已。 而你的 ID 与账号的对应就在/etc/passwd 当中哩。

每一个文件都具有『拥有人与拥有群组』的属性吗?没错啦~每个登入的使用者至少都会取得两个 ID ,一个是使用者 ID (User ID ,简称
UID)、一个是群组 ID (Group ID ,简称 GID)。

使用者账号

Linux 系统上面的用户如果需要登入主机以取得 shell 的环境来工作,那么你输入账号密码后,系统帮你处理了什么呢?

  1. 先找寻/etc/passwd里面是否有你输入的账号?如果没有则跳出,如果有的话则将该账号对应的 UID 与GID (在 /etc/group 中) 读出来,另外,该账号的家目录与 shell 设定也一并读出;
  2. 再来则是核对密码表啦!这时 Linux 会进入/etc/shadow里面找出对应的账号与 UID,然后核对一下你刚刚输入的密码与里头的密码是否相符?
  3. 如果一切都 OK 的话,就进入 Shell 控管的阶段啰!
/etc/passwd 文件结构

这个文件的构造是这样的:每一行都代表一个账号,有几行就代表有几个账号在你的系统中! 不过需要特别留意的是,里头很多账号本来就是系统正常运作所必须要的,我们可以简称他为系统账号,例如 bin, daemon, adm, nobody 等等,这些账号请不要随意的杀掉他呢!这个文件的内容有点像这样:

[root@node-135 yurq]# head -4 /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin

我们先来看一下每个 Linux 系统都会有的第一行,就是 root 这个系统管理员那一行好了, 你可以明显的看出来,每一行使用『:』分隔开,共有七个咚咚,分别是:

  1. 账号名称:
    就是账号啦!用来提供给对数字不太敏感的人类使用来登入系统的!需要用来对应 UID 喔。例如 root 的UID 对应就是 0 (第三字段);
  2. 密码:
    早期 Unix 系统的密码就是放在这字段上!但是因为这个文件的特性是所有的程序都能够读取,这样一来很容易造成密码数据被窃取, 因此后来就将这个字段的密码数据给他改放到 /etc/shadow 中了。所以这里你会看到一个『 x 』,呵呵!
  3. UID:
    这个就是使用者标识符啰!通常 Linux 对于 UID 有几个限制需要说给您了解一下:
id 范围该 ID 使用者特性
0
(系统管理员)
当 UID 是 0 时,代表这个账号是『系统管理员』! 所以当你要让其他的账号名称也具有 root 的权限时,将该账号的 UID 改为 0 即可。 这也就是说,一部系统上面的系统管理员不见得只有 root 喔! 不过,很不建议有多个账号的 UID 是 0 啦~容易让系统管理员混乱!
1~999
(系统账号)
保留给系统使用的 ID,其实除了 0 之外,其他的 UID 权限与特性并没有不一样。默认 1000 以下的数字让给系统作为保留账号只是一个习惯。
由于系统上面启动的网络服务或背景服务希望使用较小的权限去运作,因此不希望使用 root 的身份去执行这些服务, 所以我们就得要提供这些运作中程序的拥有者账号才行。这些系统账号通常是不可登入的, 所以才会有我们在第十章提到的/sbin/nologin 这个特殊的 shell 存在。
根据系统账号的由来,通常这类账号又约略被区分为两种:
- 1~200:由 distributions 自行建立的系统账号;
- 201~999:若用户有系统账号需求时,可以使用的账号 UID。
1000~60000
(可登入账号)
给一般使用者用的。事实上,目前的 linux 核心 (3.10.x 版)已经可以支持到4294967295 (2^32-1) 这么大的 UID 号码喔!
  1. GID:
    这个与 /etc/group 有关!其实 /etc/group 的观念与 /etc/passwd 差不多,只是他是用来规范组名与 GID 的对应而已!
  2. 用户信息说明栏:
    这个字段基本上并没有什么重要用途,只是用来解释这个账号的意义而已!不过,如果您提供使用 finger 的功能时, 这个字段可以提供很多的讯息呢!本章后面的 chfn 指令会来解释这里的说明。
  3. 家目录:
    这是用户的家目录,以上面为例, root 的家目录在 /root ,所以当 root 登入之后,就会立刻跑到 /root 目录里头啦!呵呵! 如果你有个账号的使用空间特别的大,你想要将该账号的家目录移动到其他的硬盘去该怎么作? 没有错!可以在这个字段进行修改呦!默认的用户家目录在 /home/yourIDname
  4. Shell:
    当用户登入系统后就会取得一个 Shell 来与系统的核心沟通以进行用户的操作任务。那为何预设 shell 会使用 bash 呢?就是在这个字段指定的啰! 这里比较需要注意的是,有一个 shell 可以用来替代成让账号无法取得 shell 环境的登入动作!那就是 /sbin/nologin 这个东西!这也可以用来制作纯 pop 邮件账号者的数据呢!
/etc/shadow 文件结构

我们知道很多程序的运作都与权限有关,而权限与 UID/GID 有关!因此各程序当然需要读取/etc/passwd 来了解不同账号的权限。 因此 /etc/passwd 的权限需设定为 -rw-r--r-- 这样的情况, 虽然早期的密码也有加密过,但却放置到 /etc/passwd 的第二个字段上!这样一来很容易被有心人士所窃取的, 加密过的密码也能够透过暴力破解法去 trial and error (试误) 找出来!

因为这样的关系,所以后来发展出将密码移动到 /etc/shadow 这个文件分隔开来的技术, 而且还加入很多的密码限制参数在 /etc/shadow 里头呢!在这里,我们先来了解一下这个文件的构造吧! 鸟哥的 /etc/shadow 文件有点像这样:

[root@node-135 yurq]# ll /etc/passwd
-rw-r--r-- 1 root root 1204 Aug 11 10:13 /etc/passwd

[root@node-135 yurq]# ll /etc/shadow
----------. 1 root root 849 Aug  9 09:25 /etc/shadow

[root@node-135 yurq]# head -4 /etc/shadow
root:$6$CxTq1OkkZPBr3c.8$mQEBysixMLtVF2I7vwH/78y0Kl3wT0n7PRVINuFPRWLPiyZZObH8fpC8ZgSu9AaetwuEf/zqNkuN99cUVIrzu1::0:99999:7:::
bin:*:18353:0:99999:7:::
daemon:*:18353:0:99999:7:::
adm:*:18353:0:99999:7:::

基本上, shadow 同样以『:』作为分隔符,如果数一数,会发现共有九个字段啊,这九个字段的用途是这样的:

  1. 账号名称:
    由于密码也需要与账号对应啊~因此,这个文件的第一栏就是账号,必须要与 /etc/passwd 相同才行!

  2. 密码:
    这个字段内的数据才是真正的密码,而且是经过编码的密码 (加密) 啦! 你只会看到有一些特殊符号的字母就是了!需要特别留意的是,虽然这些加密过的密码很难被解出来, 但是『很难』不等于『不会』,所以,这个文件的预设权限是『-rw-------』或者是『----------』,亦即只有 root 才可以读写就是了!你得随时注意,不要不小心更动了这个文件的权限呢!

    另外,由于各种密码编码的技术不一样,因此不同的编码系统会造成这个字段的长度不相同。 举例来说,旧式的 DES, MD5 编码系统产生的密码长度就与目前惯用的 SHA 不同!SHA 的密码长度明显的比较长些。由于固定的编码系统产生的密码长度必须一致,因此『当你让这个字段的长度改变后,该密码就会失效(算不出来)』。 很多软件透过这个功能,在此字段前加上 ! 或 * 改变密码字段长度,就会让密码『暂时失效』了

  3. 最近更动密码的日期:
    这个字段记录了『更动密码那一天』的日期,不过,很奇怪呀!在我的例子中怎么会是 16559 呢?呵呵,这个是因为计算 Linux 日期的时间是以 1970 年 1 月 1 日作为 1 而累加的日期,1971 年 1 月 1 日则为 366 啦! 得注意一下这个资料呦!上述的 16559 指的就是 2015-05-04 那一天啦!了解乎? 而想要了解该日期可以使用本章后面 chage 指令的帮忙!至于想要知道某个日期的累积日数, 可使用如下的程序计算:

    [root@node-135 yurq]#  echo $(($(date --date="2023/08/11" +%s)/86400+1))
    19580
    

    86400 为每一天的秒数, %s 为 1970/01/01 以来的累积总秒数。 由于 bash 仅支持整数,因此最终需要加上 1 补齐 1970/01/01 当天。

  4. 密码不可被更动的天数:(与第 3 字段相比)
    第四个字段记录了:这个账号的密码在最近一次被更改后需要经过几天才可以再被变更!如果是 0 的话,表示密码随时可以更动的意思。这的限制是为了怕密码被某些人一改再改而设计的!如果设定为 20 天的话,那么当你设定了密码之后, 20 天之内都无法改变这个密码呦!

  5. 密码需要重新变更的天数:(与第 3 字段相比)
    经常变更密码是个好习惯!为了强制要求用户变更密码,这个字段可以指定在最近一次更改密码后, 在多少天数内需要再次的变更密码才行。你必须要在这个天数内重新设定你的密码,否则这个账号的密码将会『变为过期特性』。 而如果像上面的 99999 (计算为 273 年) 的话,那就表示,呵呵,密码的变更没有强制性之意。

  6. 密码需要变更期限前的警告天数:(与第 5 字段相比)
    当账号的密码有效期限快要到的时候 (第 5 字段),系统会依据这个字段的设定,发出『警告』言论给这个账号,提醒他『再过 n 天你的密码就要过期了,请尽快重新设定你的密码呦!』,如上面的例子,则是密码到期之前的 7 天之内,系统会警告该用户。

  7. 密码过期后的账号宽限时间(密码失效日):(与第 5 字段相比)
    密码有效日期为『更新日期(第 3 字段)』+『重新变更日期(第 5 字段)』,过了该期限后用户依旧没有更新密码,那该密码就算过期了。 虽然密码过期但是该账号还是可以用来进行其他工作的,包括登入系统取得bash 。不过如果密码过期了, 那当你登入系统时,系统会强制要求你必须要重新设定密码才能登入继续使用喔,这就是密码过期特性

    那这个字段的功能是什么呢?是在密码过期几天后,如果使用者还是没有登入更改密码,那么这个账号的密码将会『失效』, 亦即该账号再也无法使用该密码登入了。要注意密码过期与密码失效并不相同

  8. 账号失效日期:
    这个日期跟第三个字段一样,都是使用 1970 年以来的总日数设定。这个字段表示: 这个账号在此字段规定的日期之后,将无法再使用。 就是所谓的『账号失效』,此时不论你的密码是否有过期,这个『账号』都不能再被使用! 这个字段会被使用通常应该是在『收费服务』的系统中,你可以规定一个日期让该账号不能再使用啦!

  9. 保留:
    最后一个字段是保留的,看以后有没有新功能加入。

但在某些情况底下你得要使用各种方法来处理这个文件的!举例来说,常常听到人家说:『我的密码忘记了』, 或者是『我的密码不晓得被谁改过,跟原先的不一样了』,这个时候怎么办?

  • 一般用户的密码忘记了:这个最容易解决,请系统管理员帮忙, 他会重新设定好你的密码而不需要知道你的旧密码!利用 root 的身份使用 passwd 指令来处理即可。
  • root 密码忘记了:这就麻烦了!因为你无法使用 root 的身份登入了嘛! 但我们知道 root 的密码在/etc/shadow 当中,因此你可以使用各种可行的方法开机进入 Linux 再去修改。 例如重新启动进入单人维护模式后,系统会主动的给予 root 权限的 bash 接口, 此时再以 passwd 修改密码即可;或以Live CD 开机后挂载根目录去修改 /etc/shadow,将里面的 root 的密码字段清空, 再重新启动后 root 将
    不用密码即可登入!登入后再赶快以 passwd 指令去设定 root 密码即可。

如果你想要知道 shadow 是使用哪种加密的机制时, 可以透过底下的方法去查询喔!

[root@node-135 yurq]#  authconfig --test | grep hashing
 password hashing algorithm is sha512

关于群组: 有效与初始群组、groups, newgrp

/etc/group 文件结构

这个文件就是在记录 GID 与组名的对应了~鸟哥测试机的 /etc/group 内容有点像这样:

[root@study ~]# head -n 4 /etc/group
root:x:0:
bin:x:1:
daemon:x:2:
sys:x:3:
...
project:x:1001:alex,arod

这个文件每一行代表一个群组,也是以冒号『:』作为字段的分隔符,共分为四栏,每一字段的意义是:

  1. 组名:
    就是组名啦!同样用来给人类使用的,基本上需要与第三字段的 GID 对应。
  2. 群组密码:
    通常不需要设定,这个设定通常是给『群组管理员』使用的,目前很少有这个机会设定群组管理员啦! 同样的,密码已经移动到 /etc/gshadow 去,因此这个字段只会存在一个『x』而已;
  3. GID:
    就是群组的 ID 啊。我们 /etc/passwd 第四个字段使用的 GID 对应的群组名,就是由这里对应出来的!
  4. 此群组支持的账号名称:
    我们知道一个账号可以加入多个群组,那某个账号想要加入此群组时,将该账号填入这个字段即可。 举例来说,如果我想要让 dmtsai 与 alex 也加入 root 这个群组,那么在第一行的最后面加上『dmtsai,alex』,注意不要有空格, 使成为『 root:x:0:dmtsai,alex 』就可以啰~

谈完了 /etc/passwd, /etc/shadow, /etc/group 之后,我们可以使用一个简单的图示来了解一下 UID / GID 与密码之间的关系, 图示如下。其实重点是 /etc/passwd 啦,其他相关的数据都是根据这个文件的字段去找寻出来的。 下图中, root 的 UID 是 0 ,而 GID 也是 0 ,去找 /etc/group 可以知道 GID 为 0 时的组名就是 root 哩。 至于密码的寻找中,会找到 /etc/shadow 与 /etc/passwd 内同账号名称的那一行,就是密码相关数据啰
在这里插入图片描述

[root@node-135 yurq]# tail -3 /etc/passwd
tss:x:59:59:Account used by the trousers package to sandbox the tcsd daemon:/dev/null:/sbin/nologin
alex:x:1001:1002::/home/alex:/bin/bash		#属组 1002
arod:x:1002:1003::/home/arod:/bin/bash
[root@node-135 yurq]# id alex
uid=1001(alex) gid=1002(alex) groups=1002(alex),1001(project)	#附加组 1001
[root@node-135 yurq]# tail -3 /etc/group
project:x:1001:alex,arod		#附加组 1001 ==> project
alex:x:1002:					#属组 1002 ==> alex
arod:x:1003:

至于在 /etc/group 比较重要的特色在于第四栏啦,因为每个使用者都可以拥有多个支持的群组。不过这里你或许会觉得奇怪的,那就是:『假如我同时加入多个群组,那么我在作业的时候,到底是以那个群组为准?』 底下我们就来谈一谈这个『有效群组』的概念。

有效群组(effective group)与初始群组(initial group)

还记得每个使用者在他的 /etc/passwd 里面的第四栏有所谓的 GID 吧?那个 GID 就是所谓的『初始群组 (initial group) 』!也就是说,当用户一登入系统,立刻就拥有这个群组的相关权限的意思。 举例来说,我们上面提到 dmtsai 这个使用者的 /etc/passwd 与 /etc/group 还有 /etc/gshadow 相关的内容如下:

[root@study ~]# usermod -a -G users dmtsai <==先设定好次要群组
[root@study ~]# grep dmtsai /etc/passwd /etc/group /etc/gshadow
/etc/passwd:dmtsai:x:1000:1000:dmtsai:/home/dmtsai:/bin/bash
/etc/group:wheel:x:10:dmtsai <==次要群组的设定、安装时指定的
/etc/group:users:x:100:dmtsai <==次要群组的设定
/etc/group:dmtsai:x:1000: <==因为是初始群组,所以第四字段不需要填入账号
/etc/gshadow:wheel:::dmtsai <==次要群组的设定
/etc/gshadow:users:::dmtsai <==次要群组的设定
/etc/gshadow:dmtsai:!!::

非初始群组的其他群组可就不同了。举上面这个例子来说,我将 dmtsai 加入 users 这个群组当中,由于 users 这个群组并非是 dmtsai 的初始群组,因此, 我必须要在 /etc/group 这个文件中,找到 users 那一行,并且将 dmtsai 这个账号加入第四栏, 这样 dmtsai 才能够加入 users 这个群组啊。

那么在这个例子当中,因为我的 dmtsai 账号同时支持 dmtsai, wheel 与 users 这三个群组, 因此,在读取/写入/执行文件时,针对群组部分,只要是 users, wheel 与 dmtsai 这三个群组拥有的功能,我dmtsai 这个使用者都能够拥有喔!这样瞭呼?不过,这是针对已经存在的文件而言, 如果今天我要建立一个新的文件或者是新的目录,请问一下,新文件的群组是 dmtsai, wheel 还是 users ?呵呵!这就得要检查一下当时的有效群组了 (effective group)。

groups: 有效与支持群组的观察

如果我以 dmtsai 这个使用者的身份登入后,该如何知道我所有支持的群组呢? 很简单啊,直接输入 groups 就可以了!注意喔,是 groups 有加 s 呢!结果像这样:

[dmtsai@study ~]$ groups
dmtsai wheel users

第一个输出的群组即为有效群组 (effective group) 了。也就是说,我的有效群组为 dmtsai 啦~此时,如果我以 touch 去建立一个新档,例如:『 touch test 』,那么这个文件的拥有者为 dmtsai ,而且群组也是 dmtsai 的啦。

[dmtsai@study ~]$ touch test
[dmtsai@study ~]$ ll test
-rw-rw-r--. 1 dmtsai dmtsai 0 Jul 20 19:54 test
newgrp: 有效群组的切换

那么如何变更有效群组呢?就使用 newgrp 啊!不过使用 newgrp 是有限制的,那就是你想要切换的群组必须是你已经有支持的群组。举例来说, dmtsai 可以在 dmtsai/wheel/users 这三个群组间切换有效群组,但是 dmtsai 无法切换有效群组成为 sshd 啦!使用的方式如下:

[dmtsai@study ~]$ newgrp users
[dmtsai@study ~]$ groups
users wheel dmtsai
[dmtsai@study ~]$ touch test2
[dmtsai@study ~]$ ll test*
-rw-rw-r--. 1 dmtsai dmtsai 0 Jul 20 19:54 test
-rw-r--r--. 1 dmtsai users 0 Jul 20 19:56 test2
[dmtsai@study ~]$ exit # 注意!记得离开 newgrp 的环境喔

我们额外的来讨论一下 newgrp 这个指令,这个指令可以变更目前用户的有效群组, 而且是另外以一个 shell 来提供这个功能的喔,所以,以上面的例子来说, dmtsai 这个使用者目前是以另一个 shell 登入的,而且新的 shell 给予 dmtsai 有效 GID 为users 就是了。如果以图示来看就是如下所示:
在这里插入图片描述
虽然用户的环境设定(例如环境变量等等其他数据)不会有影响,但是使用者的『群组权限』将会重新被计算。 但是需要注意,由于是新取得一个 shell ,因此如果你想要回到原本的环境中,请输入exit回到原本的 shell 喔!

你要加入一个群组有两个方式:

  • 一个是透过系统管理员(root) 利用 usermod 帮你加入,如果 root 太忙了而且你的系统有设定群组管理员
  • 那么你可以透过群组管理员以 gpasswd 帮你加入他所管理的群组中!
/etc/gshadow

刚刚讲了很多关于『有效群组』的概念,另外,也提到 newgrp 这个指令的用法,但是,如果/etc/gshadow 这个设定没有搞懂得话,那么 newgrp 是无法动作的呢!鸟哥测试机的 /etc/gshadow 的内容有点像这样:

[root@study ~]# head -n 4 /etc/gshadow
root:::
bin:::
daemon:::
sys:::

这个文件内同样还是使用冒号『:』来作为字段的分隔字符,而且你会发现,这个文件几乎与 /etc/group 一模一样啊!是这样没错~不过,要注意的大概就是第二个字段吧~第二个字段是密码栏, 如果密码栏上面是『!』或空的时,表示该群组不具有群组管理员!至于第四个字段也就是支持的账号名称啰~ 这四个字段的意义为:

  1. 组名
  2. 密码栏,同样的,开头为 ! 表示无合法密码,所以无群组管理员
  3. 群组管理员的账号 (相关信息在 gpasswd 中介绍)
  4. 有加入该群组支持的所属账号 (与 /etc/group 内容相同!)

以系统管理员的角度来说,这个 gshadow 最大的功能就是建立群组管理员啦! 那么什么是群组管理员呢?由于系统上面的账号可能会很多,但是我们 root 可能平时太忙碌,所以当有使用者想要加入某些群组时, root 或许会没有空管理。此时如果能够建立群组管理员的话,那么该群组管理员就能够将那个账号加入自己管理的群组中! 可以免去 root 的忙碌啦!不过,由于目前有类似 sudo 之类的工具, 所以这个群组管理员的功能已经很少使用了。我们会在后续的 gpasswd 中介绍这个实作。

22.2 账号管理

好啦!既然要管理账号,当然是由新增与移除使用者开始的啰~底下我们就分别来谈一谈如何新增、移除与更改用户的相关信息吧~

新增与移除使用者: useradd, 相关配置文件, passwd, usermod, userdel

useradd
[root@study ~]# useradd [-u UID] [-g 初始群组] [-G 次要群组] [-mM] [-c 说明栏] [-d 家目录绝对路径] [-s shell] 使用者账号名
选项与参数:
-u :后面接的是 UID ,是一组数字。直接指定一个特定的 UID 给这个账号;
-g :后面接的那个组名就是我们上面提到的 initial group 啦~ 该群组的 GID 会被放置到 /etc/passwd 的第四个字段内。
-G :后面接的组名则是这个账号还可以加入的群组。 这个选项与参数会修改 /etc/group 内的相关资料喔!
-M :强制!不要建立用户家目录!(系统账号默认值)
-m :强制!要建立用户家目录!(一般账号默认值)
-c :这个就是 /etc/passwd 的第五栏的说明内容啦~可以随便我们设定的啦~
-d :指定某个目录成为家目录,而不要使用默认值。务必使用绝对路径!
-r :建立一个系统的账号,这个账号的 UID 会有限制 (参考 /etc/login.defs)
-s :后面接一个 shell ,若没有指定则预设是 /bin/bash 的啦~
-e :后面接一个日期,格式为『YYYY-MM-DD』此项目可写入 shadow 第八字段, 亦即账号失效日的设定项目啰;
-f :后面接 shadow 的第七字段项目,指定密码是否会失效。0 为立刻失效, -1 为永远不失效(密码只会过期而强制于登入时重新设定而已。)
# 范例一:完全参考默认值建立一个用户,名称为 vbird1
[root@study ~]# useradd vbird1
[root@study ~]# ll -d /home/vbird1
drwx------. 3 vbird1 vbird1 74 Jul 20 21:50 /home/vbird1
# 默认会建立用户家目录,且权限为 700 !这是重点!
[root@study ~]# grep vbird1 /etc/passwd /etc/shadow /etc/group
/etc/passwd:vbird1:x:1003:1004::/home/vbird1:/bin/bash
/etc/shadow:vbird1:!!:16636:0:99999:7:::
/etc/group:vbird1:x:1004: <==预设会建立一个与账号一模一样的群组名

CentOS 这些默认值主要会帮我们处理几个项目:

  • 在 /etc/passwd 里面建立一行与账号相关的数据,包括建立 UID/GID/家目录等;
  • 在 /etc/shadow 里面将此账号的密码相关参数填入,但是尚未有密码;
  • 在 /etc/group 里面加入一个与账号名称一模一样的组名;
  • 在 /home 底下建立一个与账号同名的目录作为用户家目录,且权限为 700

由于在 /etc/shadow 内仅会有密码参数而不会有加密过的密码数据,因此我们在建立使用者账号时,还需要使用『 passwd 账号 』来给予密码才算是完成了用户建立的流程。如果由于特殊需求而需要改变使用者相关参数时, 就得要透过上述表格中的选项来进行建立了,参考底下的案例:

# 范例二:假设我已知道我的系统当中有个组名为 users ,且 UID 1500 并不存在,
#	 请用 users 为初始群组,以及 uid 为 1500 来建立一个名为 vbird2 的账号
[root@study ~]# useradd -u 1500 -g users vbird2
[root@study ~]# ll -d /home/vbird2
drwx------. 3 vbird2 users 74 Jul 20 21:52 /home/vbird2
[root@study ~]# grep vbird2 /etc/passwd /etc/shadow /etc/group
/etc/passwd:vbird2:x:1500:100::/home/vbird2:/bin/bash
/etc/shadow:vbird2:!!:16636:0:99999:7:::
# 看一下,UID 与 initial group 确实改变成我们需要的了!

了解了一般账号后,我们来瞧瞧那啥是系统账号 (system account) 吧!

# 范例三:建立一个系统账号,名称为 vbird3
[root@study ~]# useradd -r vbird3
[root@study ~]# ll -d /home/vbird3
ls: cannot access /home/vbird3: No such file or directorya <==不会主动建立家目录
[root@study ~]# grep vbird3 /etc/passwd /etc/shadow /etc/group
/etc/passwd:vbird3:x:699:699::/home/vbird3:/bin/bash
/etc/shadow:vbird3:!!:16636::::::
/etc/group:vbird3:x:699:

由于系统账号主要是用来进行运作系统所需服务的权限设定, 所以系统账号默认都不会主动建立家目录的!

由这几个范例我们也会知道,使用 useradd 建立使用者账号时,其实会更改不少地方,至少我们就知道底下几个文件:

  • 用户账号与密码参数方面的文件:/etc/passwd, /etc/shadow
  • 使用者群组相关方面的文件:/etc/group, /etc/gshadow
  • 用户的家目录:/home/账号名称

那请教一下,你有没有想过,为何『 useradd vbird1 』会主动在 /home/vbird1 建立起用户的家目录?家目录内有什么数据且来自哪里?为何预设使用的是 /bin/bash 这个 shell ?为何密码字段已经都规范好了 (0:99999:7 那一串)?呵呵!这就得要说明一下 useradd 所使用的参考文件啰!

useradd 参考档(/etc/default/useradd)

其实 useradd 的默认值可以使用底下的方法呼叫出来:

[root@study ~]# useradd -D
GROUP=100 <==预设的群组
HOME=/home <==默认的家目录所在目录
INACTIVE=-1 <==密码失效日,在 shadow 内的第 7EXPIRE= <==账号失效日,在 shadow 内的第 8SHELL=/bin/bash <==预设的 shell
SKEL=/etc/skel <==用户家目录的内容数据参考目录
CREATE_MAIL_SPOOL=yes <==是否主动帮使用者建立邮件信箱(mailbox)

这个数据其实是由/etc/default/useradd呼叫出来的!你可以自行用 vim 去观察该文件的内容。搭配上头刚刚谈过的范例一的运作结果,上面这些设定项目所造成的行为分别是:

  • GROUP=100:新建账号的初始群组使用 GID 为 100 者
    系统上面 GID 为 100 者即是 users 这个群组,此设定项目指的就是让新设使用者账号的初始群组为 users 这一个的意思。 但是我们知道 CentOS 上面并不是这样的,在 CentOS 上面预设的群组为与账号名相同的群组。 举例来说, vbird1 的初始群组为 vbird1 。怎么会这样啊?这是因为针对群组的角度有两种不同的机制所致, 这两种机制分别是:

    • 私有群组机制:
      系统会建立一个与账号一样的群组给使用者作为初始群组。 这种群组的设定机制会比较有保密性,这是因为使用者都有自己的群组,而且家目录权限将会设定为 700 (仅有自己可进入自己的家目录) 之故。使用这种机制将不会参考 GROUP=100 这个设定值。代表性的 distributions 有 RHEL, Fedora, CentOS 等;
    • 公共群组机制:
      就是以 GROUP=100 这个设定值作为新建账号的初始群组,因此每个账号都属于 users 这个群组,且默认家目录通常的权限会是『 drwxr-xr-x … username users … 』,由于每个账号都属于 users 群组,因此大家都可以互相分享家目录内的数据之故。代表 distributions 如 SuSE 等。

    由于我们的 CentOS 使用私有群组机制,因此这个设定项目是不会生效的!不要太紧张啊!

  • HOME=/home:用户家目录的基准目录(basedir)
    用户的家目录通常是与账号同名的目录,这个目录将会摆放在此设定值的目录后。所以 vbird1 的
    家目录就会在 /home/vbird1/ 了!很容易理解吧!

  • INACTIVE=-1:密码过期后是否会失效的设定值
    我们在 shadow 文件结构当中谈过,第七个字段的设定值将会影响到密码过期后, 在多久时间内还可使用旧密码登入。这个项目就是在指定该日数啦!如果是 0 代表密码过期立刻失效, 如果是 -1 则是代表密码永远不会失效,如果是数字,如 30 ,则代表过期 30 天后才失效。

  • EXPIRE=:账号失效的日期
    就是 shadow 内的第八字段,你可以直接设定账号在哪个日期后就直接失效,而不理会密码的问题。通常不会设定此项目,但如果是付费的会员制系统,或许这个字段可以设定喔!

  • SHELL=/bin/bash:默认使用的 shell 程序文件名
    系统默认的 shell 就写在这里。假如你的系统为 mail server ,你希望每个账号都只能使用 email 的收发信件功能, 而不许用户登入系统取得 shell ,那么可以将这里设定为 /sbin/nologin ,如此一来,新建的使用者预设就无法登入! 也免去后续使用 usermod 进行修改的手续!

  • SKEL=/etc/skel:用户家目录参考基准目录
    这个咚咚就是指定用户家目录的参考基准目录啰~举我们的范例一为例, vbird1 家目录/home/vbird1 内的各项数据,都是由 /etc/skel 所复制过去的~所以呢,未来如果我想要让新增使用者时,该用户的环境变量 ~/.bashrc 就设定妥当的话,您可以到 /etc/skel/.bashrc 去编辑一下,也可以建立 /etc/skel/www 这个目录,那么未来新增使用者后,在他的家目录下就会有 www 那个目录了!这样瞭呼?

  • CREATE_MAIL_SPOOL=yes:建立使用者的 mailbox
    你可以使用『ll /var/spool/mail/vbird1』看一下,会发现有这个文件的存在喔!这就是使用者的邮件信箱!

useradd 参考档(/etc/login.defs)

除了这些基本的账号设定值之外, UID/GID 还有密码参数又是在哪里参考的呢?那就得要看一下/etc/login.defs 啦! 这个文件的内容有点像底下这样:

MAIL_DIR /var/spool/mail <==用户默认邮件信箱放置目录
PASS_MAX_DAYS 99999 <==/etc/shadow 内的第 5 栏,多久需变更密码日数
PASS_MIN_DAYS 0 <==/etc/shadow 内的第 4 栏,多久不可重新设定密码日数
PASS_MIN_LEN 5 <==密码最短的字符长度,已被 pam 模块取代,失去效用!
PASS_WARN_AGE 7 <==/etc/shadow 内的第 6 栏,过期前会警告的日数
UID_MIN 1000 <==使用者最小的 UID,意即小于 1000UID 为系统保留
UID_MAX 60000 <==使用者能够用的最大 UID
SYS_UID_MIN 201 <==保留给用户自行设定的系统账号最小值 UID
SYS_UID_MAX 999 <==保留给用户自行设定的系统账号最大值 UID
GID_MIN 1000 <==使用者自定义组的最小 GID,小于 1000 为系统保留
GID_MAX 60000 <==使用者自定义组的最大 GID
SYS_GID_MIN 201 <==保留给用户自行设定的系统账号最小值 GID
SYS_GID_MAX 999 <==保留给用户自行设定的系统账号最大值 GID
CREATE_HOME yes <==在不加 -M-m 时,是否主动建立用户家目录?
UMASK 077 <==用户家目录建立的 umask ,因此权限会是 700
USERGROUPS_ENAB yes <==使用 userdel 删除时,是否会删除初始群组
ENCRYPT_METHOD SHA512 <==密码加密的机制使用的是 sha512 这一个机制!

这个文件规范的数据则是如下所示:

  • mailbox 所在目录:
    用户的默认 mailbox 文件放置的目录在 /var/spool/mail,所以 vbird1 的 mailbox 就是在/var/spool/mail/vbird1 啰!

  • shadow 密码第 4, 5, 6 字段内容:
    透过 PASS_MAX_DAYS 等等设定值来指定的!所以你知道为何预设的 /etc/shadow 内每一行都会有『 0:99999:7 』的存在了吗?^_^!不过要注意的是,由于目前我们登入时改用 PAM 模块来进行密码检验,所以那个 PASS_MIN_LEN 是失效的!

  • UID/GID 指定数值:
    虽然 Linux 核心支持的账号可高达 2^32 这么多个,不过一部主机要作出这么多账号在管理上也是很麻烦的!所以在这里就针对 UID/GID 的范围进行规范就是了。上表中的 UID_MIN 指的就是可登入系统的一般账号的最小 UID ,至于 UID_MAX 则是最大 UID 之意。

    要注意的是,系统给予一个账号 UID 时,他是 (1)先参考 UID_MIN 设定值取得最小数值; (2)由/etc/passwd 搜寻最大的 UID 数值, 将 (1) 与 (2) 相比,找出最大的那个再加一就是新账号的 UID 了。我们上面已经作出 UID 为 1500 的 vbird2 , 如果再使用『 useradd vbird4 』时,你猜 vbird4 的 UID 会是多少?答案是: 1501 。 所以中间的 1004~1499 的号码就空下来啦!而如果我是想要建立系统用的账号,所以使用 useradd -r sysaccount 这个 -r 的选项时,就会找『比 201 大但比 1000 小的最大的 UID 』就是了。 _

  • 用户家目录设定值:
    为何我们系统默认会帮用户建立家目录?就是这个『CREATE_HOME = yes』的设定值啦!这个设定值会让你在使用 useradd 时, 主动加入『-m』这个产生家目录的选项啊!如果不想要建立用户家目录,就只能强制加上『 -M 』的选项在 useradd 指令执行时啦!至于建立家目录的权限设定呢?就透过 umask 这个设定值啊!因为是077的预设设定,因此用户家目录默认权限才会是『 drwx------ 』哩!

  • 用户删除与密码设定值:
    使用『USERGROUPS_ENAB yes』这个设定值的功能是: 如果使用 userdel 去删除一个账号时,且该账号所属的初始群组已经没有人隶属于该群组了, 那么就删除掉该群组,举例来说,我们刚刚有建立 vbird4 这个账号,他会主动建立 vbird4 这个群组。 若 vbird4 这个群组并没有其他账号将他加入支持的情况下,若使用 userdel vbird4 时,该群组也会被删除的意思。 至于『ENCRYPT_METHOD SHA512』则表示使用SHA512 来加密密码明文,而不使用旧式的 MD5。

现在你知道啦,使用 useradd 这支程序在建立 Linux 上的账号时,至少会参考:

  • /etc/default/useradd
  • /etc/login.defs
  • /etc/skel/*

这些文件,不过,最重要的其实是建立 /etc/passwd, /etc/shadow, /etc/group, /etc/gshadow 还有用户家目录就是了~所以,如果你了解整个系统运作的状态,也是可以手动直接修改这几个文件就是了。OK!账号建立了,接下来处理一下用户的密码吧!

passwd

刚刚我们讲到了,使用 useradd 建立了账号之后,在预设的情况下,该账号是暂时被封锁的, 也就是说,该账号是无法登入的,你可以去瞧一瞧 /etc/shadow 内的第二个字段就晓得啰~ 那该如何是好?怕什么?直接给他设定新密码就好了嘛!对吧~设定密码就使用 passwd啰!

[root@study ~]# passwd [--stdin] [账号名称] <==所有人均可使用来改自己的密码
[root@study ~]# passwd [-l] [-u] [--stdin] [-S] \
> [-n 日数] [-x 日数] [-w 日数] [-i 日期] 账号 <==root 功能
选项与参数:
--stdin :可以透过来自前一个管线的数据,作为密码输入,对 shell script 有帮助!
-l :是 Lock 的意思,会将 /etc/shadow 第二栏最前面加上 ! 使密码失效;
-u :与 -l 相对,是 Unlock 的意思!
-S :列出密码相关参数,亦即 shadow 文件内的大部分信息。
-n :后面接天数,shadow 的第 4 字段,多久不可修改密码天数
-x :后面接天数,shadow 的第 5 字段,多久内必须要更动密码
-w :后面接天数,shadow 的第 6 字段,密码过期前的警告天数
-i :后面接『日期』,shadow 的第 7 字段,密码失效日期
# 范例一:请 root 给予 vbird2 密码
[root@study ~]# passwd vbird2
Changing password for user vbird2.
New UNIX password: <==这里直接输入新的密码,屏幕不会有任何反应
BAD PASSWORD: The password is shorter than 8 characters <==密码太简单或过短的错误!
Retype new UNIX password: <==再输入一次同样的密码
passwd: all authentication tokens updated successfully. <==竟然还是成功修改了!

# 范例二:用 vbird2 登入后,修改 vbird2 自己的密码
[vbird2@study ~]$ passwd <==后面没有加账号,就是改自己的密码!
Changing password for user vbird2.
Changing password for vbird2
(current) UNIX password: <==这里输入『原有的旧密码』
New UNIX password: <==这里输入新密码
BAD PASSWORD: The password is shorter than 8 characters <==密码太短!不可以设定!重新想
New password: <==这里输入新想的密码
BAD PASSWORD: The password fails the dictionary check - it is based on a dictionary word
# 同样的,密码设定在字典里面找的到该字符串,所以也是不建议!无法通过,再想新的!
New UNIX password: <==这里再想个新的密码来输入吧
Retype new UNIX password: <==通过密码验证!所以重复这个密码的输入
passwd: all authentication tokens updated successfully. <==有无成功看关键词

要帮一般账号建立密码需要使用『passwd 账号』的格式,使用『passwd』表示修改自己的密码!

与 root 不同的是,一般账号在更改密码时需要先输入自己的旧密码 (亦即 current 那一行),然后再输入新密码 (New 那一行)。 要注意的是,密码的规范是非常严格的,尤其新的 distributions 大多使用 PAM 模块来进行密码的检验,包括太短、 密码与账号相同、密码为字典常见字符串等,都会被PAM 模块检查出来而拒绝修改密码,此时会再重复出现『 New 』这个关键词! 那时请再想个新密码!若出现『 Retype 』才是你的密码被接受了!重复输入新密码并且看到『 successfully 』这个关键词时才是修改密码成功喔!

为何用户要设订自己的密码会这么麻烦啊?这是因为密码的安全性啦!如果密码设定太简单, 一些有心人士就能够很简单的猜到你的密码,如此一来人家就可能使用你的一般账号登入你的主机或使用其他主机资源(例如,前些年的挖矿), 对主机的维护会造成困扰的!所以新的 distributions 是使用较严格的 PAM 模块来管理密码,这个管理的机制写在/etc/pam.d/passwd当中。而该文件与密码有关的测试模块就是使用:pam_cracklib.so,这个模块会检验密码相关的信息, 并且取代 /etc/login.defs 内的 PASS_MIN_LEN 的设定啦!关于 PAM 我们在本章后面继续介绍,这里先谈一下, 理论上,你的密码最好符合如下要求:

  • 密码不能与账号相同;
  • 密码尽量不要选用字典里面会出现的字符串;
  • 密码需要超过 8 个字符;
  • 密码不要使用个人信息,如身份证、手机号码、其他电话号码等;
  • 密码不要使用简单的关系式,如 1+1=2, Iamvbird 等;
  • 密码尽量使用大小写字符、数字、特殊字符($,_,-等)的组合。

为了方便系统管理,新版的 passwd 还加入了很多创意选项喔!鸟哥个人认为最好用的大概就是这个『 --stdin 』了! 举例来说,你想要帮 vbird2 变更密码成为 abc543CC ,可以这样下达指令呢!

# 范例三:使用 standard input 建立用户的密码
[root@study ~]# echo "abc543CC" | passwd --stdin vbird2
Changing password for user vbird2.
passwd: all authentication tokens updated successfully.

这个动作会直接更新用户的密码而不用再次的手动输入!好处是方便处理,缺点是这个密码会保留在指令中, 未来若系统被攻破,人家可以在 /root/.bash_history 找到这个密码呢!所以这个动作通常仅用在 shell script 的大量建立使用者账号当中!要注意的是,这个选项并不存在所有 distributions 版本中, 请使用 man passwd 确认你的 distribution 是否有支持此选项喔!

# 范例四:管理 vbird2 的密码使具有 60 天变更、密码过期 10 天后账号失效的设定
[root@study ~]# passwd -S vbird2
vbird2 PS 2015-07-20 0 99999 7 -1 (Password set, SHA512 crypt.)
# 上面说明密码建立时间 (2015-07-20)、0 最小天数、99999 变更天数、7 警告日数与密码不会失效 (-1)
[root@study ~]# passwd -x 60 -i 10 vbird2
[root@study ~]# passwd -S vbird2
vbird2 PS 2015-07-20 0 60 7 10 (Password set, SHA512 crypt.)
# 让 vbird2 每 60 天需要变更密码, 密码过期后 10 天未使用就宣告账号失效

如果我想要让某个账号暂时无法使用密码登入主机呢?

# 范例五:让 vbird2 的账号失效,观察完毕后再让她失效
[root@study ~]# passwd -l vbird2
[root@study ~]# passwd -S vbird2
vbird2 LK 2015-07-20 0 60 7 10 (Password locked.)
# 嘿嘿!状态变成『 LK, Lock 』了啦!无法登入喔!
[root@study ~]# grep vbird2 /etc/shadow
vbird2:!!$6$iWWO6T46$uYStdkB7QjcUpJaCLB.OOp...:16636:0:60:7:10::
# 其实只是在这里加上 !! 而已!
[root@study ~]# passwd -u vbird2
[root@study ~]# grep vbird2 /etc/shadow
vbird2:$6$iWWO6T46$uYStdkB7QjcUpJaCLB.OOp...:16636:0:60:7:10::
# 密码字段恢复正常!
chage

除了使用 passwd -S 之外,有没有更详细的密码参数显示功能呢?有的!那就是 chage 了!他的用法如下:

[root@study ~]# chage [-ldEImMW] 账号名
选项与参数:
-l :列出该账号的详细密码参数;
-d :后面接日期,修改 shadow 第三字段(最近一次更改密码的日期),格式 YYYY-MM-DD
-E :后面接日期,修改 shadow 第八字段(账号失效日),格式 YYYY-MM-DD
-I :后面接天数,修改 shadow 第七字段(密码失效日期)
-m :后面接天数,修改 shadow 第四字段(密码最短保留天数)
-M :后面接天数,修改 shadow 第五字段(密码多久需要进行变更)
-W :后面接天数,修改 shadow 第六字段(密码过期前警告日期)

使用passwd -S却无法看到很清楚的说明。如果使用 chage 那可就明白多了!

# 范例一:列出 vbird2 的详细密码参数
[root@study ~]# chage -l vbird2
Last password change : Jul 20, 2015
Password expires : Sep 18, 2015
Password inactive : Sep 28, 2015
Account expires : never
Minimum number of days between password change : 0
Maximum number of days between password change : 60
Number of days of warning before password expires : 7

chage 有一个功能很不错喔!如果你想要让『使用者在第一次登入时, 强制她们一定要更改密码后才能够使用系统资源』,可以利用如下的方法来处理的!

# 范例二:建立一个名为 agetest 的账号,该账号第一次登入后使用默认密码,但必须
#		要更改过密码后,使用新密码才能够登入系统使用 bash 环境
[root@study ~]# useradd agetest
[root@study ~]# echo "agetest" | passwd --stdin agetest
[root@study ~]# chage -d 0 agetest
[root@study ~]# chage -l agetest | head -n 3
Last password change : password must be changed
Password expires : password must be changed
Password inactive : password must be changed
# 此时此账号的密码建立时间会被改为 1970/1/1 ,所以会有问题!

# 范例三:尝试以 agetest 登入的情况
You are required to change your password immediately (root enforced)
WARNING: Your password has expired.
You must change your password now and login again!
Changing password for user agetest.
Changing password for agetest
(current) UNIX password: <==这个账号被强制要求必须要改密码!

非常有趣吧!你会发现 agetest 这个账号在第一次登入时可以使用与账号同名的密码登入, 但登入时就会被要求立刻更改密码,更改密码完成后就会被踢出系统。再次登入时就能够使用新密码登入了!

该系列目录 --> 【BASH】回顾与知识点梳理(目录)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/863373.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

班费管理系统(Mybatis + Swing)学生班级信息java jsp源代码mysql

本项目为前几天收费帮学妹做的一个项目&#xff0c;Java EE JSP项目&#xff0c;在工作环境中基本使用不到&#xff0c;但是很多学校把这个当作编程入门的项目来做&#xff0c;故分享出本项目供初学者参考。 一、项目描述 班费管理系统&#xff08;Mybatis Swing) 系统有1权…

Java 正则表达式【匹配与分组基本原理】

简介 我们一般使用正则表达式是用来处理字符串的&#xff0c;不管是实际的开发中还是我们的算法竞赛中&#xff0c;使用正则表达式绝对可以大大提升我们的效率。 正则表达式&#xff08;regular expression&#xff09;其实就是对字符串进行模式匹配的技术。 快速入门 我们这里…

要过软考,务必先搞清楚这3点

前段时间软考成绩出来了&#xff0c;大家都过了没&#xff1f; 我看好多人都说早上的题目稳过&#xff0c;下午的好多都挂了。 软考每年这个通过率&#xff0c;确实是一言难尽。 到底怎么样才能过&#xff0c;自学、培训&#xff0c;各种诀窍&#xff0c;五花八门。 但考不过…

【无标题杭州生物制药公司【阿诺医药】申请纳斯达克IPO上市】

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 猛兽财经获悉&#xff0c;杭州生物制药公司阿诺医药&#xff08;Adlai Nortye&#xff09;近期已向美国证券交易委员会&#xff08;SEC&#xff09;提交招股书&#xff0c;申请在纳斯达克IPO上市&#xff0c;股票代码为&am…

OLED透明屏,与传统的显示屏相比,有哪些特点和优势?

近年来&#xff0c;随着科技的不断发展&#xff0c;人们对于安全防护的需求也越来越高。 传统的安防设备已经不能满足人们的需求&#xff0c;因此&#xff0c;透明屏作为一种新型的安防展示设备&#xff0c;逐渐受到人们的关注和喜爱。 透明屏是一种将显示屏与玻璃结合的新型…

要求表里某字段值唯一

在开发过程中&#xff0c;要求表里某字段值唯一 一、场景 在单据&#xff0c;要求某字段值不重复 查看数据模型&#xff1a; 查看单据&#xff1a; 二、问题 区域编码&#xff0c;区域名称不重复 三、解决方案 1&#xff09;数据库加索引 2&#xff09;书写保存后存储过…

plt绘制雷达图

1、圆形 import matplotlib.pyplot as plt import numpy as npplt.rcParams[font.sans-serif][SimHei] #显示中文 plt.rcParams[axes.unicode_minus]False #正常显示负号def radar_map(data, label, cls):# 设置雷达图的角度&#xff0c;用于平分切开一个圆面n len…

使用windows搭建WebDAV服务,并内网穿透公网访问【无公网IP】

文章目录 1. 安装IIS必要WebDav组件2. 客户端测试3. 使用cpolar内网穿透&#xff0c;将WebDav服务暴露在公网3.1 打开Web-UI管理界面3.2 创建隧道3.3 查看在线隧道列表3.4 浏览器访问测试 4. 安装Raidrive客户端4.1 连接WebDav服务器4.2 连接成功4.2 连接成功 1. Linux(centos8…

聚焦阅读和写作两大语文专项,猿辅导推出语文教辅《我们的语文》

近期正在热映的动画电影《长安三万里》火了。有人说&#xff0c;这是一部披着电影外衣的唐诗启蒙片&#xff0c;从中感受到了传统文化的魅力和教育的“延时性”。电影里借大唐诗人之口&#xff0c;通过48首诗词让我们体味到从大唐奔流而来的诗意&#xff0c;带我们回味独属的中…

大模型时代下的我们,破茧重生探索新开发范式!|WAVE SUMMIT 开源论坛

WAVE SUMMIT深度学习开发者峰会2023由深度学习技术及应用国家工程研究中心主办&#xff0c;百度飞桨和文心大模型承办。大会设有1个主论坛&#xff0c;5个平行论坛&#xff0c;本次为大家介绍「开源共建 智领未来」开源论坛。 AGI时代到来&#xff0c;机遇与危机并存 身处时代洪…

有没有推荐的golang的练手项目?

前言 下面是github上的golang项目&#xff0c;适合练手&#xff0c;可以自己选择一些项目去练习&#xff0c;整理不易&#xff0c;希望能多多点赞收藏一下&#xff01;废话少说&#xff0c;我们直接进入正题>>> 先推荐几个教程性质的项目&#xff08;用于新手学习、巩…

Cobbler自动化部署安装CentOS7

Cobbler介绍&#xff1a; 1&#xff09;Cobbler是一个Linux服务器安装的服务&#xff0c;可以通过网络启动PXE的方式来快速安装、重装物理服务器和虚拟机&#xff0c;同时还可以管理DHCP、DNS等。 2&#xff09;Cobbler 可以使用命令行的方式管理&#xff0c;也提供了基于Web的…

即时通讯App开发:从0到1的全过程

在数字化时代&#xff0c;即时通讯已经成为人们生活中不可或缺的一部分。如果你想进入这个领域并开发属于自己的即时通讯应用程序&#xff0c;本文将为你提供从0到1的全过程指南。 1. 设想和市场研究 在着手开发之前&#xff0c;你需要明确你的应用程序的核心特点和目标用户群…

LeetCode算法递归类—验证二叉搜索树

目录 98. 验证二叉搜索树 题解&#xff1a; 代码&#xff1a; 运行结果&#xff1a;​编辑 给你一个二叉树的根节点 root &#xff0c;判断其是否是一个有效的二叉搜索树。 有效 二叉搜索树定义如下&#xff1a; 节点的左子树只包含 小于 当前节点的数。节点的右子树只包含…

C语言必会题目(1)

W...Y的主页 &#x1f60a; 代码仓库分享❤️ 在学习语言时&#xff0c;最重要的就是练习&#xff0c;光听不练假把式。下面我就推荐一些C语言必会的题。 执行下面程序&#xff0c;正确的输出是&#xff08; &#xff09; int x5,y7; void swap() { int z; zx; xy; yz; } int…

【几个python虚拟环境会遇到的问题】

几个python虚拟环境会遇到的问题 twine is not recognized as an internal or external command,operable program or batch file.setup命令不报错但不起作用pipreqs is not recognized as an internal or external command,operable program or batch file. ‘twine’ is not …

安卓中常见的字节码指令介绍

问题背景 安卓开发过程中&#xff0c;经常要通过看一些java代码对应的字节码&#xff0c;来了解java代码编译后的运行机制&#xff0c;本文将通过一个简单的demo介绍一些基本的字节码指令。 问题分析 比如以下代码&#xff1a; public class test {public static void main…

I 2C 接口控制器理论讲解

IIC系列文章&#xff1a; (1) I 2C 接口控制器理论讲解 (2) I2C接口控制设计与实现 文章目录 一、 IIC协议二、IIC协议解析1.特点2.规定3.器件地址4.存储地址 三、IIC写时序1.单字节写时序2.连续写时序&#xff08;页写时序&#xff09; 四、IIC读时序1.单字节读时序2.连续读时…

Unity3D高级编程:主程手记学习1

第一章 软件架构 Untiy 分层设计 分层后再分治

C++复习笔记——primer第五版

文章目录 一、引用和指针1.引用2.指针2.1利用指针访问对象2.2指针的值或指针所指对象的值的改变 3.赋值和指针4.指向指针的引用 二、String1.初始化String对象的方式2. string对象上的操作3.使用getline读取一整行4.字面值和字符串相加5.使用for循环改变字符串中的字符 三、Vec…