The Problem
As a programmer I am always searching for elegant ways how to accomplish certain things. One of the last tasks was to parse the /etc/passwd file of a linux box. Of course there are multiple ways how to do this, but the Java8 way seems to be a cool solution.
The Solution
The Program consists of two classes. The first one is the ‘PwdUser’ class which represents one single entry in the passwd file:
public class PwdUser { public String userid; public String password; public Integer uid; public Integer gid; public String fullname; public String homedir; public String shell; public PwdUser(String pwdline) { String[] values = pwdline.split(":"); if(values.length != 7) { throw new IllegalArgumentException("Line must have 7 fields"); } this.userid = values[0]; this.password = values[1]; this.uid= Integer.parseInt(values[2]); this.gid= Integer.parseInt(values[3]); this.fullname = values[4]; this.homedir = values[5]; this.shell = values[6]; } }
As you see - you can call the constructor with a full line from the passwd file ant the line is slitted up into separate variables. (Errorchecking could be better - but this example is more for educational purposes)
The second class is the main class:
import java.nio.file.Files; import java.nio.file.Paths; import java.util.ArrayList; import java.util.stream.Collectors; import java.util.stream.Stream; public class Test { public static void main(String[] args) { // Read the file try (Stream<String> stream = Files.lines(Paths.get("/etc/passwd"))) { // Yeah - Java8 read, filter and instantiante on one line of code ! ArrayList<PwdUser> users = stream.map(PwdUser::new) .filter(u -> !u.shell.equals("/bin/false")) .filter(u -> !u.shell.equals("/usr/sbin/nologin")) .collect(Collectors.toCollection(ArrayList::new)); // Do something with your users ... for (PwdUser u : users) { System.out.println(u.userid); } } catch (Exception e) { e.printStackTrace(); } } }
This is where the magic happens:
- The file is opened within the try - which means that the JVM closes it automatically (try-with-ressources)
- Within the try block we have the stream of the file which is processed as follows:
- Create a PwdUser for every line in the file
- Remove all objects which are not allowed to log into the system (This is indicated by a shell does not equal to
/bin/falseand also not to/usr/sbin/nologin - Grab the remeaning ones an put them into a new ArrayList
- Iterate over the ArrayList and process the objects
Neat - isn’t it ?