1186 lines
31 KiB
Bash
1186 lines
31 KiB
Bash
##@cooked comments # -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
|
# outils pour gérer des fichiers .ldif
|
|
##@cooked nocomments
|
|
##@require base
|
|
##@require awk
|
|
uprovide ldif
|
|
urequire base awk
|
|
|
|
function def_match_attr() {
|
|
local attr first script
|
|
script="function fix_attr(attr) {
|
|
gsub(/:+$/, \"\", attr)
|
|
return attr \":\"
|
|
}
|
|
function norm_attr(attr) {
|
|
return tolower(attr)
|
|
}
|
|
function match_attr(attr) {
|
|
attr = tolower(attr)
|
|
if ("
|
|
if [ -n "$*" ]; then
|
|
first=1
|
|
for attr in "$@"; do
|
|
attr="${attr%%:*}"
|
|
if [ -n "$first" ]; then
|
|
first=
|
|
else
|
|
script="$script || "
|
|
fi
|
|
script="${script}attr == tolower(\"$attr:\") || attr == tolower(\"$attr::\")"
|
|
done
|
|
else
|
|
script="${script}1"
|
|
fi
|
|
script="$script) return 1
|
|
else return 0
|
|
}"
|
|
echo "$script"
|
|
}
|
|
|
|
function def_match_value() {
|
|
local pattern first script
|
|
script="function match_value(line) {
|
|
sub(/^[^:]+::?[ ]+/, \"\", line)
|
|
if ("
|
|
if [ -n "$*" ]; then
|
|
first=1
|
|
for pattern in "$@"; do
|
|
pattern="${pattern//\\\\/\\\\}"
|
|
if [ -n "$first" ]; then
|
|
first=
|
|
else
|
|
script="$script || "
|
|
fi
|
|
script="${script}line ~ /$pattern/"
|
|
done
|
|
else
|
|
script="${script}1"
|
|
fi
|
|
script="$script) return 1
|
|
else return 0
|
|
}"
|
|
echo "$script"
|
|
}
|
|
|
|
function uncut_lines() {
|
|
# reformer les lignes qui sont coupées
|
|
awk '
|
|
BEGIN {
|
|
inline = 0
|
|
}
|
|
|
|
{
|
|
if (!inline) {
|
|
line = $0
|
|
inline = 1
|
|
} else {
|
|
if ($0 ~ /^ /) {
|
|
line = line substr($0, 2)
|
|
} else {
|
|
print line
|
|
inline = 0
|
|
|
|
line = $0
|
|
inline = 1
|
|
}
|
|
}
|
|
}
|
|
|
|
END {
|
|
if (inline) print line
|
|
}
|
|
'
|
|
}
|
|
|
|
function cut_lines() {
|
|
# couper les lignes trop longues
|
|
awk '
|
|
{
|
|
if (length($0) > 78) {
|
|
prefix = ""
|
|
maxlen = 78
|
|
line = $0
|
|
while (length(line) > maxlen) {
|
|
print prefix substr(line, 1, maxlen)
|
|
line = substr(line, maxlen + 1)
|
|
prefix = " "
|
|
maxlen = 77
|
|
}
|
|
if (line != "") print prefix line
|
|
} else {
|
|
print
|
|
}
|
|
}
|
|
'
|
|
}
|
|
|
|
function ensure_complete_objects() {
|
|
# S'assurer que le ldif ne contient que des objets complets (éliminant ainsi
|
|
# les groupes ayant seulement dn:)
|
|
awk '
|
|
function dump_ldif() {
|
|
if (attrs) {
|
|
print ldif
|
|
print ""
|
|
}
|
|
ldif = ""
|
|
attrs = 0
|
|
}
|
|
|
|
/^dn:/ {
|
|
dump_ldif()
|
|
ldif = $0
|
|
next
|
|
}
|
|
$0 != "" {
|
|
ldif = ldif "\n" $0
|
|
attrs = 1
|
|
}
|
|
|
|
END {
|
|
dump_ldif()
|
|
}
|
|
'
|
|
}
|
|
|
|
function delete_marked_objects() {
|
|
# Supprimer les objets marqués avec --DELETE--:
|
|
awk '
|
|
BEGIN { keep = 0 }
|
|
function dump_ldif() {
|
|
if (keep) {
|
|
print ldif
|
|
print ""
|
|
}
|
|
ldif = ""
|
|
keep = 1
|
|
}
|
|
/^dn:/ {
|
|
dump_ldif()
|
|
ldif = $0
|
|
next
|
|
}
|
|
/^--DELETE--:/ { keep = 0 }
|
|
$0 != "" { ldif = ldif "\n" $0 }
|
|
END { dump_ldif() }
|
|
'
|
|
}
|
|
|
|
function tl_addattr() {
|
|
awk '
|
|
/^dn:/ {
|
|
lastattr = ""
|
|
dn = $0
|
|
next
|
|
}
|
|
|
|
{
|
|
attr = $1
|
|
if (attr != "") {
|
|
if (dn != "") {
|
|
print dn
|
|
print "changetype: add"
|
|
dn = ""
|
|
}
|
|
sub(/:+$/, "", attr)
|
|
}
|
|
print
|
|
lastattr = attr
|
|
}
|
|
'
|
|
}
|
|
|
|
function tl_modifyattr() {
|
|
local modtype="$1"
|
|
awkrun modtype="$modtype" '
|
|
/^dn:/ {
|
|
lastattr = ""
|
|
dn = $0
|
|
next
|
|
}
|
|
|
|
{
|
|
attr = $1
|
|
if (attr == "") {
|
|
if (lastattr != "") {
|
|
print "-"
|
|
}
|
|
} else {
|
|
if (dn != "") {
|
|
print dn
|
|
print "changetype: modify"
|
|
dn = ""
|
|
}
|
|
sub(/:+$/, "", attr)
|
|
if (lastattr != attr) {
|
|
if (lastattr != "") {
|
|
print "-"
|
|
}
|
|
print modtype ": " attr
|
|
}
|
|
}
|
|
print
|
|
lastattr = attr
|
|
}
|
|
'
|
|
}
|
|
|
|
function tl_deleteattr() {
|
|
awk '
|
|
/^dn:/ {
|
|
lastattr = ""
|
|
dn = $0
|
|
next
|
|
}
|
|
|
|
{
|
|
attr = $1
|
|
if (attr == "") {
|
|
if (lastattr != "") {
|
|
print "-"
|
|
print
|
|
}
|
|
} else {
|
|
if (dn != "") {
|
|
print dn
|
|
print "changetype: modify"
|
|
dn = ""
|
|
}
|
|
sub(/:+$/, "", attr)
|
|
if (lastattr != attr) {
|
|
if (lastattr != "") {
|
|
print "-"
|
|
}
|
|
print "delete: " attr
|
|
}
|
|
}
|
|
lastattr = attr
|
|
}
|
|
'
|
|
}
|
|
|
|
function tl_deleteentry() {
|
|
awk '
|
|
/^dn:/ {
|
|
dn = $0
|
|
print dn
|
|
print "changetype: delete"
|
|
print ""
|
|
next
|
|
}
|
|
'
|
|
}
|
|
|
|
function tl_touchentry() {
|
|
awk '
|
|
/^dn:/ {
|
|
dn = $0
|
|
print dn
|
|
print "changetype: modify"
|
|
print ""
|
|
next
|
|
}
|
|
'
|
|
}
|
|
|
|
function tl_keepattr() {
|
|
local match_attr="$1"
|
|
awk "$match_attr"'
|
|
$0 == "" || match_attr($1) {
|
|
print
|
|
}
|
|
'
|
|
}
|
|
|
|
function tl_keepval() {
|
|
local match_attr="$1" match_value="$2"
|
|
awk "$match_attr
|
|
$match_value"'
|
|
match_attr($1) {
|
|
if (match_value($0)) {
|
|
print
|
|
}
|
|
next
|
|
}
|
|
{ print }
|
|
'
|
|
}
|
|
|
|
function tl_excludeattr() {
|
|
local match_attr="$1"
|
|
awk "$match_attr"'
|
|
! match_attr($1) {
|
|
print
|
|
}
|
|
'
|
|
}
|
|
|
|
function tl_excludeval() {
|
|
local match_attr="$1" match_value="$2"
|
|
awk "$match_attr
|
|
$match_value"'
|
|
match_attr($1) {
|
|
if (! match_value($0)) {
|
|
print
|
|
}
|
|
next
|
|
}
|
|
{ print }
|
|
'
|
|
}
|
|
|
|
function tl_keepvalentry() {
|
|
local match_attr="$1" match_value="$2"
|
|
awk "$match_attr
|
|
$match_value"'
|
|
function keep_maybe() {
|
|
if (! keep) print "--DELETE--: yes"
|
|
done = 1
|
|
}
|
|
/^dn:/ {
|
|
keep = 0
|
|
done = 0
|
|
}
|
|
match_attr($1) {
|
|
if (match_value($0)) keep = 1
|
|
}
|
|
$0 == "" { keep_maybe() }
|
|
{ print }
|
|
END {
|
|
if (! done) keep_maybe()
|
|
}
|
|
'
|
|
}
|
|
|
|
function tl_excludevalentry() {
|
|
local match_attr="$1" match_value="$2"
|
|
awk "$match_attr
|
|
$match_value"'
|
|
function keep_maybe() {
|
|
if (! keep) print "--DELETE--: yes"
|
|
done = 1
|
|
}
|
|
/^dn:/ {
|
|
keep = 1
|
|
done = 0
|
|
}
|
|
match_attr($1) {
|
|
if (match_value($0)) keep = 0
|
|
}
|
|
$0 == "" { keep_maybe() }
|
|
{ print }
|
|
END {
|
|
if (! done) keep_maybe()
|
|
}
|
|
'
|
|
}
|
|
|
|
function tl_replval() {
|
|
local script="$1"; shift
|
|
script="$script
|
|
function print_values() {
|
|
for (i = 0; i < count; i++) {
|
|
print attr \" \" values[i]
|
|
}
|
|
}
|
|
BEGIN {
|
|
count=$#"
|
|
local i value
|
|
let i=0
|
|
for value in "$@"; do
|
|
script="$script
|
|
values[$i] = $(quoted_awk "$value")"
|
|
let i=$i+1
|
|
done
|
|
script="$script
|
|
}"'
|
|
match_attr($1) {
|
|
attr = fix_attr($1)
|
|
while (match_attr($1)) {
|
|
if (getline <= 0) break
|
|
}
|
|
print_values()
|
|
}
|
|
{ print }
|
|
'
|
|
awkrun value="$value" "$script"
|
|
}
|
|
|
|
function tl_addval() {
|
|
local attr="$1"; shift
|
|
local script="$(def_match_attr "$attr")
|
|
function print_values() {
|
|
for (i = 0; i < count; i++) {
|
|
print attr \" \" values[i]
|
|
}
|
|
add = 0
|
|
}
|
|
BEGIN {
|
|
add=0
|
|
attr=fix_attr($(quoted_awk "$attr"))
|
|
count=$#"
|
|
local i value
|
|
let i=0
|
|
for value in "$@"; do
|
|
script="$script
|
|
values[$i] = $(quoted_awk "$value")"
|
|
let i=$i+1
|
|
done
|
|
script="$script
|
|
}"'
|
|
/^dn:/ {
|
|
add = 1
|
|
}
|
|
add && match_attr($1) {
|
|
while (match_attr($1)) {
|
|
print
|
|
status = getline
|
|
if (status == 0) {
|
|
# traiter EOF de façon particulière, pour ne pas dupliquer le dernier print
|
|
print_values()
|
|
next
|
|
} else if (status < 0) {
|
|
break
|
|
}
|
|
}
|
|
print_values()
|
|
}
|
|
add && $0 == "" {
|
|
print_values()
|
|
}
|
|
{ print }
|
|
END {
|
|
if (add) print_values()
|
|
}
|
|
'
|
|
awk "$script"
|
|
}
|
|
|
|
function tl_decode() {
|
|
local match_attr="$1"
|
|
awkrun -f "$match_attr"'
|
|
function split_base64(text, result) {
|
|
result = ""
|
|
while (text != "") {
|
|
if (result != "") result = result "\n"
|
|
result = result substr(text, 1, 64)
|
|
text = substr(text, 65)
|
|
}
|
|
return result
|
|
}
|
|
|
|
/^[^:]+:: / && match_attr($1) {
|
|
name = $0; sub(/::.*$/, "", name)
|
|
value = $0; sub(/^[^:]+:: /, "", value)
|
|
|
|
decoded_value = b64decode(value)
|
|
#cmd = "echo '\''" split_base64(value) "'\'' | openssl base64 -d"
|
|
#decoded_value = ""
|
|
#while ((cmd | getline line) > 0) {
|
|
# decoded_value = decoded_value line
|
|
#}
|
|
#close(cmd)
|
|
print name ": " decoded_value
|
|
next
|
|
}
|
|
{ print }
|
|
'
|
|
}
|
|
|
|
function tl_encode() {
|
|
local match_attr="$1"
|
|
awkrun "$match_attr"'
|
|
function quote(text) {
|
|
# remplacer les quotes par le caractere echappement approprie
|
|
gsub('"/'/, \"'\\\\''\""', text)
|
|
return text
|
|
}
|
|
|
|
/^[^:]+: / && match_attr($1) {
|
|
name = $0; sub(/:.*$/, "", name)
|
|
value = $0; sub(/^[^:]+: /, "", value)
|
|
|
|
cmd = "echo '\''" quote(value) "'\'' | openssl base64"
|
|
coded_value = ""
|
|
while ((cmd | getline line) > 0) {
|
|
coded_value = coded_value line
|
|
}
|
|
close(cmd)
|
|
print name ":: " coded_value
|
|
next
|
|
}
|
|
{ print }
|
|
'
|
|
}
|
|
|
|
function tl_format() {
|
|
local args show_headers asep vsep qsep escape shell cmd begincmd endcmd localvars
|
|
show_headers=
|
|
asep=$'\t'
|
|
vsep=';'
|
|
qsep=
|
|
if parse_opts \
|
|
-h,--show-headers show_headers \
|
|
-F: asep= \
|
|
-R: vsep= \
|
|
--quote: qsep= \
|
|
--escape: escape \
|
|
-e shell \
|
|
-c: cmd= \
|
|
--bc: begincmd= \
|
|
--ec: endcmd= \
|
|
-l,--local localvars=1 \
|
|
@ args -- "$@"; then
|
|
set -- "${args[@]}"
|
|
else
|
|
eerror "$args"
|
|
return 1
|
|
fi
|
|
[ -n "$shell" ] && show_headers=1
|
|
|
|
local match_attr="$(def_match_attr "$@")"
|
|
local define_attrs=
|
|
local i=1 attr
|
|
for attr in "$@"; do
|
|
define_attrs="$define_attrs attrs[$i] = \"$attr\"; "
|
|
let i=$i+1
|
|
done
|
|
|
|
awkrun -f show_headers="$show_headers" asep="$asep" vsep="$vsep" qsep="$qsep" escape="$escape" \
|
|
shell="$shell" cmd="$cmd" begincmd="$begincmd" endcmd="$endcmd" localvars="$localvars" '
|
|
function reset_values() {
|
|
for (i = 1; i <= length(attrs); i++) {
|
|
attr = norm_attr(attrs[i])
|
|
values[attr] = ""
|
|
}
|
|
has_values = 0
|
|
}
|
|
function quote_shell(value) {
|
|
gsub(/'\''/, "'\'\\\\\''", value)
|
|
return "'\''" value "'\''"
|
|
}
|
|
function dump_headers() {
|
|
line = ""
|
|
if (shell) {
|
|
if (localvars) {
|
|
print "local attributes index"
|
|
for (i = 1; i <= length(attrs); i++) {
|
|
attr = norm_attr(attrs[i])
|
|
print "local " attr
|
|
}
|
|
}
|
|
line = line "attributes=("
|
|
for (i = 1; i <= length(attrs); i++) {
|
|
attr = norm_attr(attrs[i])
|
|
if (i > 1) line = line " "
|
|
line = line quote_shell(attr)
|
|
}
|
|
line = line ")"
|
|
} else {
|
|
for (i = 1; i <= length(attrs); i++) {
|
|
attr = attrs[i]
|
|
if (i > 1) line = line asep
|
|
line = line attr
|
|
}
|
|
}
|
|
if (line != "") print line
|
|
}
|
|
function dump_cmd(atbegin, atend) {
|
|
if (atbegin && begincmd != "") print begincmd
|
|
if (atend && endcmd != "") print endcmd
|
|
}
|
|
function __should_quote(s) {
|
|
if (s ~ /^[[:blank:][:cntrl:][:space:]]/) return 1
|
|
if (s ~ /[[:blank:][:cntrl:][:space:]]$/) return 1
|
|
return 0
|
|
}
|
|
function dump_values(atbegin, value) {
|
|
if (shell) {
|
|
print "index=" nr
|
|
for (i = 1; i <= length(attrs); i++) {
|
|
attr = norm_attr(attrs[i])
|
|
print attr "=" values[attr]
|
|
}
|
|
if (!atbegin && cmd != "") print cmd
|
|
} else {
|
|
line = ""
|
|
for (i = 1; i <= length(attrs); i++) {
|
|
attr = norm_attr(attrs[i])
|
|
if (i > 1) line = line asep
|
|
value = values[attr]
|
|
if (qsep != "" && index(value, qsep) != 0) {
|
|
if (escape) gsub(qsep, quote_subrepl(escape) "&", value);
|
|
else gsub(qsep, "&&", value);
|
|
}
|
|
if (qsep != "" && (index(value, qsep) != 0 || index(value, asep) != 0 || __should_quote(value))) {
|
|
line = line qsep value qsep
|
|
} else {
|
|
line = line value
|
|
}
|
|
}
|
|
if (line != "") print line
|
|
}
|
|
nr = nr + 1
|
|
}
|
|
|
|
function parse_attr(line) {
|
|
sub(/::?.*$/, "", line)
|
|
return line
|
|
}
|
|
function parse_value(line) {
|
|
sub(/^[^:]+::? /, "", line)
|
|
return line
|
|
}
|
|
|
|
'"$match_attr"'
|
|
BEGIN {
|
|
'"$define_attrs"'
|
|
if (show_headers) dump_headers()
|
|
reset_values()
|
|
nr = -1
|
|
if (shell) dump_values(1)
|
|
dump_cmd(1, 0)
|
|
}
|
|
$0 != "" && match_attr($1) {
|
|
has_values = 1
|
|
attr = norm_attr(parse_attr($0))
|
|
value = parse_value($0)
|
|
if (shell) {
|
|
if (values[attr] == "") {
|
|
values[attr] = quote_shell(value)
|
|
} else {
|
|
tmp = values[attr]
|
|
if (substr(tmp, 1, 1) == "(") tmp = substr(tmp, 2, length(tmp) - 2)
|
|
tmp = tmp " " quote_shell(value)
|
|
values[attr] = "(" tmp ")"
|
|
}
|
|
} else {
|
|
if (values[attr] == "") {
|
|
values[attr] = value
|
|
} else {
|
|
values[attr] = values[attr] vsep value
|
|
}
|
|
}
|
|
}
|
|
$0 == "" {
|
|
if (has_values) dump_values()
|
|
reset_values()
|
|
}
|
|
END {
|
|
if (has_values) dump_values()
|
|
if (shell) dump_cmd(0, 1)
|
|
}
|
|
'
|
|
}
|
|
|
|
function tl_formatcsv() {
|
|
local args show_headers vsep qsep escape
|
|
show_headers=1
|
|
vsep=';'
|
|
qsep='"'
|
|
escape=
|
|
if parse_opts \
|
|
-h,--show-headers show_headers=1 \
|
|
-n,--no-headers show_headers= \
|
|
-R: vsep= \
|
|
--quote: qsep= \
|
|
--escape: escape \
|
|
@ args -- "$@"; then
|
|
set -- "${args[@]}"
|
|
else
|
|
eerror "$args"
|
|
return 1
|
|
fi
|
|
|
|
tl_format ${show_headers:+--show-headers} -F , -R "$vsep" --quote "$qsep" --escape "$escape" "$@"
|
|
}
|
|
|
|
function tl_parsecsv() {
|
|
local -a args headers
|
|
local basedn= rdnattr= skip_lines=0 parse_headers= vsep=';'
|
|
if parse_opts \
|
|
-u:,--rdnattr: rdnattr= \
|
|
-s:,--skip-lines: skip_lines= \
|
|
-h,--parse-headers parse_headers=1 \
|
|
-R: vsep= \
|
|
@ args -- "$@"; then
|
|
set -- "${args[@]}"
|
|
else
|
|
eerror "$args"
|
|
return 1
|
|
fi
|
|
basedn="$1"; shift
|
|
if [ -n "$basedn" ]; then
|
|
[ -n "$rdnattr" ] || rdnattr=uid
|
|
else
|
|
[ -n "$rdnattr" ] || rdnattr=dn
|
|
fi
|
|
[ -n "$*" ] && headers=("$@")
|
|
[ -n "${headers[*]}" ] || parse_headers=1
|
|
|
|
awkrun -f \
|
|
basedn="$basedn" rdnattr="$rdnattr" \
|
|
skip_lines="$skip_lines" parse_headers="$parse_headers" "headers[@]=headers" \
|
|
vsep="$vsep" '
|
|
BEGIN { skip_lines = skip_lines + 0; parse_headers = parse_headers + 0 }
|
|
NR <= skip_lines { next }
|
|
parse_headers {
|
|
array_parsecsv(headers, $0)
|
|
parse_headers = 0
|
|
next
|
|
}
|
|
{
|
|
array_parsecsv(attrs, $0)
|
|
rdnindex = key_index(rdnattr, headers)
|
|
rdnvalue = attrs[rdnindex]
|
|
if (basedn != "") {
|
|
print "dn: " rdnattr "=" rdnvalue "," basedn
|
|
} else {
|
|
print "dn: " rdnvalue
|
|
}
|
|
nbheaders = length(headers)
|
|
for (i = 1; i <= nbheaders; i++) {
|
|
attr = attrs[i]
|
|
split(attr, values, vsep)
|
|
attr = headers[i]
|
|
if (basedn == "" && attr == rdnattr) {
|
|
continue # ne pas écrire deux fois le même attribut
|
|
}
|
|
for (j = 1; j <= length(values); j++) {
|
|
print attr ": " values[j]
|
|
}
|
|
}
|
|
print ""
|
|
}
|
|
'
|
|
}
|
|
|
|
function tl_parsecsvmod() {
|
|
local -a args headers
|
|
local basedn= rdnattr= skip_lines=0 parse_headers= vsep=';'
|
|
if parse_opts \
|
|
-u:,--rdnattr: rdnattr= \
|
|
-s:,--skip-lines: skip_lines= \
|
|
-h,--parse-headers parse_headers=1 \
|
|
-R: vsep= \
|
|
@ args -- "$@"; then
|
|
set -- "${args[@]}"
|
|
else
|
|
eerror "$args"
|
|
return 1
|
|
fi
|
|
basedn="$1"; shift
|
|
if [ -n "$basedn" ]; then
|
|
[ -n "$rdnattr" ] || rdnattr=uid
|
|
else
|
|
[ -n "$rdnattr" ] || rdnattr=dn
|
|
fi
|
|
[ -n "$*" ] && headers=("$@")
|
|
[ -n "${headers[*]}" ] || parse_headers=1
|
|
|
|
awkrun -f \
|
|
basedn="$basedn" rdnattr="$rdnattr" \
|
|
skip_lines="$skip_lines" parse_headers="$parse_headers" "headers[@]=headers" \
|
|
vsep="$vsep" '
|
|
BEGIN { skip_lines = skip_lines + 0; parse_headers = parse_headers + 0 }
|
|
NR <= skip_lines { next }
|
|
parse_headers {
|
|
array_parsecsv(headers, $0)
|
|
parse_headers = 0
|
|
next
|
|
}
|
|
{
|
|
array_parsecsv(attrvalues, $0)
|
|
rdnindex = key_index(rdnattr, headers)
|
|
rdnvalue = attrvalues[rdnindex]
|
|
nbheaders = length(headers)
|
|
# déterminer d"abord s"il faut écrire l"objet
|
|
printobj = 0
|
|
for (i = 1; i <= nbheaders; i++) {
|
|
attr = headers[i]
|
|
if (attr == rdnattr) continue
|
|
attrvalue = attrvalues[i]
|
|
if (attrvalue == "") continue
|
|
# ok on doit ecrire le dn
|
|
if (basedn != "") {
|
|
print "dn: " rdnattr "=" rdnvalue "," basedn
|
|
} else {
|
|
print "dn: " rdnvalue
|
|
}
|
|
print "changetype: modify"
|
|
printobj = 1
|
|
break
|
|
}
|
|
# maintenant, écrire l"objet le cas échéant
|
|
if (printobj) {
|
|
for (i = 1; i <= nbheaders; i++) {
|
|
attr = headers[i]
|
|
if (attr == rdnattr) continue
|
|
attrvalue = attrvalues[i]
|
|
if (attrvalue == "") {
|
|
continue
|
|
} else if (attrvalue ~ /^(replace|add|delete):/) {
|
|
changetype = attrvalue
|
|
sub(/:.*/, "", changetype)
|
|
attrvalue = substr(attrvalue, length(changetype) + 2)
|
|
} else {
|
|
changetype = "replace"
|
|
}
|
|
print changetype ": " attr
|
|
split(attrvalue, values, vsep)
|
|
for (j = 1; j <= length(values); j++) {
|
|
print attr ": " values[j]
|
|
}
|
|
print "-"
|
|
}
|
|
print ""
|
|
}
|
|
}
|
|
'
|
|
}
|
|
|
|
TRANSFORM_CMD_HELP="\
|
|
Il est possible de spécifier plusieurs commandes séparées par //
|
|
Les expressions régulières sont celles reconnues par awk.
|
|
|
|
u, uncut
|
|
Fusionner les lignes coupées. Cette action est en principe effectuée
|
|
automatiquement au début, sauf avec l'option --nu
|
|
c, cut
|
|
Couper les lignes trop longues. Il n'est pas conseillé d'appliquer des
|
|
méthodes de transformation après avoir utilisé cette action.
|
|
dec, decode [attrs...]
|
|
Décoder les valeurs des attributs mentionnés si nécessaire (c'est à dire
|
|
s'ils sont encodés en base64)
|
|
enc, encode [attrs...]
|
|
Encoder en base64 les valeurs des attributs mentionnés.
|
|
k, keepattr attrs...
|
|
Garder uniquement les lignes des attributs mentionnés. Ensuite, supprimer
|
|
les objets ayant uniquement la ligne dn: (en d'autres termes, keepattr sans
|
|
argument supprime *tout* le flux)
|
|
kv, keepval attr patterns...
|
|
Pour l'attribut attr, garder uniquement les lignes pour lesquelles les
|
|
valeurs correspondent aux expressions régulières. Les autres attributs ne
|
|
sont pas modifiés. Ensuite, supprimer les objets ayant uniquement la ligne
|
|
dn:
|
|
x, excludeattr attrs...
|
|
Supprimer les lignes des attributs mentionnés. Ensuite, supprimer les objets
|
|
ayant uniquement la ligne dn:
|
|
xv, excludeval attr patterns...
|
|
Pour l'attribut attr, supprimer les lignes pour lesquelles les valeurs
|
|
correspondent aux expressions régulières. Les autres attributs ne sont pas
|
|
modifiés. Ensuite, supprimer les objets ayant uniquement la ligne dn:
|
|
kve, keepvalentry attr patterns...
|
|
Pour l'attribut attr, vérifier si *au moins une* valeur correspond à l'une
|
|
des expressions régulières. Si c'est le cas, garder toute l'entrée, sinon
|
|
supprimer toute l'entrée.
|
|
xve, excludevalentry attr patterns...
|
|
Pour l'attribut attr, vérifier si *aucune* des valeurs ne correspond à l'une
|
|
des expressions régulières. Si c'est le cas, garder toute l'entrée, sinon
|
|
supprimer toute l'entrée.
|
|
rv, replval attr values...
|
|
Remplacer toutes les valeurs de l'attribut attr par les valeurs spécifiées.
|
|
av, addval attr values...
|
|
Ajouter un nouvel attribut avec les valeurs spécifiées. Si l'attribut existe
|
|
déjà, les nouvelles valeurs sont ajoutées à la fin.
|
|
sed args
|
|
awk args
|
|
grep args
|
|
sort [args]
|
|
awkrun [args]
|
|
Traiter le flux avec respectivement les commandes sed, awk, grep, sort et
|
|
awkrun. awkrun est la version 'améliorée' de awk offerte par nutools.
|
|
Note: ces commandes ne tiennent pas compte de la locale: elles sont lancées
|
|
avec la variable LANG=C
|
|
Note: aucun argument n'est filtré, mais il ne faudrait pas utiliser les
|
|
options qui provoquent la modification en place d'un fichier, comme par
|
|
exemple l'option -i de sed
|
|
format [options] attrs...
|
|
Formater le flux au format ldif en données tabulaires.
|
|
-h, --show-headers
|
|
Afficher les en-têtes. Par défaut, les en-têtes ne sont pas affichés.
|
|
-F ASEP
|
|
Spécifier le séparateur pour les attributs. Par défaut, il s'agit du
|
|
caractère de tabulation.
|
|
-R VSEP
|
|
Spécifier le séparateur pour les valeurs des attributs. Par défaut, il
|
|
s'agit du point-virgule ';'
|
|
--quote QUOTE
|
|
Spécifier le caractère à employer pour encadrer une valeur si elle
|
|
contient l'un des caractères ASEP ou QSEP. Par défaut, les valeurs ne
|
|
sont pas encadrées.
|
|
--escape ESCAPE
|
|
Indiquer que le caractère QUOTE dans une chaine doit être mis en
|
|
échappement avec le caractère ESCAPE. Si ESCAPE est une valeur vide,
|
|
doubler le caractère QUOTE.
|
|
e.g. si QUOTE='\"' et ESCAPE='\\', la valeur abc\"def est écrite ainsi:
|
|
\"abc\\\"def\"
|
|
Par contre, si ESCAPE='', alors la valeur est écrite ainsi:
|
|
\"abc\"\"def\"
|
|
-e
|
|
Retourner les valeurs comme des variables shell. Les options -F et -R
|
|
sont ignorées. Les attributs multivalués sont écrits sous forme de
|
|
tableaux. Par exemple:
|
|
attributes=('mail' 'givenName')
|
|
index=0
|
|
mail='user@domain.fr'
|
|
givenName=('peter' 'gabriel')
|
|
-l, --local
|
|
Ajouter une définition pour rendre locales les variables utilisées,
|
|
e.g. avec l'exemple précédent:
|
|
local attributes index
|
|
local mail
|
|
local givenName
|
|
attributes=('mail' 'givenName')
|
|
index=0
|
|
mail='user@domain.fr'
|
|
givenName=('peter' 'gabriel')
|
|
--bc
|
|
Dans le mode -e, spécifier une commande à insérer avant le premier
|
|
enregistrement. Quand cette commande est lancée, index==-1
|
|
-c
|
|
Dans le mode -e, spécifier une commande à insérer après chaque
|
|
enregistrement
|
|
--ec
|
|
Dans le mode -e, spécifier une commande à insérer après le dernier
|
|
enregistrement
|
|
formatcsv [options] attrs...
|
|
Equivalent à 'format -F , --show-headers --quote \\\"'
|
|
-n, --no-headers
|
|
Ne pas afficher les en-têtes. Par défaut, les en-têtes sont affichés.
|
|
-R VSEP
|
|
--quote QUOTE
|
|
--escape ESCAPE
|
|
Ces options ont la même signification que pour format
|
|
parsecsv [options] basedn [attrs...]
|
|
Analyser le flux au format CSV (qui a par exemple été générée avec la
|
|
commande formatcsv), et reconstruire les objets LDAP associés.
|
|
|
|
En principe, basedn n'est pas vide, et l'option -u détermine l'attribut dont
|
|
la valeur est utilisée pour nommer les objets. Le cas particulier basedn==''
|
|
est aussi supporté, auquel cas la valeur par défaut de rdnattr n'est plus
|
|
'uid' mais 'dn'
|
|
|
|
basedn
|
|
DN de base des objets à construire
|
|
-u, --rdnattr rdnattr[=uid]
|
|
Nommer les objets avec la valeur de l'attribut spécifié
|
|
-s, --skip-lines nblines
|
|
Sauter nblines au début du flux
|
|
-h, --parse-headers
|
|
Lire la liste des attributs à partir de la première ligne non ignorée du
|
|
flux. Si la liste des attributs est vide, cette option est implicitement
|
|
activée.
|
|
-R VSEP
|
|
Spécifier le séparateur pour les valeurs des attributs. Par défaut, il
|
|
s'agit du point-virgule ';'
|
|
parsecsvmod [options] basedn [attrs...]
|
|
Analyser le flux au format CSV qui contient des ordres de modification des
|
|
objets LDAP, et construire les modifications au format LDIF.
|
|
L'attribut rdnattr est le seul dont la valeur doit être au format standard.
|
|
Les valeurs des autres attributs doivent être de la forme [CHANGETYPE:]value
|
|
où CHANGETYPE peut valoir replace (par défaut), add, delete. Si une valeur
|
|
est vide, elle est ignorée
|
|
|
|
En principe, basedn n'est pas vide, et l'option -u détermine l'attribut dont
|
|
la valeur est utilisée pour nommer les objets. Le cas particulier basedn==''
|
|
est aussi supporté, auquel cas la valeur par défaut de rdnattr n'est plus
|
|
'uid' mais 'dn'
|
|
|
|
basedn
|
|
DN de base des objets à construire
|
|
-u, --rdnattr rdnattr[=uid]
|
|
Nommer les objets avec la valeur de l'attribut spécifié
|
|
-s, --skip-lines nblines
|
|
Sauter nblines au début du flux
|
|
-h, --parse-headers
|
|
Lire la liste des attributs à partir de la première ligne non ignorée du
|
|
flux. Si la liste des attributs est vide, cette option est implicitement
|
|
activée.
|
|
-R VSEP
|
|
Spécifier le séparateur pour les valeurs des attributs. Par défaut, il
|
|
s'agit du point-virgule ';'
|
|
awkcsv [options] [attrs...]
|
|
$(sed 's/^/ /g' <<<"$__AWKCSV_HELP")
|
|
mergecsv [options] left right -k field
|
|
$(sed 's/^/ /g' <<<"$__MERGECSV_HELP")
|
|
sortcsv [options] input -k field
|
|
$(sed 's/^/ /g' <<<"$__SORTCSV_HELP")
|
|
|
|
lsed args
|
|
lawk args
|
|
lgrep args
|
|
lsort [args]
|
|
lawkrun [args]
|
|
lawkcsv [options] [attrs...]
|
|
lmergecsv [options] left right -k field
|
|
lsortcsv [options] input -k field
|
|
Ces commandes sont comme les commandes sans le préfixe 'l', mais elles sont
|
|
lancées sans LANG=C, ce qui fait qu'elle tiennent compte de la locale.
|
|
En effet, les outils de coreutils utilisent les règles de la locale pour le
|
|
tri et la comparaison des chaines, et par exemple, avec LANG=fr_FR.UTF-8, la
|
|
locale indique que les ponctuations doivent être ignorées pour le tri, ce
|
|
qui peut poser problème.
|
|
csed args
|
|
cawk args
|
|
cgrep args
|
|
csort [args]
|
|
cawkrun [args]
|
|
cawkcsv [options] [attrs...]
|
|
cmergecsv [options] left right -k field
|
|
csortcsv [options] input -k field
|
|
Ces commandes existent pour compatibilité. Ces commandes sont des aliases
|
|
des commandes sans le préfixe 'c', et existent pour insister sur le fait
|
|
qu'elles sont lancées avec LANG=C.
|
|
|
|
Les directives suivantes transforment le flux au format ldif en une suite de
|
|
commandes de modifications pour ldapmodify:
|
|
|
|
A, modaddattr
|
|
Créer un objet de toutes pièces avec les attributs donnés et leurs valeurs
|
|
a, modaddval
|
|
Ajouter les valeurs spécifiée à l'attribut
|
|
r, modreplval
|
|
Remplacer les valeurs de l'attribut par celles spécifiées
|
|
d, moddelval
|
|
Supprimer les valeurs spécifiées de l'attribut
|
|
D, moddelattr
|
|
Supprimer l'attribut
|
|
delentry
|
|
Supprimer l'objet
|
|
touchentry
|
|
Forcer la réplication de l'objet en simulant une modification"
|
|
|
|
function get_transform_cmd() {
|
|
# Créer une liste de commandes bash à évaluer en fonction des arguments: une
|
|
# suite de commandes séparées par //
|
|
# Les variables suivantes peuvent être définies en entrée:
|
|
# _T_inputfile:
|
|
# Si cette variable est non vide, lire à partir du fichier $_T_inputfile
|
|
# au lieu de stdin
|
|
# _T_uncut_before:
|
|
# faut-il fusionner automatiquement les lignes *avant* de lancer les
|
|
# commandes.
|
|
# _T_cut_after:
|
|
# faut-il découper automatiquement les lignes *après* avoir lancé les
|
|
# commandes.
|
|
local -a cmds cmdparts
|
|
local cmd dest first=1 xempty xdel
|
|
local auto_uncut="$_T_uncut_before"
|
|
local auto_cut="$_T_cut_after" last_is_cut
|
|
[ -n "$_T_inputfile" ] && dest='cat "$_T_inputfile"'
|
|
if [ -n "$*" ]; then
|
|
cmd=
|
|
while [ "$#" -gt 0 ]; do # parce qu'on peut avoir un argument vide!
|
|
if [ "$1" == // ]; then
|
|
[ -n "$cmd" ] && cmds=("${cmds[@]}" "$cmd")
|
|
cmd=
|
|
shift
|
|
continue
|
|
fi
|
|
cmd="${cmd:+"$cmd "}$(quoted_arg "$1")"
|
|
shift
|
|
done
|
|
[ -n "$cmd" ] && cmds=("${cmds[@]}" "$cmd")
|
|
cmd=
|
|
fi
|
|
for cmd in "${cmds[@]}"; do
|
|
eval "set -- $cmd"
|
|
cmd="$1"; shift
|
|
xempty=
|
|
xdel=
|
|
last_is_cut=
|
|
case "$cmd" in
|
|
u|uncut)
|
|
if [ -n "$first" -a -n "$auto_uncut" ]; then
|
|
# l'uncut automatique est demandé, et la première commande est
|
|
# uncut: pas besoin de faire l'uncut automatique
|
|
auto_uncut=
|
|
fi
|
|
cmdparts=(uncut_lines)
|
|
;;
|
|
c|cut)
|
|
cmdparts=(cut_lines)
|
|
last_is_cut=1
|
|
;;
|
|
dec|decode) cmdparts=(tl_decode "$(def_match_attr "$@")");;
|
|
enc|encode) cmdparts=(tl_encode "$(def_match_attr "$@")");;
|
|
k|keep|keepattr)
|
|
cmdparts=(tl_keepattr "$(def_match_attr dn "$@")")
|
|
xempty=1
|
|
;;
|
|
K|kv|keepval)
|
|
local match_attr="$(def_match_attr "$1")"; shift
|
|
cmdparts=(tl_keepval "$match_attr" "$(def_match_value "$@")")
|
|
xempty=1
|
|
;;
|
|
x|exclude|excludeattr)
|
|
cmdparts=(tl_excludeattr "$(def_match_attr "$@")")
|
|
xempty=1
|
|
;;
|
|
dv|delval|X|xv|excludeval)
|
|
local match_attr="$(def_match_attr "$1")"; shift
|
|
cmdparts=(tl_excludeval "$match_attr" "$(def_match_value "$@")")
|
|
xempty=1
|
|
;;
|
|
xve|excludevalentry)
|
|
local match_attr="$(def_match_attr "$1")"; shift
|
|
cmdparts=(tl_excludevalentry "$match_attr" "$(def_match_value "$@")")
|
|
xdel=1
|
|
;;
|
|
kve|keepvalentry)
|
|
local match_attr="$(def_match_attr "$1")"; shift
|
|
cmdparts=(tl_keepvalentry "$match_attr" "$(def_match_value "$@")")
|
|
xdel=1
|
|
;;
|
|
sv|setval|rv|replval)
|
|
local match_attr="$(def_match_attr "$1")"; shift
|
|
cmdparts=(tl_replval "$match_attr" "$@")
|
|
xempty=1
|
|
;;
|
|
av|addval)
|
|
cmdparts=(tl_addval "$@")
|
|
xempty=1
|
|
;;
|
|
xe|xempty|excludeempty) cmdparts=(ensure_complete_objects);;
|
|
sed|awk|grep|sort) cmdparts=(LANG=C "$cmd" "$@");;
|
|
csed|cawk|cgrep|csort) cmdparts=(LANG=C "${cmd#c}" "$@");;
|
|
lsed|lawk|lgrep|lsort) cmdparts=("${cmd#l}" "$@");;
|
|
awkrun|cawkrun) cmdparts=(cawkrun "$@");;
|
|
lawkrun) cmdparts=(lawkrun "$@");;
|
|
awkcsv|csvawk|cawkcsv) cmdparts=(cawkcsv "$@");;
|
|
lawkcsv) cmdparts=(lawkcsv "$@");;
|
|
mergecsv|cmergecsv) cmdparts=(cmergecsv "$@");;
|
|
lmergecsv) cmdparts=(lmergecsv "$@");;
|
|
sortcsv|csortcsv) cmdparts=(csortcsv "$@");;
|
|
lsortcsv) cmdparts=(lsortcsv "$@");;
|
|
f|format) cmdparts=(tl_format "$@");;
|
|
fcsv|formatcsv|format_csv|csv) cmdparts=(tl_formatcsv "$@");;
|
|
pcsv|parsecsv|parse_csv) cmdparts=(tl_parsecsv "$@");;
|
|
pcsvmod|parsecsvmod|parse_csvmod) cmdparts=(tl_parsecsvmod "$@");;
|
|
A|modaddattr) cmdparts=(tl_addattr);;
|
|
a|ma|modadd|modaddval) cmdparts=(tl_modifyattr add);;
|
|
r|mr|modrepl|modreplval) cmdparts=(tl_modifyattr replace);;
|
|
d|md|moddel|moddelval) cmdparts=(tl_modifyattr delete);;
|
|
D|moddelattr) cmdparts=(tl_deleteattr);;
|
|
delentry|moddelentry) cmdparts=(tl_deleteentry);;
|
|
touch|touchentry|modtouchentry) cmdparts=(tl_touchentry);;
|
|
litteral) cmdpars=("$@");;
|
|
*)
|
|
eerror "$cmd: commande inconnue. elle sera ignorée"
|
|
continue
|
|
;;
|
|
esac
|
|
[ -n "$auto_uncut" ] && dest="${dest:+"$dest | "}"'uncut_lines'
|
|
dest="${dest:+"$dest | "}$(quoted_args "${cmdparts[@]}")"
|
|
[ -n "$xempty" ] && dest="${dest:+"$dest | "}"'ensure_complete_objects'
|
|
[ -n "$xdel" ] && dest="${dest:+"$dest | "}"'delete_marked_objects'
|
|
first=
|
|
auto_uncut=
|
|
done
|
|
[ -n "$auto_cut" -a -z "$last_is_cut" ] && dest="${dest:+"$dest | "}"'cut_lines'
|
|
echo "$dest"
|
|
}
|
|
function transform() { eval "$(get_transform_cmd "$@")"; }
|