Как извлечь наибольшее значение UID из /etc/passwd?

Я хочу предсказать следующий UID перед созданием нового пользователя. Поскольку новый примет самое большое значение идентификатора и добавит к нему 1, я подумал о следующем сценарии:

biggestID=0
cat /etc/passwd | while read line
do
if test [$(echo $line | cut -d: -f3) > $biggestID]
then
biggestID=$(echo $line | cut -d: -f3)
fi
echo $biggestID
done
let biggestID=$biggestID+1
echo $biggestID

В результате я получаю 1, Это смутило меня, и я подумал, что проблема с циклом, поэтому я добавил echo $biggestID ниже fi чтобы проверить, действительно ли меняется его значение, и выясняется, что с циклом проблем нет, так как я получил много значений до 1000. Так почему biggestIDвозвращаемое значение 0 после цикла?

3 ответа

Решение

Это из-за этой строки:

cat /etc/passwd | while read line

Это работает while цикл в под-оболочке, так biggestID устанавливается в вложенной оболочке, а не в родительской оболочке.

Если вы измените ваш цикл следующим образом, он будет работать:

while read line
...
done < /etc/passwd

Это потому что while цикл теперь выполняется в той же оболочке, что и основной скрипт, и вы просто перенаправляете содержимое /etc/passwd в петлю.

Вы можете изменить программу на что-то вроде этого:

newID=$(( $(cut -d: -f3 /etc/passwd | sort -n | tail -n 1 ) +1 ))
echo $newID
  • cut -d: -f3 /etc/passwd| sort -n | tail -n 1 извлекает наибольшее значение из третьего поля в passwd
  • $( ... ) обозначает результат команды, здесь самый большой идентификатор
  • newID=$(( ... + 1 )) добавить 1 и сохранить результат в newID

С помощью awk вы делаете все расчеты в одной программе:

awk -F: 'BEGIN {maxuid=0;} {if ($3 > maxuid) maxuid=$3;} END {print maxuid+1;}' /etc/passwd

Если вы не хотите начинать с awk, оставьте отзыв о вашем коде.

biggestID=0
# Do not use cat .. but while .. do .. done < input (do not open subshell)
# Use read -r line (so line is taken literally)
cat /etc/passwd | while read line
do
   # Do not calculate the uid twice (in test and assignment) but store in var
   # uid=$(cut -d: -f3 <<< "${line}")
   # Use space after "[" and before "]"
   # test is not needed, if [ .. ] already implicit says so
   # (I only use test for onelines like "test -f file || errorfunction")
   if test [$(echo $line | cut -d: -f3) > $biggestID]
   then
      biggestID=$(echo $line | cut -d: -f3)
   fi
   # Next line only for debugging
   echo $biggestID
done
# You can use (( biggestID = biggestID + 1 ))
# or (when adding one)
# (( ++biggestID ))
let biggestID=$biggestID+1
# Use double quotes to get the contents literally, and curly brackets
# for a nice style (nothing strang will happen if you add _happy right after the var)
# echo "${biggestID}" 
echo $biggestID
Другие вопросы по тегам