I'm trying to take a substring of a string read from a file and put it in a variable. The string will look something like this:
"dn: uid=myUid,ou=People,dc=mydomain,dc=furtherdomain"
The following succeeds but is too clunky for me:
#!/bin/bash
while IFS= read -r line; do
if [[ "$line" == *"uid="* ]]; then
uid1=${line#*uid=}
uid2=${uid1%,*}
uid3=${uid2%,*}
uid=${uid3%,*}
echo "$uid"
fi
done <<< "dn: uid=myUid,ou=People,dc=mydomain,dc=furtherdomain"
Assuming arguments are submitted in this form:
dn: uid=myUid,ou=People,dc=mydomain,dc=furtherdomain
or even
dn: ou=People,uid=myUid,dc=mydomain,dc=furtherdomain
dn: ou=People,dc=furtherdomain,uid=myUid,dc=mydomain
dn: uid=myUid,ou=People,dc=mydomain,dc=furtherdomain,cn=commonname
dn: fn=Full Name,uid=myUid,ou=People,dc=mydomain,dc=furtherdomain
(Yes, the way I present her will support spaces! ;-)
uid
) as requestedSomething like:
#!/bin/bash
IdLine="$*"
while IFS== read -d, name val;do
case $name in
uid ) uid=$val ;;
esac
done < <(printf %s "${IdLine#*: }")
Or, inspired by anubhava's answer, but able to find uid=
even if not at 1st position.
shopt -s extglob
line='dn: fn=Full Name,uid=myUid,ou=People,dc=mydomain,dc=furtherdomain'
uid="${line//+(*uid=|,*)}"
Under bash you coud use associative array to index all values:
Warning: There are some field repetition! For sample dc
are present two time!! For this I use a coma ,
to separate values into same field.
#!/bin/bash
IdLine="$*"
declare -A IdArray='()'
while IFS== read -d, name val;do
if [[ -v IdArray[$name] ]]; then
IdArray[$name]+=",$val"
else
IdArray[$name]="$val"
fi
done < <(printf %s "${IdLine#*: }")
Then
echo ${IdArray[uid]}
You variable will look like:
declare -p IdArray
declare -A IdArray=([dc]="mydomain,furtherdomain" [ou]="People" [uid]="myUid" )
or
declare -A IdArray=([dc]="mydomain,furtherdomain" [fn]="Full Name" [ou]="People" [uid]="myUid" )
parseDnLine() {
local -n _aArray=$1
shift
local _idLine="$*" _nam _val
while IFS== read -d, _nam _val; do
if [[ -v _aArray[$_nam] ]]; then
_aArray[$_nam]+=,${_val%$'\n'}
else
_aArray[$_nam]=${_val%$'\n'}
fi
done <<<"${_idLine#*: },"
}
Then prepare 4 associative array:
declare -A test{1..4} # Require to declare Associative Array outside of function
parseDnLine test1 dn: ou=People,uid=myUid,dc=mydomain,dc=furtherdomain
parseDnLine test2 dn: ou=People,dc=furtherdomain,uid=myUid,dc=mydomain
line='dn: uid=myUid,ou=People,dc=mydomain,dc=furtherdomain,cn=commonname'
parseDnLine test3 "$line"
line="dn: fn=Full Name,uid=myUid,ou=People,dc=mydomain,dc=furtherdomain"
parseDnLine test4 $line
declare -p test{1..4}
Will produce something like:
declare -A test1=([dc]="mydomain,furtherdomain" [ou]="People" [uid]="myUid" )
declare -A test2=([dc]="furtherdomain,mydomain" [ou]="People" [uid]="myUid" )
declare -A test3=([dc]="mydomain,furtherdomain" [cn]="commonname" [ou]="People" [uid]="myUid" )
declare -A test4=([dc]="mydomain,furtherdomain" [fn]="Full Name" [ou]="People" [uid]="myUid" )
Then, of course:
echo ${test1[uid]}
myUid
x509
SSL Cert's DN: subject or issuerWith some little edits, this function become suitable for parsing DN lines from X509 certificate files, by using
openssl x509 -noout -subject
to print subject DN.openssl x509 -noout -issuer
to print issuer DN.parseDnLine() {
local -n _aArray=$1
shift
local _idLine _nam _val _unquot
IFS=':=' read -r _ _idLine <<<"$*"
while IFS='=' read -rd, _nam _val; do
read -r _nam <<<"$_nam"
read -r _val <<<"${_val%$'\n'}"
_unquot=${_val//\"}
while (( ( ${#_val} - ${#_unquot} ) % 2)); do
read -rd, _unquot
_val+=", $_unquot"
_unquot=${_val//\"}
done
printf -v _unquot '%b' "${_unquot//\\/\\x}"
if [[ -v _aArray[$_nam] ]]; then
_aArray["$_nam"]+=,$_unquot
else
_aArray["$_nam"]=$_unquot
fi
done <<<"$_idLine,"
}
Then
declare -A 'test=()'
parseDnLine test dn: uid=myUid,ou=People,dc=mydomain,dc=furtherdomain,cn=commonname
declare -p test
Still work:
declare -A test=([dc]="mydomain,furtherdomain" [cn]="commonname" [ou]="People" [uid]="myUid" )
From my local /etc/ssl/certs
directory:
declare -A 'test=()'
parseDnLine test $(
openssl x509 -in /etc/ssl/certs/Go_Daddy_Root_Certificate_Authority_-_G2.pem \
-noout -subject)
declare -p test
declare -A test=([O]="GoDaddy.com, Inc." [L]="Scottsdale" [C]="US" [ST]="Arizona" [CN]="Go Daddy Root Certificate Authority - G2" )
Note the quote in [O]="GoDaddy.com, Inc."
.
And from any website:
declare -A 'test=()'
parseDnLine test $(
openssl x509 -noout -subject < <(
openssl s_client <<<$'HEAD / HTTP/1.0\r\n\r' 2>&1 paypal.com:443
))
declare -p test
declare -A test=([jurisdictionC]="US" [O]="PayPal, Inc." [L]="San Jose" [C]="US" [jurisdictionST]="Delaware" [businessCategory]="Private Organization" [ST]="California" [serialNumber]="3014267" [CN]="paypal.com" )
Then, using dunpArray
from Looping over arrays, printing both index and value:
dumpArray test
jurisdictionC : US
O : PayPal, Inc.
L : San Jose
C : US
jurisdictionST : Delaware
businessCategory: Private Organization
ST : California
serialNumber : 3014267
CN : paypal.com
Finally print both issuer and subject in one operation:
while read -r line; do
certyp=${line%%=*};
echo "-- ${certyp^^} --";
declare -A 'test=()';
parseDnLine test "$line";
dumpArray test;
done < <(openssl x509 -noout -subject -issuer < <(
openssl s_client google.com:443 <<<$'HEAD / HTTP/1.0\r\n\r' 2>&1))
-- SUBJECT --
CN: *.google.com
-- ISSUER --
O : Google Trust Services
C : US
CN: WR2