On 07.01.2013 08:59, Jozsef Kadlecsik wrote:
On Sun, 6 Jan 2013, Jan Engelhardt wrote:
On Sunday 2013-01-06 04:50, Born Without wrote:
As I was missing those features in the ipset set listing capabilities:
- show sum of set members
- suppress listing of headers
- choose a delimiter character for separating member entries
I wrote a little wrapper script (for the bash shell) to support them.
For those who like, you'll find it attached.
There's libipset, with which this task should be achievable to the
maximum customizable degree without involving ugly text parsing with sh.
good you mention libipset, because not even the man page does, nor does any
documentation or similar exist.
I have taken Joszef into Cc..
[...]
In order to parse the output produced by ipset, one should take into
account the followings:
- New header elements may appear but the header part is always
started by "Name:" and ended by "Members:".
- New value parameters may appear but those are appended to the existing
ones.
If those "rules" are taken into account, then shell/perl/etc scripts can
safely parse the output.
Thank you Joszef for that information.
I've taken it into account and adapted the script.
Also added:
-a parameter to act just like 'ipset list', but with whitespace as
default delim.
comments and examples.
Best regards
#!/bin/bash
# -----------------------------------------------------------------
# ipset set listing wrapper script
# -----------------------------------------------------------------
# Examples:
# $0 - no args, just list set names
# $0 -c - show all set names and their member sum
# $0 -t - show all sets, but headers only
# $0 -c -m setA setB - show members and sum of setA & setB
# $0 -a -c -d : - show all sets members, sum and use `:' as entry delimiter
# $0 -c -m -d $'\n' setA - show members and sum of setA, delim with newline
# -----------------------------------------------------------------
# -----------------------------------------------------------------
# Modify here
# -----------------------------------------------------------------
# path to ipset
ipset="/sbin/ipset"
# default delimiter character
delim=" "
# default read timeout
TMOUT=30
# -----------------------------------------------------------------
set -f
shopt -s extglob
show_all=0 show_count=0 show_members=0 headers_only=0 names_only=0 in_header=0 i=0
[[ -x $ipset ]] || {
printf "ipset binary \`%s' does not exist, or is not executable" "$ipset"
exit 1
}
while (($#)); do # parse cmd-line options
case "$1" in
-h) printf "ipset set listing wrapper script\n"
printf "%s [-{a|c|h|m|n|r|s|t}] [...] [-d char] [set-name] [...]\n" "${0//*\//}"
exit 0
;;
-a) show_all=1
shift
;;
-c) show_count=1
shift
;;
-m) show_members=1
shift
;;
-n) names_only=1
shift
;;
-t) headers_only=1
arr_par[i++]="$1"
shift
;;
-s|-r) arr_par[i++]="$1"
shift
;;
-d) if [[ -z $2 ]]; then
printf "delim character is missing\n" >&2
exit 2
else
if ((${#2} > 1)); then
printf "only one character is allowed as delim\n" >&2
exit 2
fi
delim="$2"
shift 2
fi
;;
-o) if [[ $2 != plain ]]; then
printf "only plain output is supported\n" >&2
exit 2
else
shift 2
fi
;;
-\!|-f) printf "unsupported option: \`$1'\n" >&2
exit 2
;;
*) break
esac
done
# option logic
if ((names_only && headers_only)); then
printf "options -n and -t are mutually exclusive\n" >&2
exit 2
elif ((headers_only)); then
if ((show_count || show_members || show_all)); then
printf "options -t and -a|-c|-m are mutually exclusive\n" >&2
exit 2
fi
elif ((names_only)); then
if ((show_count || show_members || show_all)); then
printf "options -n and -a|-c|-m are mutually exclusive\n" >&2
exit 2
fi
"$ipset" l -n
exit $?
fi
# sets to work on (no arg means all sets)
i=0
if [[ $1 ]]; then
arr_opts=("$@")
else
while IFS=$'\n' read -r; do
arr_opts[i++]="$REPLY"
done < <("$ipset" l -n)
i=0
fi
# read sets
for x in "${!arr_opts[@]}"; do
while read -r; do
case "$REPLY" in
"") : ;;
Name:*) # header opened
if ((in_header)); then
printf "unexpected entry: \`%s' - header not closed?\n" "$REPLY" >&2
exit 1
fi
i=0 in_header=1
printf "\n%s\n" "$REPLY"
;;
@(Type|Header|Size in memory|References):*) # header entry
if ((headers_only || show_all)); then
printf "%s\n" "$REPLY"
fi
;;
Revision:*) # header entry (closes header on -t)
if ((headers_only)); then
in_header=0
printf "%s\n" "$REPLY"
elif ((show_all)); then
printf "%s\n" "$REPLY"
fi
;;
Members:*) # header entry (closes header if not -t)
in_header=0
if ((show_all)); then
printf "%s\n" "$REPLY"
fi
;;
*) # member entry
if ((in_header)); then
printf "unexpected entry: \`%s'\n" "$REPLY" >&2
exit 1
fi
if ((show_members || show_all)); then
printf "%s$delim" "$REPLY"
fi
let i+=1
esac
done < <("$ipset" l "${arr_opts[x]}" "${arr_par[@]}")
if ((show_members || show_all)) && [[ $delim != $'\n' ]]; then
printf "\n"
fi
if ((show_count)); then
printf "Member count: %d\n" $i
fi
done