创建一个脚本来识别过去 15 天内未登录的用户

创建一个脚本来识别过去 15 天内未登录的用户

我有疑问:

练习是:

编写一个脚本来检测过去 15 天内未登录且属于“alumnos”组的用户。该列表将添加到 /var/log/alumnos_sin_login 中。

我的做法:

    #2)
#!/bin/bash
#Scripts which detects users whose group is "alumnos" who have been not logged in,
#in the last 15 days. The users' list is added to /var/log/alumnos_sin_login
#RESULTADO holds those users who haven't entered in the last 15 days
#LISTA holds alumnos' users' list
#USUAEIO actual user being parsed
#RAIZ != "" if user has logged -15 days

#Read and check if group is not created
exec 0 </etc/gshadow
if [ $(grep "alumnos:") -e ]
then
    echo "Grupo alumnos no existe"
    exit 1
fi


RESULTADO="Los alumnos que llevan más de 15 días sin loguearse son: "
LISTA=$(grep "alumnos:" | cut -d ':' -f 4)
IFS=,
for USUARIO in $LISTA
do
    RAIZ=$(find /home/$USUARIO -atime +15 | grep "/home/$USUARIO")
    if [ $RAIZ != "" ]
    then
        RESULTADO="$RESULTADO $USUARIO"
    fi
done

echo $RESULTADO >> /var/log/alumnos_sin_login
exit 0

疑惑:如何改进这句话?

if [ $(grep "alumnos:") -e ]

检查该组是否已创建。如果它不存在,它工作正常,但如果它存在,它会报告:

bash: [: ==: unary operator was expected

为什么?

其次,是否有更好的方法来了解用户是否在过去 15 天内没有登录。因为在代码中我假设它的目录是 /home/name_of_user 并且它不是标准。我的意思是,是否有一个命令可以获取最后一个用户的登录时间,或者至少有一种方法可以正确了解其目录;因为我不知道。

感谢您的帮助。

答案1

获取过去 15 天内未登录的用户列表的最简单方法/home是使用以下lastlog命令

lastlog -b 15 

查看一行输出:

alumno1 pts/14 172.17.1.114 10 月 22 日星期六 22:18:57 +0100 2016

如果您只想要名称(第一个字段):

lastlog -b 15 | sed "1d" | awk ' { print $1 } '

sed "1d"如果用于删除lastlog标题)

男人最后记录

选项 适用于 lastlog 命令的选项有:

   -b, --before DAYS
       Print only lastlog records older than DAYS.

如果用户从未登录过,则将显示“从未登录过”消息,而不是端口和时间。

至于检查组的实际脚本:

#!/bin/bash 

getent group alumnos > /dev/null
if [ $? -ne 0 ]
then
    echo "group alumnos does not exist"
    exit 1
fi

for i in ` lastlog -b 15 | sed "1d" | awk ' { print $1 } '`
do
    if [ `id -ng $i` == "alumnos" ]
    then
        echo $i
    fi
done
exit 0

其中:
变量i将迭代由 给出的所有用户的名称lastlog
id -ng user给出当前迭代“$i”指向的用户组的名称,以
getent group alumnos检查该组是否存在

至于if你提到的错误;当grep没有找到任何东西时,它会错过一个操作数,然后变成空;因此出现错误。技巧之一是使用“x”填充字符串比较,如下所示:

if [ "x"$i == "xstring" ]
then
   ...

检查团体校友是否存在的另一种选择:

if [ $(grep "^alumnos:" /etc/group) -e ]
then
    echo "No group alumnos"
    exit 1
fi

检查具有多个组的用户的另一种选择:

groups user | grep alumnos

答案2

如果要列出属于补充组的用户foo,请使用

getent group foo | cut -d ':' -f 4- | tr -s '\n,' '\n\n'

getent命令使用“名称服务开关”;这意味着即使在用户信息和密码存储在远程服务器上的系统上,getent仍然可以获得用户信息:

  • getent passwd而不是解析/etc/passwd

  • getent group而不是解析/etc/group

如果上面指定了第三个参数,则仅显示相应的条目。 (还有shadowgshadow,但getent仅向具有特殊权限的用户提供信息。)

