qcm

Faire des qcm simplement - retour accueil

git clone git://bebou.netlib.re/qcm
Log | Files | Refs | README |

qcm.sh (5333B)


      1 #! /bin/sh
      2 
      3 usage() <<-. cat
      4 	Faire des sondages simples en parsant les logs d'un serveur web
      5 
      6 	Usage : qcm [-h] [-e] [-u url] [-l logs] [-g] [-i identifiant]
      7 
      8 	url par défaut : http://bebou.netlib.re (modifiable dans le code)
      9 	log par défaut : /var/log/nginx/access.log (modifiable dans le code)
     10 	nombre de question par défaut : 4 (ABCD)
     11 	identifiant par défaut : match la regex [a-zA-Z0-9]{3}
     12 
     13 	Exemples :
     14 
     15 	qcm # écrire le questionnaire sur le moment avec tous les défauts
     16 	qcm -u http://monsite.com # modifier l'affichage de l'url
     17 	qcm -l /var/log/httpd/logs # changer le chemin du log parcouru
     18 	qcm -e # masquer les réponses quand elles arrivent, mode "examen"
     19 	qcm -i fraise # lancer un questionnaire avec l'identifiant fraise
     20 	cat mon-questionnaire.qcm | qcm # lancer le questionnaire .qcm
     21 	cat mon-questionnaire.qcm | ssh compte@serveur qcm # le lancer à distance mais ne fonctionne pas encore !
     22 
     23 	Pour une explication plus détaillée voir le README ou
     24 	http://arthur.bebou.netlib.re/qcm
     25 .
     26 
     27 show() <<-. cat
     28 	url         : $url/$id/réponse
     29 	par exemple : $url/$id/A
     30 
     31 	$question
     32 
     33 	$context
     34 
     35 	$groupedanswers
     36 
     37 	total   : $tot
     38 .
     39 
     40 gplot() {
     41 gnuplot -e "
     42 	set term dumb 75,13;
     43 	set border 1+2;
     44 	set ytics scale 0 nomirror autofreq 1;
     45 	set xtics nomirror;
     46 	set yrange [0:*];
     47 	plot '-' u 1:xtic(2) w histo not;
     48 " | sed 's/-/━/g; s/|/┃/g; s/ \* / ┃ /g; s/ \*\*/ ┏━/g; s/━+/━━/g; s/+━/┗━/g;
     49 		 s/\([0-9]\) +/\1 ┃/g; s/\(┃ \+\)+/\1 /g; s/\*\* /━┓ /g; s/\*\*\*/━━━/g;
     50 		 s/\*\*/━━/g'
     51 }
     52 
     53 
     54 calcandshow() {
     55 	local plotcmd hide; plotcmd="$1";hide="$2"
     56 	if [ -z "$uniqueanswers" ];then tot=0
     57 	else
     58 		if [ -n "$hide" ];then
     59 			groupedanswers=
     60 		else
     61 			if [ "$type" != "ouverte" -a "$type" != "regex" ];then
     62 				 sortanswers='while read line;do echo "$line" | grep -o . | sort -u | paste -s -d "\0" -;done'
     63 			else sortanswers='cat'
     64 			fi
     65 			groupedanswers=$(echo "$uniqueanswers" |
     66 				grep -Eo "/$id/[^ ]+ " | cut -d'/' -f3- | # PARSAGE DE LOG
     67 				eval $sortanswers |
     68 				sed 's,%\([0-9A-F][0-9A-F]\),\\\\\x\1,g' | xargs printf "%b\n" |
     69 				grep -v "^$" |
     70 				sort | uniq -c | sort -rn | $plotcmd )
     71 		fi
     72 		tot=$(echo "$uniqueanswers" | wc -l)
     73 	fi
     74 
     75 	context=$(case "$type" in
     76 		( "ouverte" ) continue ;;
     77 		( "regex" )   printf "format autorisé : %s" "$options" ;;
     78 		( * )
     79 			[ "$choix" = "+" ] \
     80 				&& printf "%s\n" "une ou plusieurs options vraies" \
     81 				|| printf "%s\n" "une seule option vraie"
     82 			[ -n "$options" ] \
     83 				&& printf "%s" "$(echo "$options" | tr '~' '\n' | paste $tmpd/o -)" \
     84 				|| printf "options : %s" "$(< $tmpd/o paste -d '\0' -s -)"
     85 			;;
     86 	esac)
     87 
     88 	clear
     89 	show
     90 }
     91 
     92 demander() {
     93 	local plotcmd
     94 	case "$type" in
     95 		( "ouverte" ) pattern=;                       plotcmd="cat";;
     96 		( "regex" )   pattern="${options:-[ABCD] } "; plotcmd="cat";;
     97 		( * )
     98 			possibleanswers="ABCDEFGHIJQLMNOPQRSTUVWXYZ"
     99 			[ -n "$options" ] && nbq=$(( $(echo "$options" | grep -o '~' | wc -l) + 1 ))
    100 			echo "$possibleanswers" | grep -o '.' | head -n$nbq > $tmpd/o
    101 			answers=$(cat $tmpd/o | tr -d '\n')
    102 			pattern="[$answers]$choix ";;
    103 	esac
    104 	pattern="GET /$id/$pattern"
    105 
    106 	[ -p $tmpd/notif ] || mkfifo $tmpd/notif
    107 	tail -fn0 "$logs" | stdbuf -oL grep -E "$pattern" >> $tmpd/in & # PARSAGE DE LOG
    108 	tail1pid=$!
    109 	tail -fn0 "$logs" | stdbuf -oL grep -E "$pattern" > $tmpd/notif & # PARSAGE DE LOG
    110 	tail2pid=$!
    111 
    112 	calcandshow "$plotcmd" "$hide"
    113 	cat $tmpd/notif | while read newanswer ;do
    114 		uniqueanswers=$(< $tmpd/in sort $uopt -k1,1)
    115 		[ "$olduniqueanswers" != "$uniqueanswers" ] && calcandshow "$plotcmd" "$hide"
    116 		olduniqueanswers="$uniqueanswers"
    117 	done &
    118 	disppid=$!
    119 
    120 	read _ < /dev/tty
    121 	kill $disppid $tail1pid $tail2pid
    122 
    123 	if [ -n "$hide" ];then
    124 		uniqueanswers=$(< $tmpd/in sort $uopt -k1,1)
    125 		calcandshow "$plotcmd"
    126 		read _ < /dev/tty
    127 		uniqueanswers=;groupedanswers=;tot=0
    128 	fi
    129 
    130 	rm $tmpd/in
    131 }
    132 
    133 nbq=4
    134 uopt="-u"
    135 choix=
    136 plotcmd="cat"
    137 url="http://bebou.netlib.re"
    138 logs="/var/log/nginx/access.log"
    139 
    140 while getopts "hegl:u:i:" opt; do
    141 	case $opt in
    142 		( l | u | i ) [ ! -z $OPTARG ] && eval "$opt='$OPTARG'" ;;
    143 		( g )     command -v gnuplot && plotcmd="gplot" ;;
    144 		( h )     usage; exit ;;
    145 		( e )     hide="yes";;
    146 		( * )     echo "Option inconnue, voir l'aide en lançant qcm -h";exit 1;;
    147   esac
    148 done
    149 
    150 tmpd=$(mktemp -d ${TMPDIR:-/tmp}/qcm.XXX)
    151 if [ -n "$i" ];then
    152 	existingids=$(ps -A -l -f | grep "[ /]qcm " |
    153 	              grep -o -- '-i [^ ]\+' |
    154 				  cut -d' ' -f2 | sort | uniq -c)
    155 	while echo "$existingids" | grep -q " \+[3-9] \+$i";do
    156 		if [ ! -t 0 ];then echo "id existe déjà"; exit 1;
    157 		else               read -p "id existe déjà, nouvel id : " i < /dev/tty
    158 		fi
    159 	done
    160 	id="$i"
    161 else
    162 	id=$(basename "$tmpd" | cut -d'.' -f2)
    163 fi
    164 
    165 alias question:=question; question() question="$*"
    166 alias type:=type;         type()     type="$*"
    167 alias options:=options;   options()  options="$*"
    168 alias choix:=choix;       choix()    { [ "$*" = "multiple" ] && choix="+" || choix=; }
    169 alias unique:=unique;     unique()   { [ "$*" = "non" ] && uopt= || uopt="-u"; }
    170 
    171 trap "rm -rf $tmpd;exit" INT TERM
    172 trap "kill 0"            EXIT
    173 
    174 if [ -t 0 ];then
    175 	<<-. cat
    176 	Ecrivez le questionnaire puis ctrl+d sur une ligne vide pour le soumettre
    177 	syntaxe du questionnaire :
    178 	http://arthur.bebou.netlib.re/qcm/#le-format-du-fichier-de-questionnaire
    179 	.
    180 fi
    181 
    182 cat > "$tmpd/questions"
    183 file="$tmpd/questions"
    184 . "$file"