BASH Tips&Tricks #0002: Форматируем вывод ldapsearch

BASH
Если вам случалось писать на BASH скрипты, работающие с LDAP, то вы наверное уже в курсе, что клиентская утилита ldapsearch, входящая в поставку OpenLDAP, а потому имеющаяся в комплекте большинства дистрибутивов Linux, из каких-то своих соображений (оказывается, это требование RFC 2045) выводит результирующий LDIF со строками, длина которых не превышает 78 символов. Соответственно, те строки, что оказываются длиннее 78-и символов, попросту разбиваются по правилам формата LDIF: в начале продолжения предыдущей строки ставится один пробельный символ.
Анализ такого LDIF на языке оболочки bash может быть затруднительным, гораздо удобнее, когда значение атрибута умещается в одной строке.
Итак, пусть у ldapsearch и нет подходящего ключа командной строки для отмены разбиения строк, зато у меня есть целых три решения данной проблемы: с использованием AWK, Perl или средствами самого BASH.
Расмотрим их все по порядку:
1) С использованием Perl:
perl -e 'while (<>) { $r.="$_"; }; $r=~s/\n //gm; print $r;' < <(ldapsearch _параметры_)
— это, пожалуй, самый простой и наглядный вариант, его и рекомендую к применению;
UPD: А есть и ещё проще, нашёл здесь:
perl -p00e 's/\r?\n //g' < <(ldapsearch _параметры_)

2) С использованием AWK:
awk 'BEGIN { RS=""; FS="\n"; } { l=""; cr=""; for (i=1; i<=NF; i++) { if ($i~/^ /) { l=(l substr($i,2)); } else { l=(l cr $i ); cr="\n"; }; }; print l "\n"; }' <(ldapsearch _параметры_)
— полезен как просто хороший учебный пример, фанаты же AWK наверняка могут его сократить раза этак в три и наверняка не забудут увековечить свой вариант, отписав его в комментарии к посту;

3) Решение задачи средствами самого BASH и с небольшой помощью SED:
while read -r l; do if [[ $l =~ ^\<NOBR\> ]]; then echo -n "${l:6}"; else echo; echo -n "$l"; fi; done < <(ldapsearch _параметры_ | sed -r 's/^\s/<NOBR>/') | sed -e '1d' -e '$s%$%\n%'
— пригодится, пожалуй, мне, как неисправимому sed и bash-маньяку :)

P.S. По сути проблемы на заметку:
[akkerman@localhost ~]$ cd Compile/openldap-2.4.23/
[akkerman@localhost openldap-2.4.23]$ fgrep -rHn LDIF_LINE_WIDTH ./
./libraries/liblutil/ldif.c:581:			if ( len > LDIF_LINE_WIDTH ) {
./libraries/liblutil/ldif.c:621:			if ( len > LDIF_LINE_WIDTH+LDIF_KLUDGE ) {
./libraries/liblutil/ldif.c:650:			if ( len > LDIF_LINE_WIDTH+LDIF_KLUDGE ) {
./libraries/liblutil/ldif.c:675:			if ( len > LDIF_LINE_WIDTH+LDIF_KLUDGE ) {
./include/ldif.h:36:#define LDIF_LINE_WIDTH      76      /* maximum length of LDIF lines */
./include/ldif.h:53:    + ((LDIF_BASE64_LEN(vlen) + (nlen) + 3) / LDIF_LINE_WIDTH * 2 ))

5 комментариев

avatar
Приведённый скрипт AWK скорей плохой пример, он переусложнён. В нём есть ненужная развилка и куча переменных и совсем нет условий
Более простой вариант выглядит так:
awk '!/^ / {printf "\n"} //{printf "%s", substr($0,2)}'

он короче и совершенно понятно как он работает.