#!/usr/bin/bash # 20241109 ~ @verner # fgp : outil de recherche contenu fichiers, à récursivité adaptative # ―――――――― _help() { cat < ... Description: Recherche contenu fichiers à récursivité adaptative et sortie formatée. La liste d'options accessibles est limitée aux courantes (90% des besoins) Options par défaut: * recherche à partir du répertoire courant, si aucun répertoire indiqué; * récursivité automatique (max 10) jusqu'aux premiers résultats, ou niveau max imposé par option '-N' * regex Etendu ; ex: '(abc|xyz)' * Masjucules/minuscules indifférenciées (inversable avec -ni) * ne traverse pas les systèmes de fichiers différents * exclusion des répertoires/fichiers cachés * exclusion des répertoires .cache, Trash, lost+found, et fichiers binaires * exclusion des fichiers non autorisés * avertissement au delà de 100 fichiers trouvés * détection des variables commençant par un tiret Options: -a,--all : recherche aussi dans les répertoires/fichiers cachés -N : profondeur max N de recherche répertoires -r : récursivité (max 10) -mN : affichage limité aux N premières lignes trouvées par fichier (ex: -m2) -l,--files-with-matches : seul le nom du fichier sera affiché -w,--word : recherche de 'cat' -> 'xx/cat,yy' sera trouvé, mais pas 'xxcatyy' -v,--invert-match : recherche inversée -AN : affiche N lignes suivantes (After ; seulement pour entrée | ) -q,--quiet : sortie muette, test uniquement (seulement pour entrée | ) -ni,--no-ignore-case : distinction minuscule ou Majuscule -nc,--no-color : suppression sortie couleur -h,--help : affiche cette aide Exemples: fgp '^[scude]' /etc/apt/s{,*/}*[st] fgp -a 'firefox' fgp '(modules=|blacklist)' /etc /usr/share fgp '^P.*(esr|rbird)$' /var/ fgp -v '^(#|$)' /etc/dpkg/*.cfg lspci -v | fgp 'audio' -A7 man cp | fgp '-deref' EOF } # ――――――――― opt=EIhis for x ; do case $x in -a|--all) a=1 ;; # + hiddens -l|--files-with-matches) l=-l ;; # print file-name only -w|--word) opt=w$opt ;; # exact word (more restrictive) -m*) ((${x/-m/}>0)) && mc=$x ;; # max count output -ni|--no-ignore-case) opt=${opt/i/} ;; # strict case -A*) ((${x/-A/}>0)) && A=$x ;; # After (pipe input only) -v|--invert-match) v=-v ;; -q|--quiet) q=-q ;; -nc|--no-color) cl=never ;; -r) md=10 ;; -h|--help) _help ; exit ;; -[0-9]*) ((${x/-/}>0)) 2>/dev/null && md=${x/-/} ;; # depth *) [ -d "$x" ] && R+=("$x") || { [ -f "$x" ] && F+=("$x") || pat="$x" ;} ;; esac done # ――――――――― [ "$pat" ] || { echo " > argument absent" ; exit 1 ;} [ "$F$R" ] || R=. t0=$(date "+%s") # ――――――――― [ "$cl" ] || { cl=always; GREP_COLORS='ms=01;36'; p='\x1b[38;5'; c0='\x1b[0m' cb="$p;75m";cc="$p;123m";cg="$p;120m";co="$p;215m";cy="$p;228m"; } # ―――――――― if [ -p /dev/stdin ] ; then cat /dev/stdin | grep -$opt $v $q $mc $A --color=$cl -- "$pat" ; exit fi # ―――――――― p1="${pat/^/^[0-9]*:}" ; grep -q '\[' <<<"$pat" && p2=¤ || p2="${pat/^/}" _gp() { grep -n$opt $mc -- "$pat" "$f" |sed 's#\(.\{120\}\)#\1\n#g' | \ sed -rn "\%$p1%I{s/^[0-9]*:/${cy}& $c0/;s,$p2,${cc}&$c0,gI;p}" echo ; } # ――――――――― if [ "$F" ] ; then if [ "$v" ] ; then grep -ETvn $l --color=$cl -- "$pat" "${F[@]}" else while read f ; do sed "s,[^/]*$,${cg}&$c0," <<<"$f" [ "$l" ] || _gp done< <(grep -l -$opt -- "$pat" "${F[@]}") fi fi if [ "$R" ] ; then fmax=100; D=1 [ "$v" ] && echo " > -v non compatible argument répertoire" && exit 1 msg1() { printf "――――\n» $lim$co$z$c0 fichiers sous " printf "$cb$(echo "${R[@]}")$c0 | depth: $co$D$c0 " T=$(($(date "+%s")-$t0)) if (($T>1)) ; then S=$((T%60))s ; M=$(((T%3600)/60))mn (($T<60)) && printf "| ~ $S" || printf "| ~ $M $S" fi echo ; } { [ "$a" ] || [[ ${R/\/.//} != $R ]] ;} && hd='/¤' || hd='.*/\..*' for Rx in "${R[@]}" ; do d=1 ; y=0 ; [ "$md" ] && M=$md || M=1 while ((d<=M)) ; do ex=1 while read f ; do if ((d>1)) && [ "$ex" ] ; then ex= ; ((M>D)) && D=$M printf "${co}%0.s../" $(seq 1 $((d-1))) ; printf " $d ${c0}\n" fi sed "s,$Rx,${cb}&$c0,;s,[^/]*$,${cg}&$c0," <<<"$f" ((y++)) ; ((z++)) [ "$l" ] || _gp # ~~~~~~~~~~~ if ((z>=fmax)) ; then lim='Plus de ' ; msg1 read -t 15 -p "On continue ? [o,y / n] " q /dev/null | \ xargs -0 grep -l -$opt -- "$pat" |LC_ALL=C sort -V) ((z>20)) && l=-l [ -z "$md" ] && ((y<10)) && ((M<10)) && ((M++)) ((d++)) done done if ((z==0)); then printf "${cy}» Rien trouvé / Options possibles:\n" [ "$a" ] || printf " * recherche dans les fichiers cachés: -a\n" printf " * modifier le répertoire de recherche ${c0}\n" exit 1 elif ((z>3)); then msg1 fi fi # ――――――――― exit