通过 dscl 查找低于 500 的可用 ID

通过 dscl 查找低于 500 的可用 ID

我们如何围绕 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。对于您的情况,只需使用0499,如下所示。如果函数找不到任何空位,则返回一个空字符串,因此您需要在使用echoed 值之前检查这一点(也如下所示)。

我意识到这不使用 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_existsuser_exists_dscldsclid

相关内容