I have the following in a file Output.dat. I need to extract the value between dn: uid= and ,ou=
dn: uid=user1,ou=Active,ou=Member,dc=domain,dc=org dn: <a href="https://getridbug.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="592c303d642c2a3c2b6b19383b3a773a3634">[email protected]</a>,ou=Active,ou=Member,dc=domain,dc=org dn: uid=usertest,ou=Active,ou=Member,dc=domain,dc=org dn: uid=abc1,ou=Active,ou=Member,dc=domain,dc=org
- I tried using
sed -e '/dn: uid=/,/,ou=/p' output.dat but
it returns complete line instead of value.
- When tried to use
sed -e '/dn: uid=/,/,ou=/1/p' output.dat
then got the following error:
sed: -e expression #1, char 18: unknown command: `'
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
If you have a version of GNU grep with PCRE (-P) support, then assuming you mean the first occurrence of ,ou
grep -oP '(?<=dn: uid=).+?(?=,ou=)' file
If you want to match up to the second ,ou you can remove the non-greedy ? modifier
grep -oP '(?<=dn: uid=).+(?=,ou=)' file
The expressions in parentheses are zero-length assertions (aka lookarounds) meaning that they form part of the match, but are not returned as part of the result. You could do the same thing natively in perl e.g.
perl -ne 'print "$1n" if /(?<=dn: uid=)(.+?)(?=,ou=)/' file
It’s possible to do something similar in sed, using regular (non zero-length) grouping e.g. (for GNU sed – other varieties may need additional escaping)
sed -rn 's/(.*dn: uid=)([^,]+)(,ou=.*)/2/p' file
or simplifying slightly
sed -rn 's/.*dn: uid=([^,]+),ou=.*/1/p' file
Note the [^,] is a bit of a hack here, since sed doesn’t have a true non-greedy match option.
Afterthought: although it’s not exactly what you asked, it looks like what you actually want to do is read comma-separated name=value pairs from a file, and then further split the value of the first field from its name. You could achieve that in many ways – including
awk -F, '{sub(".*=","",$1); print $1}' file
or a pure-bash solution such as
while IFS=, read -r a b c d; do printf '%sn' "${a#*=}"; done < file
Method 2
This is a good job for awk. You can split the string instead of attempting to use a regex. Here is a solution:
$ awk -F= '{ split($2,arr,","); print arr[1] }' test.txt
user1
<a href="https://getridbug.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="bfcaccdacd8dffdedddc91dcd0d2">[email protected]</a>
usertest
abc1
Method 3
With sed:
sed 's/[^=]*=([^,]+),.*/1/' file
This assumes the uid= will have the first occurrence of = on the line and it assumes that you want to stop at the first ,ou= instance on the line.
Explanation
This looks for any number of non = characters ([^=]*) followed by = then matches and saves as many non-commas as it can find ( ([^,]+) ) followed by a comma and the rest of the line (,.*). This means it will replace everything up to and including the first = and after the first comma with whatever non-comma characters it finds after the first = on the line.
Method 4
Some more choices, in order of length:
-
GNU
grepwith PCREsgrep -oP 'uid=K[^,]+' file
The
Kdiscards everything matched up to that point, which combined with the-oswitch will causegrepto print only the longest stretch of non,characters that comes after theuid=. -
awkawk -F'[=,]' '{print $2}' file-F'[=,]sets the field separator to be either=or,so the 2nd field is the user name. -
sedsed -r 's/.{8}([^,]*).*/1/' fileThat will match the first 7 characters (
.{7})=, capture the longest stretch of non-,as1and replace the whole line with1. -
perlperl -pe 's/.+?=([^,]+).*/$1/' file
The
-pemeans “print every line after applying the script given by -e”. Thes///is the substitution operator and the regular expression looks for the 1st (.+?, the?makes it match the shortest possible string)=and then captures the longest stretch of non-,characters after that. Thes///replaces what was matched with what was captured (what was inside the parentheses). -
cutcut -d'=' -f 2 file | cut -d ',' -f 1
The
-dsets the delimiter to=so the 2nd (-f 2) field isusername,ou. The secondcutuses,as delimiter and prints the username alone.
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0