我正在编写这个bash脚本,该脚本应打印出所有从未登录过的用户,并对其进行排序。我设法让所有输入工作,但是,在打印输出时遇到问题。循环如下:
for user in $(lastlog | grep -i 'never' | awk '{print $1}'); do
grep $user /etc/passwd | awk -F ':' '{print $1, $3}'
done
当然,这个循环不会对输出进行排序,但是,由于我对shell和shell脚本的理解有限,它应该只是放一个'|排序'在第一个'awk'{print $ 1}'之后。我的问题是这个循环的输出打印每个用户至少两次,在某些情况下,打印四次。为什么这样,我该如何解决?
答案 0 :(得分:2)
好吧,让我们尝试调试它:
for user in $(lastlog | grep -i 'never' | awk '{print $1}'); do
echo "The user '$user' matches these lines:"
grep $user /etc/passwd | awk -F ':' '{print $1, $3}'
echo
done
输出:
The user 'daemon' matches these lines:
daemon 1
colord 112
The user 'bin' matches these lines:
root 0
daemon 1
bin 2
sys 3
sync 4
games 5
man 6
(...)
事实上,colord
的条目确实包含daemon
:
colord:x:112:120:colord colour management daemon,,,:/var/lib/colord:/bin/false
^-- Here
games
条目与bin
匹配:
games:x:5:60:games:/usr/games:/usr/sbin/nologin
^-- Here
因此,不是在任何地方匹配用户名字符串,我们只想将它从行的开头到第一个冒号匹配:
for user in $(lastlog | grep -i 'never' | awk '{print $1}'); do
echo "The user '$user' matches these lines:"
grep "^$user:" /etc/passwd | awk -F ':' '{print $1, $3}'
echo
done
现在每个条目只显示它应该的单独条目,所以你可以移除回声并继续前进。
如果您对精细和抛光感兴趣,这里有一个替代解决方案,可以跨语言设置,奇怪的用户名,网络身份验证,大型列表等高效工作:
LC_ALL=C lastlog |
awk -F ' ' '/Never logged in/ {printf "%s\0", $1}' |
xargs -0 getent passwd |
awk -F : '{print $1,$3}' |
sort
答案 1 :(得分:2)
试想一下名为sh
的用户会发生什么。 grep sh
匹配的用户数量是多少?可能所有这些,因为每个都在shell
字段中使用了一些shell。
你应该考虑
awk -F ':' '$1 == "'"$user"'" {print $1, $3}' /etc/passwd
或用户的awk变量:
awk -F ':' -vuser="$user" '$1 == user {print $1, $3}' /etc/passwd
答案 2 :(得分:0)
你的grep将匹配多行,(man将匹配manuel和norman等)将它锚定到行的开头并添加一个踪迹:。
grep "^${user}:" /etc/passwd | awk -F ':' '{print $1, $3}'
更好的选择可能是忘记完全grepping / etc / passwd并使用id
命令获取用户ID:
id=$(id -u "${user}" 2>/dev/null) && printf "%s %d\n" "${user}" "${id}"
如果id命令失败,则不打印任何内容,或者可以将其修改为:
id=$(id -u "${user}" 2>/dev/null)
printf "%s %s\n" "${user}" "${id:-(User not found)}"
在gnu linux中我很确定找不到找到的用户id是不可能的,因为lastlog只会报告现有用户,所以第二个例子可能毫无意义。