2

I want to predict the next UID before creating a new user. Since the new one will take the biggest ID value yet and adds 1 to it, I thought of the following script:

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

As a result I get 1. This confused me and I thought that the problem is with the loop, so I added the echo $biggestID just below fi to check if its value is truly changing and it turns out there is no problem with the loop as I got many values up to 1000. So why is biggestID's value returning to 0 after the loop?

das-g
  • 9,718
  • 4
  • 38
  • 80
engineering student
  • 233
  • 1
  • 3
  • 14
  • Possible duplicate of [How can I add numbers in a bash script](http://stackoverflow.com/questions/6348902/how-can-i-add-numbers-in-a-bash-script) – tddmonkey Feb 28 '16 at 12:36
  • Prehaps you have a line like `nobody:x:65534:65533:nobody:/var/lib/nobody:/bin/bash` and want to skip this one. – Walter A Feb 28 '16 at 13:46

3 Answers3

2

It's because of this line:

cat /etc/passwd | while read line

That runs the while loop in a sub-shell, so biggestID is being set in the sub-shell, not in the parent shell.

If you change your loop to the following, it will work:

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

This is because the while loop is now running in the same shell as the main script, and you're just redirecting the contents of /etc/passwd into the loop.

e.dan
  • 7,275
  • 1
  • 26
  • 29
1

You could change the program to something like this:

newID=$(( $(cut -d: -f3 /etc/passwd | sort -n | tail -n 1 ) +1 ))
echo $newID
  • cut -d: -f3 /etc/passwd| sort -n | tail -n 1 fetches the biggest value from the third field in passwd
  • $( ... ) stands for the result of the command, here the biggest id
  • newID=$(( ... + 1 )) add 1 and stores the result in newID
Jens
  • 69,818
  • 15
  • 125
  • 179
Lars Fischer
  • 9,135
  • 3
  • 26
  • 35
1

With awk you do all calculations in one program:

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

When you not want to start with awk yet, some feedback on your code.

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
Jens
  • 69,818
  • 15
  • 125
  • 179
Walter A
  • 19,067
  • 2
  • 23
  • 43