#!/bin/bash # -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8 source "$(dirname -- "$0")/lib/ulib/auto" || exit 1 function display_help() { uecho "$scriptname: Afficher le résultat d'une recherche par regexp et compter éventuellement leurs occurences USAGE $scriptname [options] [regexp] Chaque ligne *entière* de stdin est mise en correspondance avec l'expression regulière qui doit avoir la syntaxe de awk. S'il y a correspondance, afficher soit toute l'expression matchée, soit chaque groupe s'il y a des expressions parenthésées, chacun des groupes étant séparé par le caractère sep. Si l'expression régulière n'est pas spécifiée, elle vaut par défaut '.*' ce qui fait que toutes les lignes correspondent. Ceci peut être utile avec les options -s et -c. Certaines expressions régulières sont prédéfinies. regexp peut avoir l'une des valeurs prédéfinies suivantes: ip --> "'[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+'" OPTIONS -F sep Spécifier le caractère séparateur en sortie s'il faut afficher des champs multiples. Par défaut, utiliser le caractère ':' Si un séparateur vide est spécifié, le séparateur standard de awk est utilisé. -s Trier le résultat -C FIELDNUM -c, --count Compter les occurences successives de la valeur du champ FIELDNUM, et afficher une ligne de la forme 'countlast_line' pour chaque groupe, last_line étant la dernière occurence du groupe. L'option -c correspond à '-C 0', c'est à dire compter les occurences successives de toute les lignes. Le séparateur utilisé pour calculer le numéro de champ est sep, spécifié avec l'option -F. -a, --all-lines Avec les options -c/-C, afficher toutes les lignes des occurences successives au lieu de seulement la ligne de la dernière occurence. Ceci est utile surtout avec l'option -C, pour voir les différences avec les différentes lignes. -m, --multiple Avec les options -c/-C, n'afficher que les lignes dont le compte est supérieur à 1. Avec l'option -a, les groupes contigus sont séparés par une ligne '--'" } function match() { local regexp="$1" sep="$2" awkrun ${sep:+FS="$sep"} '{ pos = match($0, /'"${regexp//\//\\/}"'/, out) if (pos != 0) { max = length(out) / 3 if (max == 1) { print out[0] } else { line = "" for (i = 1; i < max; i++) { if (i > 1) line = line FS line = line out[i] } print line } } }' } function count() { local field="$1" sep="$2" all_lines="$3" awkrun field="$field" ${sep:+FS="$sep"} all_lines="$all_lines" ' BEGIN { first = 1 lastfield = "" lastline = "" count = 0 if (all_lines == "") all_lines = 0 else all_lines = 1 } !first && $field != lastfield { if (!all_lines) print count FS lastline count = 0 } { count = count + 1 lastfield = $field lastline = $0 first = 0 if (all_lines) print count FS lastline } END { print count FS lastline } ' } sep=: sort= count= all_lines= multiple= parse_opts "${PRETTYOPTS[@]}" \ --help '$exit_with display_help' \ -F: sep= \ -s sort=1 \ -c,--count count=0 \ -C: count= \ -a,--all-lines all_lines=1 \ -m,--multiple multiple=1 \ @ args -- "$@" && set -- "${args[@]}" || die "$args" regexp="$1" [ -n "$regexp" ] || regexp=".*" case "$regexp" in ip) regexp='[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+';; esac cmd="$(qvals match "$regexp" "$sep")" [ -n "$sort" ] && cmd="$cmd | sort" [ -n "$count" ] && cmd="$cmd | $(qvals count "$count" "$sep" "$all_lines")" if [ -n "$multiple" ]; then if [ -n "$all_lines" ]; then cmd="$cmd | $(qvals grep -v -B 1 "^1$sep")" else cmd="$cmd | $(qvals grep -v "^1$sep")" fi fi eval "$cmd"