2

I need to compare the user list (/etc/passwd) to a .csv file of account and get the account from /etc/passwd that are not in my csv file.

/etc/passwd shows:

root:x:0:0:root:/root:/bin/bash
albert:x:521:521:auto:/home/albert:/bin/bash
alfred:x:521:521:auto:/home/alfred:/bin/bash

.csv file shows:

albert,abc123

Expected output is:

root
alfred

I tried for 2 days with awk and grep but the result are not what I need..

2 Answers 2

4

A combination of grep, tr, cut and process substitution:

cut -d: -f1 /etc/passwd | grep -xvFf <(tr ',' '\n'  < file.csv)

The cut command gets the usernames from /etc/passwd (the first :-delimited field).

Then, the tr command converts your CSV fields to one username per line.

The grep command then looks for entire lines (-x) which don't match (-v) any fixed patterns (-F) from a file containing patterns, one per line (-f). We use process substitution (<()) to use tr's output for these patterns.

3
  • Thanks for that clear and smooth answer. Works like a charm !
    – Alexander
    Feb 17, 2016 at 1:32
  • What could I do if I want to keep the same logic, but the expected output is: root:x:0:0:root:/root:/bin/bash alfred:x:521:521:auto:/home/alfred:/bin/bash (I would like to keep the whole line, because I have verification to do with the other information)
    – Alexander
    Feb 17, 2016 at 4:19
  • grep -wvFf <(tr ',' '\n' < file.csv) /etc/passwd, I suppose.
    – muru
    Feb 17, 2016 at 4:55
2

Not as smooth as muru's solution, but another way using comm, tr and cut and sort:

comm -13 <(<file tr ',' '\n' | sort) <(cut -d ':' -f 1 /etc/passwd | sort)
  • comm -13 <(<file tr ',' '\n' | sort) <(cut -d ':' -f 1 /etc/passwd | sort): compares the lines in the output of <file tr ',' '\n' | sort and cut -d ':' -f 1 /etc/passwd | sort and prints only the lines unique to cut -d ':' -f 1 /etc/passwd | sort;
  • <file tr ',' '\n' | sort: reads STDIN from file, translates commas to newlines and sorts the output file;
  • cut -d ':' -f 1 /etc/passwd | sort: prints the first colon-separated field of each line in /etc/passwd and sorts the output file;

And another way using combine (in the moreutils package: sudo add-apt-repository universe && sudo apt-get update && sudo apt-get install moreutils), which allows to save a couple of sort commands (though most likely combine sorts the files internally anyway):

combine <(cut -d ':' -f 1 /etc/passwd) NOT <(<file tr ',' '\n')
  • combine <(cut -d ':' -f 1 /etc/passwd) NOT <(<file tr ',' '\n'): compares the lines in the output of cut -d ':' -f 1 /etc/passwd and <file tr ',' '\n' and prints only the lines unique to cut -d ':' -f 1 /etc/passwd;
  • <file tr ',' '\n': reads STDIN from file and translates commas to newlines;
  • cut -d ':' -f 1 /etc/passwd: prints the first colon-separated field of each line in /etc/passwd;
4
  • Thanks you ! Also work like a charm and I just learned the 'comm' :)
    – Alexander
    Feb 17, 2016 at 1:34
  • ASking the same question I asked to Muru, if I want to output all the line of etc/shadow instead of the cut, how could I do with this command ?
    – Alexander
    Feb 18, 2016 at 0:13
  • @Alexander The solution muru gave you already is actually the best one I can think of, it should take care of almost all edge cases: askubuntu.com/questions/735576/….
    – kos
    Feb 18, 2016 at 9:59
  • Thanks for all the help, I didn't notice his answer.
    – Alexander
    Feb 18, 2016 at 14:38

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .