如何遍历用户?

Sil*_*eth 6 users shell-script accounts

如何循环遍历 shell 脚本中的所有用户?

我正在编写一个 shell 脚本来在系统上执行清理。如果脚本以 root 身份运行,我想在所有用户的主目录中执行请求的操作。

我想我可以遍历/etc/passwd; 中的行。然而,我看到的条目比活着的、呼吸的用户多得多。有什么特殊的方法可以清除虚拟用户/etc/passwd吗?

我更喜欢为 Bourne Shell 量身定制的解决方案(为了便携性)。也欢迎伪代码和纯粹的解释。

Gil*_*il' 6

没有枚举所有现有用户帐户的标准命令。在大多数 Unix 变体上,/etc/passwd包含本地帐户列表,始终具有相同的传统格式(以冒号分隔的列)。在带有 Glibc 的 Linux(即任何非嵌入式 Linux)上,您可以使用getent命令:getent passwd类似于cat /etc/passwd,但还包括远程帐户(NIS、LDAP 等)。

以下代码段枚举用户帐户:

getent passwd | while IFS=: read -r name password uid gid gecos home shell; do
  echo "$name's home directory is $home"
done
Run Code Online (Sandbox Code Playgroud)

以完全可靠的方式过滤有血有肉的用户是不可能的,因为用户数据库中没有任何内容说明用户是否是有血有肉的。(另外:测试账户算不算?来宾账户算不算?等等)这里有一些你可以应用的启发式方法。

  • 您可以过滤主目录似乎不是系统目录的用户。

    top=${home#/}; top=${top%%/*}
    case $top in
      |bin|dev|etc|lib*|no*|proc|sbin|usr|var) echo "Looks like a system user";;
      *) echo "Looks like a user with a real home directory";;
    esac
    
    Run Code Online (Sandbox Code Playgroud)
  • 您可以测试用户是否拥有他们的主目录。对于有血有肉的用户来说几乎总是这样,对于系统用户来说通常不是这样,但这不是很可靠,因为一些系统用户确实拥有他们的主目录。此外,如果有血有肉的用户的主目录是当前不可用的远程目录,则它可能不存在,尽管通常该目录会自动挂载。在 Linux 上:

    if [ -d "$home" ] && [ "$(stat -c %u "$home")" = "$uid" ]; then
      echo "Likely flesh-and-blood"
    else 
      echo "Probably a system user"
    fi
    
    Run Code Online (Sandbox Code Playgroud)
  • 您可以测试用户的外壳是否是实际外壳。但是许多系统用户也这样做,所以它比主目录更不可靠。

  • 您可以测试该帐户是否有密码。这并不完全可靠,因为有血有肉的用户并不总是有密码(例如,他们可能只有 SSH 密钥)。有时系统帐户有密码——特别是 root 帐户经常有。如何做到这一点取决于 Unix 变体,并且通常需要 root 访问权限。在带有影子密码的 Linux 上(这是 Linux 的正常情况),您需要查找/etc/shadow密码。

    case $(getent shadow "$name" | awk -F: '{print $2}') in
      ?|??) echo "No password on this account";;
      |\$*) echo "This account has a password";;
      *) echo "Weird password field";;
    esac
    
    Run Code Online (Sandbox Code Playgroud)
  • 许多系统为系统帐户与血肉用户定义了 UID 范围。范围取决于系统:默认值取决于 Unix 变体和发行版,通常可以由系统管理员配置。在大多数 Linux 发行版中,范围定义为login.defsUID_MINtoUID_MAX用于人类用户,其他值用于系统帐户。

我认为主目录的路径是最可靠的单一指标,但您可能希望将其与其他启发式方法结合使用。