我们如何围绕 dscl 编写一个脚本来循环遍历当前列出的正在使用的 ID,然后吐出 500 以下第一个尚未使用的 ID?
更新 # 1 (2013 年 2 月 17 日)
我发现了一些非常有用的脚本http://wiki.awkwardtv.org/wiki/Manage_users_and_groups_scripts我可以将其缩小到可以获得高于给定数字的第一个可用 ID 的程度,但我仍然没有办法编写脚本来停止查看超过某个上限(例如 500)的数字。
#!/bin/sh
continue="no"
number_used="dontknow"
fnumber=300
user_id=0
until [ $continue = "yes" ] ; do
if [ `dscl . -list /Users UniqueID | awk '{print $2, "\t", $1}' | sort -ug | grep -c "$fnumber"` -gt 0 ] ; then
number_used=true
else
number_used=false
fi
if [ $number_used = "true" ] ; then
fnumber=`expr $fnumber + 1`
else
user_id="$fnumber"
continue="yes"
fi
done;
echo "Next available user_id: $user_id"
更新 # 2 (2013 年 2 月 17 日)
我想我可以反向操作,但如果从 500 到 0 的每个用户 ID 都被占用了怎么办?我仍然需要设置一个下限,以摆脱混乱的负面 ID 情况。
#!/bin/sh
continue="no"
number_used="dontknow"
fnumber_work_backwards_from=500
fnumber=$fnumber_work_backwards_from
user_id=0
until [ $continue = "yes" ] ; do
if [ `dscl . -list /Users UniqueID | awk '{print $2, "\t", $1}' | sort -ug | grep -c "$fnumber"` -gt 0 ] ; then
number_used=true
else
number_used=false
fi
if [ $number_used = "true" ] ; then
fnumber=`expr $fnumber - 1`
else
user_id="$fnumber"
continue="yes"
fi
done;
echo "First available user_id which is closest to and lower than $fnumber_work_backwards_from: $user_id"
答案1
例如,可以使用 Ruby 来完成此操作,它比您可能找到的任何 Bash 脚本都要简洁得多。
dscl . -list /Users UniqueID | awk '{print $2}' |
ruby -e 'puts ((0..500).to_a - STDIN.readlines.map(&:to_i)).first'
我们只需从另一个由 0 到 500 的数字组成的数组中减去实际的 ID(作为数组)。这为我们提供了数组中所有未使用的 ID,并从中取出第一个,因为它已经排序好了。
答案2
这应该可以找到您需要的内容。下面的函数find_next_userid
将在两个数字之间进行搜索,以找到第一个未使用的用户 ID。对于您的情况,只需使用0
和499
,如下所示。如果函数找不到任何空位,则返回一个空字符串,因此您需要在使用echo
ed 值之前检查这一点(也如下所示)。
我意识到这不使用 dscl,但这应该可以工作并且更易于移植。[更新:添加了使用 dscl 的版本。]
从技术上讲,我正在使用 bash,因此我注意到了这一点;我不确定它是否可以在 sh 中工作。
在 OS X 10.9.4 上测试。
#!/bin/bash
user_exists()
{
username=$1
if id -u $username >/dev/null 2>&1; then
return 0
else
return -1
fi
}
user_exists_dscl()
{
username=$1
user_found=`dscl . -search /Users UniqueID $username | awk 'FNR == 2 {print $1}'`
if [ "${user_found}" != "" ] ; then
return 0
else
return -1
fi
}
find_next_userid()
{
low=$1
hi=$2
for curr in `seq $low $hi`;
do
if ! (user_exists $curr) ; then
echo $curr
break
fi
done
echo ""
}
FIRST_UNUSED_USERID=`find_next_userid 0 499`
if [ "$FIRST_UNUSED_USERID" != "" ]; then
echo "Do your stuff here!"
else
echo "No unused userid found!"
fi
编辑:忘记包含user_exists()
。更新后注意到此解决方案不使用 dscl 但仍然有效。我想我可能很快就会有一个使用 dscl 的解决方案。
编辑2:添加了。如果您确实需要使用而不是,则用 替换对user_exists_dscl
的调用。user_exists
user_exists_dscl
dscl
id