输出getent group foo类似于

foo:x:1001:user1,user2,user3

其中第一个字段是组名称,第二个字段是组密码(*如果没有密码,或者x仅在文件中gshadow),第三个字段是组 ID 号,第四个字段是以逗号分隔的用户列表将此组作为补充组。

cut -d ':' -f 4-命令从每行中删除前三个以冒号分隔的字段。 (或者,换句话说,它仅输出每个输入行中的第四个和任何后续的以冒号分隔的字段。)这将删除组名称、密码引用和组 ID 号。

tr -s '\n,' '\n\n'所有逗号转换为换行符,并将所有连续的换行符(和逗号)合并为单个换行符。

foo因此,输出只是作为补充组的用户名,每行一个用户名。

该列表不包括主要组 ( id -gn) 为foo;的用户。仅那些有foo( )作为补充组的人id -Gn

如果您想列出foo主要组的用户,请使用例如

getent passwd | awk -F ':' '$4=='$(id -g foo)' { print $1 }'

这次,我们转储整个 passwd 数据库,并使用 进行过滤awk

$(id -g foo)部分实际上位于单引号之外,因此扩展为 group 的组 ID 号foo。 awk 规则将每行上的第四个以冒号分隔的字段与( group 的foo)组 ID 号进行比较,如果匹配,则打印第一个字段(该用户的名称)。


lastlog命令可以用来获取用户的登录记录。该-t选项允许您指定考虑记录的天数。

命令的输出(特别是日期格式)lastlog已本地化。这意味着用户区域设置会影响日期在输出中显示的方式lastlog。如果您想确保输出始终为英文并使用英文日期格式,请使用

LANG=C LC_ALL=C lastlog

LANG=C LC_ALL=C是最常用于设置区域设置的两个环境变量。 Shell 允许您临时覆盖单个命令的环境,只需将它们放在命令本身之前即可。

例如,要仅列出最近 10 天内未登录的用户,您可以使用

LANG=C LC_ALL=C lastlog -t 10 | awk '/Never logged in/ { print $1 }'

请注意,但这不会将选择限制为该foo组的成员。


您始终可以使用以下命令检查用户是哪些补充组的成员

id -gn username

通过 Bash,您可以使用

groups=" $(id -gn "$user") "
if [ "${groups// foo / }" != "$groups" ]; then
    # user $user is a member of group foo
else
    # user $user is not a member of group foo
fi

检查用户是否$user是组的成员foo。 (同样,这仅检查补充组,而不检查主要组。每个用户都有一个主要组,可以使用 获得id -Gn "$user"。)

这是可行的,因为$groups首先设置为 user 的补充组的空格分隔列表$user,并带有前导空格和尾随空格。注意引用!Bash 表达式${groups// foo / }扩展为 的值$groups,但是全部的实例foo(注意前导空格和尾随空格)已删除(用空格替换)。

if子句将删除的值$groupsfoo删除的值进行比较$groups。如果两者不同,则$group必定包含foo。如果您不喜欢这个,您可以使用等效的

if id -Gn "$user" | tr -s ' \n' '\n\n' | grep -qxF foo ; then
    # user "$user" is a member of group foo
fi

在这里,tr将所有连续的空格和换行符组合成换行符,将组名称拆分为各自的行。执行grep -qxF foo“安静”的 grep ( -q),即它不输出任何内容,仅返回成功或失败(并且在像 Bash 中的管道命令中,成功/失败由管道中的最终命令确定);选项-x意味着比较整行(所以我们不接受所有组拥有 foo在他们之中,只有群体完全匹配 foo);最后,-F选项意味着grep解释foo为固定字符串,而不是正则表达式。 (只有foo在正则表达式中包含具有特殊含义的字符(如*[]等)才重要。)


要编写问题中描述的 Bash 脚本,您需要上面的一些内容 - 至少有两种不同的方法可以使用上面的一些内容来解决这个问题 - 加上某种“将每个输入读入变量”循环,即

some command | while read line ; do
    # Here, "$line" iterates through the lines
    # output by some command
done

相关内容