Rendere PDF che contiene del testo inserito in una immagine ricercabile con Tesseract e script bash

A volte ci sono dei pdf che non sono ricercabili. Per permettere la ricerca di una parola o di una frase (anche con l’uso del mio script pubblicato in una altro link) ho trovato questo script chiamato pdfocr.sh

#! /bin/bash

INPUT=
declare -a INPUT_FILES
ARGUMENTS=( “$@” )
OUTPUT=
OUT_FINAL=
TESS_CONFIG=pdf
TESS_LANG=ita
RES=300
IMG_FMT=
MODE=full
TESS_PARAMS=
KEEP_TMP=false
MODE=full
PARALLEL=false
JOBS=1
GSDEV=jpeg
INPUT_BASENAME=
TMPDIR_PATH=~/tmp
VERBOSE=false

RESET=”\e[0m”
PENDING=”\e[1;91m”
ERROR=”\e[1;31m”
DONE=”\e[1;36m”
MSG=”\e[1;36m”

#regexes
shopt -s extglob

#kill child processes on error
trap ‘end_jobs’ EXIT

function pdfocr {

if [ ${#ARGUMENTS[@]} -eq 0 ]; then
print_usage
exit
fi

parse_args

check_req

for input_file in “${INPUT_FILES[@]}”; do
echo -e “${MSG}Input file:$RESET” `basename “$input_file”`

if [[ $MODE = clean ]]; then
echo Cleaning temp files…
fi

check_file “$input_file”

init “$input_file”

pdfocr_proc “$input_file”

echo

done

echo -e “${DONE}Finished$RESET”

}

function pdfocr_proc {

local input_file=$1

split “$input_file”

local IN_P=”$TMPDIR_PATH/$INPUT_BASENAME”

if [[ -n $PREPROCESSOR ]]; then
preprocess “$IN_P” “$IMG_FMT”
fi

ocr “$IN_P” “$IMG_FMT”

merge “$IN_P”

clean_tmp “$IN_P” “$IMG_FMT”
}

function split {

if ! [[ $MODE = @(full|split) ]];then
return
fi

echo -e ${PENDING}Running$RESET ghostscript

local IN_F=$1

local GS_OUT=”$TMPDIR_PATH/$INPUT_BASENAME%04d_gs.$IMG_FMT”
gs -dSAFER -dBATCH -dNOPAUSE -sDEVICE=$GSDEV -r$RES -dTextAlphaBits=4 \
-o “$GS_OUT” -f “$IN_F” > /dev/null

try “Error while converting $IN_F”
}

function preprocess {

if [ $PARALLEL = true ]; then
echo -e ${PENDING}Running$RESET preprocessor in parallel
export -f run_preproc
export -f try
local PRE4PARA=`parallel –shellquote ::: “$PREPROCESSOR”`
parallel -n 1 -d ::: -j $JOBS -m run_preproc “$PRE4PARA” {} ::: “$1″*_gs.”$2”
try “Error during parallel preprocessing!”
else
echo -e ${PENDING}Running$RESET preprocessor
for f in “$1″*_gs.”$2”;do
run_preproc “$PREPROCESSOR” “$f”
done
fi

}

function ocr {

if ! [[ $MODE = @(full|ocr) ]]; then
return
fi

local IN_P=”$TMPDIR_PATH/$INPUT_BASENAME”
if [ $PARALLEL = true ]; then
echo -e ${PENDING}Running$RESET tesseract in parallel
if [ “$VERBOSE” = false ];then
run_wait
fi

export -f run_tess
export -f try
export -f print_errors

if [ -z “$TESS_PARAMS” ]; then
TESS_PARAMS=” ”
fi

local ESC=`echo $TESS_PARAMS| sed ‘s/-/__-/’`
ESC=`parallel –shellquote ::: “$ESC”`
parallel -n1 -j $JOBS -m run_tess {} “$TESS_LANG” “$ESC” “$TESS_CONFIG” “$VERBOSE” ::: “$1″*_gs.”$2”
try “Error while running parallel tesseract jobs!”

if [ “$VERBOSE” = false ]; then
kill -INT $!
fi

else
echo -e ${PENDING}Running$RESET tesseract
if [ “$VERBOSE” = false ];then
run_wait
fi

for f in “$1″*_gs.”$2”; do
run_tess “$f” “$TESS_LANG” “$TESS_PARAMS” “$TESS_CONFIG” “$VERBOSE”
done

if [ “$VERBOSE” = false ]; then
kill -INT $!
fi
fi
}

function merge {

if ! [[ $MODE = @(full|merge) ]]; then
return
fi

# local IN_P=”$TMPDIR_PATH/$INPUT_BASENAME”
local file_count=`ls -1 “$1″*_gs_tess.pdf | wc -l`
echo -e ${PENDING}Merging$RESET into $OUT_FINAL
if [[ $file_count -gt 1 ]]; then
pdfunite “$1″*_gs_tess.pdf “$OUT_FINAL”
else
cp “$1″*_gs_tess.pdf “$OUT_FINAL”
fi
try “Error while merging $1″*”$2 into $OUT_FINAL”
}

function clean_tmp {
if [ $KEEP_TMP = true ]; then
return
fi

if [[ $MODE != split ]]; then
rm “$1″*_gs.”$2”
fi
if [[ $MODE != ocr ]]; then
rm “$1″*_gs_tess.pdf
fi
}
function run_wait {

export -f wait_anim
wait_anim &

}

function run_tess {
local IN=$1
local TESS_LANG=$2
local TESS_PARAMS=$3
TESS_PARAMS=`echo $TESS_PARAMS | sed ‘s/__-/-/’`
local TESS_CONFIG=$4
local VERBOSE=$5
local tess_o=
if [ “$VERBOSE” = true ]; then
echo tesseract “$IN” “${IN%.*}_tess” -l $TESS_LANG -psm 3 $TESS_PARAMS $TESS_CONFIG
fi

tess_o=$(tesseract “$IN” “${IN%.*}_tess” -l $TESS_LANG -psm 3 $TESS_PARAMS $TESS_CONFIG 2>&1)
try “Error while performing ocr!” “$tess_o”

if [ “$VERBOSE” = true ]; then
echo $tess_o
echo Tesseract input $1
echo Tesseract output ${1%.*}_tess.pdf
fi
}

function run_preproc {
local PAGE_NUM=`echo $2|gawk ‘match($0,/.+([0-9]{4})_gs.*/,arr) { print arr[1]}’`
$1 “$2” $PAGE_NUM
try “Error while preprocessing!” “Preprocessor: $1” “Input file: $2”
}

function init {

local INPUT=$1

INPUT_BASENAME=$(basename “$INPUT”)
INPUT_BASENAME=${INPUT_BASENAME%.*}

if [ -z “$OUTPUT” ]; then

local INPUT_DIR=$(dirname “$INPUT”)
OUT_FINAL=”$INPUT_DIR/$INPUT_BASENAME”_ocr.pdf

else

if [[ “$OUTPUT” =~ INPUT_BASENAME ]]; then
OUT_FINAL=”${OUTPUT/INPUT_BASENAME/$INPUT_BASENAME}”
elif [[ “${OUTPUT: -1}” == “/” ]]; then
OUT_FINAL=”$OUTPUT$INPUT_BASENAME”_ocr.pdf
OUTPUT_DIR=$OUTPUT
else
OUT_FINAL=$OUTPUT
fi

if [ -z $OUTPUT_DIR ]; then
local OUTPUT_DIR=$(dirname $OUTPUT)
fi

if [ ! -d “$OUTPUT_DIR” ]; then
mkdir -p “$OUTPUT_DIR”
try “Failed creating the output directory: $OUTPUT_DIR”
fi

fi

if [ ! -d “TMPDIR_PATH” ]; then
mkdir -p “$TMPDIR_PATH”
try “Failed creating the temporary directory: $TMPDIR_PATH”
fi

case $GSDEV in
jpeg)
IMG_FMT=jpg
;;
ppm)
;;
png*)
IMG_FMT=png
;;
tiff*)
IMG_FMT=tiff
;;
*)
throw “$IMG_FMT not supported”
;;
esac
}

function parse_args {

local let in_c=0
local let v_c=0

local LANGS_ARR=()
local IN_ARG=

while [[ $v_c -lt ${#ARGUMENTS[@]} ]]; do

key=${ARGUMENTS[$v_c]}

if (( v_c < ${#ARGUMENTS[@]} ));then
local val=”${ARGUMENTS[$((v_c+1))]}”
if [[ $val == -* ]]; then
val=
fi

fi
case $key in
-*)
IN_ARG=
let in_c=0
;;&
-i|–input)
IN_ARG=INPUT
;;
-o|–output)
OUTPUT=”$val”
;;
-t|–tempdir)
TMPDIR_PATH=”$val”
;;
–tess-config)
TESS_CONFIG=”$val”
;;
-l|–language)
IN_ARG=TESS_LANG
;;
-r|–resolution)
RES=”$val”
;;
-f|–img-format)
GSDEV=”$val”
;;
-c|–tess-param)
TESS_PARAMS=”$TESS_PARAMS -c $val”
;;
–keep-tmp)
KEEP_TMP=true
;;
-m|–mode)
MODE=”$val”
;;
-p|–parallel)
if hash parallel 2>/dev/null; then
PARALLEL=true
if [[ -n $val ]]; then
JOBS=$val
else
JOBS=`parallel –number-of-cores`
fi
fi
;;
-s|–preprocessor)
PREPROCESSOR=$val
;;
-v|–verbose)
VERBOSE=true
;;
-h|–help)
print_help
exit
;;
*)
case $IN_ARG in
INPUT)
INPUT_FILES[$in_c]=$key
let in_c++
;;
TESS_LANG)
LANGS_ARR[$in_c]=$key
let in_c++
esac
;;
esac
let v_c++
done

if [[ ${#LANGS_ARR} -gt 0 ]]; then
TESS_LANG=”${LANGS_ARR[@]}”
TESS_LANG=`echo “$TESS_LANG”|sed ‘s/ /+/’`
fi

if ! [[ $MODE = @(split|full|ocr|merge|clean) ]];then
echo “Invalid mode: $MODE”
print_usage
exit
fi

}

function check_req {

if ! hash pdfunite 2> /dev/null; then
throw “pdfunite missing!”
fi

if ! hash tesseract 2> /dev/null; then
throw “tesseract missing!”
fi

if ! hash gs 2> /dev/null; then
throw “ghostscript missing!”
fi

if [ ${#INPUT_FILES[@]} -eq 0 ]; then
throw “pdf input path is missing!”
fi
}

function check_file {
if ! [ -f “$1” ]; then
throw “No such file: $1”
fi
}

function try {
if [[ $? -ne 0 ]] ; then
throw “$@”
fi
return 0
}

function throw {
print_errors “$@”
exit 1
}

function print_errors {
for msg; do
echo -e “$ERROR$msg$RESET”
done
}

function print_help {

cat << END
pdfocr script

Description:

A convenience script that implements a pipeline for creating a searchable
pdf file. The pipeline involves three parts:
-pdf splitting and conversion to images
-character recognition
-merging into the final pdf
Each step can be performed separately of others. You can split pdf, preprocess
images (e.g. with ImageMagick) and then perform ocr and merging.

Requirements:

The following software applications are required:
gs (Ghostscript)
tesseract
pdfunite

Optional:
parallel (speeds up ocr on multiple cores)

Usage:

pdfocr -i|–input input.pdf [options…]

Options:

-l, –lang LANGS set the language(s) for tesseract; check available
languages with:
tesseract –list-langs

-o, –output OUTPUT_PATH set the output path; it can be explicit or use the
INPUT_BASENAME variable to construct it dynamically
e.g. , -o INPUT_BASENAME_ocr.pdf
Default: INPUT_BASENAME_ocr.pdf

-t, –tempdir TMPDIR_PATH set the path to directory with intermediate
files; Default: ~/tmp

-s, –preprocessor PROC_PATH set the path to an image preprocessor;
the preprocessor shall be executed for the image of
each page like this:
preprocessor img_path page_num
the preprocessor should overwrite the original image

-m, –mode MODE set the mode to perform only the part of processing;
MODE can be one of:
split
ocr
merge
full
Default: full
note: it is assumed that required files are in the
TMPDIR_PATH; modes ‘split’ and ‘ocr’ don’t delete
their output intermediate files

–tess-config CONFIG set the tesseract configuration; default: pdf

-p, –parallel [JOBS] use GNU parallel if available; limit the number
of jobs to JOBS

-v, –verbose allow verbose output

–keep-tmp keep the intermediate files; deleted by default

-f, –img-format the format of the intermediate images;
possible values:
jpeg png* ppm tiff*
any format supported by Ghostscript that matches
the above values is valid;
note: the image format makes a difference for
tesseract, so experiment with different values
Default: jpeg

-r, –resolution RES set the resolution of intermediate images to RES;
default: 300

-c, –tess-param key=val set a tesseract parameter
e.g., -c textord_min_linesize=2.5

-h, –help print this
END
}

function print_usage {
cat << END
pdfocr script

Usage:

pdfocr -i|–input input.pdf [options…]

Options:

-h, –help print help
-l, –lang LANGS set the language(s) for tesseract
-o, –output OUTPUT_PATH set the output path
-t, –tempdir TMPDIR_PATH set the path to tempdir (def: ~/tmp)
-m, –mode MODE set the mode (split,ocr,merge,full)
–tess-config CONFIG set the tesseract configuration; default: pdf
-f, –img-format FMT the format of the intermediate images;
jpeg png* ppm tiff*
-r, –resolution NUM set the resolution of the intermediate images
-c, –tess-param key=val set a tesseract parameter
–keep-tmp keep the intermediate files; deleted by default
-p, –parallel [JOBS] use GNU parallel if available
-v, –verbose allow verbose output
-s, –preprocessor PROC_PATH set the path to images preprocessor

END

}

function wait_anim {

trap “__STOP_PRINT=true” SIGINT
local move=r
local let length=5
local let pos=0
while [[ $__STOP_PRINT != true ]]; do

echo -en ” |”

for ((i=0;i<pos;i++));do
echo -n ” ”
done

echo -en “$PENDING*$RESET”

for ((i=0;i<length-pos;i++));do
echo -n ” ”
done

echo -en “|”
echo -ne \\r
if [[ $move == r ]]; then
let pos++
if ((pos>=length)); then
move=l
fi
else
let pos–
if ((pos<=0)); then
move=r
fi
fi

sleep 0.07
done
}

function end_jobs {

local job_n=`jobs -p | wc -l`
if ((job_n>0)); then
jobs -p | xargs kill
fi

}

pdfocr
trap ” EXIT SIGINT

# vim: ts=2 sw=2

Cambiare versione PHP Aruba.it

Da qualche mese Aruba ha aggiornato il look del Pannello di Controllo. Sicuramente più compatto rispetto al precedente paginone, questo cambio ha causato diversi disagi a determinati utenti, che non riuscirebbero più a trovare delle funzioni. Più che di difficoltà però, si tratta di disabitudine: abbandonare un’interfaccia usata per anni e anni (magari quotidianamente) non è certo facile.

Il dilemma di oggi è: dove posso modificare la versione di PHP in uso? Riferito al servizio Hosting, quindi siti web. Aruba offre un semplice tool per farlo, ma sembra essersi perso. In realtà, raggiungerlo è semplice!

Ci basta effettuare il Login, e cliccare poi su Pannello di Controllo. Sulla colonna dei menù a sinistra, clicchiamo su Hosting Linux, e poi sulla sottovoce Gestione Hosting Linux. Verremo reindirizzati ad un’altra pagina, dove ci basterà cliccare sul tab Strumenti e Impostazioni (in alto), e da li cliccare su Scelta della versione PHP. Aperto il pop-up, scegliamo la versione desiderata e confermiamo. Nel giro di qualche minuto, saremo in grado di verificare la nuova versione di PHP.

Problemi di compatibilità sconfitti in meno di un minuto 😎

PDF Estrattore di testo e di pagine script bash

Lo script estrae del testo da alcuni file pdf inseriti in una dir passata come argomento e li copia in una cartella deposito di un percorso specificato. Vengono creati dei file pdf con le pagine che contengono le stringe ricercate oltre a copiare il file originale. Se il nome del file contiene degli spazi questi vengono sostituiti con il carattere undescore “_”.

pdfestrattore.sh “Text” “./target/*” “./destination/”

#!/bin/bash
# Ricerca Testo e copia file presso la directory di destinazione
# bash pdfestrattore.sh “Text” “./target/*” “./destination/”
#  Vers. 1.1 del 06/02/2017
# Uso del pdfgrep versione 1.4.x e 2.0.x

controllapdfgrep=(`which pdfgrep`)
controllapdftk=(`which pdftk`)

if [ “$controllapdfgrep” = “” ];
then
echo “PdfGrep non è installato! Il comando su Ubuntu è apt-get install pdfgrep”
exit
fi

if [ “$controllapdftk” = “” ];
then
echo “Pdftk non è installato! Il comando su Ubuntu è  apt-get install pdftk”
exit
fi

function pausa()
{
read -p “$*”
}

#funzione usata per rinominare i file
RINOMINAFILE() {
#$FILE non è necessario definirla come locale
local BASENAME=$1 #$1 è la 1° variabile passata alla funzione al momento della sua invocazione
#se non ho spazi nel nome file non lo devo rinominare
if echo $BASENAME | grep ” ” ; then
NUOVONOMEFILE=`echo $BASENAME | tr ‘A-Z ‘ ‘A-Z_’`
#rinomino il file $NUOVONOMEFILE contiene il nome del file
#con gli spazi traformati in _
mv “$BASENAME” $NUOVONOMEFILE
fi
}

#questa è una funzione ricorsiva
RINOMINADIR() {
#$DIR è necessario definirla come locale
local DIR=$1
if echo $DIR | grep ” ” ; then
NUOVONOMEDIR=`echo $DIR | tr ‘A-Z ‘ ‘A-Z_’`
mv “$DIR” $NUOVONOMEDIR
else
#se non ci sono spazi assegno a $NUOVONOMEDIR il valor di $DIR
NUOVONOMEDIR=$DIR
fi
#Entro nella dir per verificare se ho altre dir o file
cd $NUOVONOMEDIR
find -maxdepth 1 | while read d; do
#il comando find mi restituisce tra i risultati anche la dir corrente ./
#che non và considerata
if [ “$d” != “.” ]; then
#verifico se $d è una directory
if [ -d “$d” ]; then
#se $d è una directory richiamo la funzione ricorsivamente
RINOMINADIR “$d”
else
#se $d non è una directory richiamo la funzione RINOMINAFILE
RINOMINAFILE “$d”
fi
fi
done
#Visto che prima sono entrato in $NUOVONOMEDIR adesso devo uscirne per poter continuare
cd ..
}

#MAIN
find -maxdepth 1 | while read l; do
#il comando find mi restituisce tra i risultati anche la dir corrente ./
#che non và considerata
if [ “$l” != “.” ]; then
#verifico se ho una directory
if [ -d “$l” ]; then
#ricchiamo la funzione RINOMINADIR
RINOMINADIR “$l”
else
#ricchiamo la funzione RINOMINAFILE
RINOMINAFILE “$l”
fi
fi
done

# Controlla se il comando viene eseguito con le opzioni corrette

if [ $# -eq 0 ]; then
echo -e ” ”
echo -e “pdfestrattore.sh Script v. 1.0 del 31-01-2017″
echo -e ” ”
echo -e “SINTASSI: ./pdfestrattore.sh “Text da cercare” sorgente destinazione”
echo -e ” ”
echo -e “Errore: devi specificare degli argomenti!”
echo -e ” ”
exit 1;
fi

PERCORSO=”$3″
ARCHIVIO=”deposito”

# Controlla l’esistenza della dir e cancella il contenuto, se non presente crea sotto $DESTINAZIONE la cartella deposito
if [ ! -d $PERCORSO/$ARCHIVIO ]; then
echo -e “Verra’ creata la dir $PERCORSO/$ARCHIVIO!”
#  chiamata di funzione pausa
pausa ‘Premere [Enter] per continuare, puoi premere CTRL+C per interrompere!’
mkdir -p $PERCORSO/$ARCHIVIO;
else
echo -e “Attenzione i file della dir $PERCORSO/$ARCHIVIO verranno cancellati!”
# controlla il numero di file nella directori di origine e di destinazione
NUMERO1=`ls -l “$2” | wc -l`
echo -e “Il numbero di files nella cartella di origine è $NUMERO1”
NUMERO2=`ls -l “$3” | wc -l`
echo -e “Il numbero di files nella catella di destinazione è $NUMERO2″
#  chiamata di funzione pausa
pausa ‘Premere [Enter] per continuare, puoi premere CTRL+C per interrompere!’
rm -rf $PERCORSO/$ARCHIVIO/*;
fi;

while read line; do
file=$(echo $line|awk -F: ‘{print $1}’)
STRING=”$1″
FILENAME=”${file##*/}”
BASENAME=”${FILENAME%.*}”
DIRNAME=”${file%/*}”
printf “$file: ”
echo “$line”|grep -q :0$ && echo Stringa non trovata! && continue
echo Stringa trovata!
cp -fi “$file” $PERCORSO/$ARCHIVIO;
RINOMINAFILE “${PERCORSO}/${ARCHIVIO}/${BASENAME}.pdf”
echo “Salvataggio nella dir: $PERCORSO/$ARCHIVIO del file completo: ${FILENAME}”
echo “Processo il file: $FILENAME…”
echo “Sto controllando per la stringa: $STRING…”
echo “Salvataggio nella dir: $PERCORSO/$ARCHIVIO del file ${BASENAME}_pagina_con_${STRING}.pdf”
## Ricerca il testo nei file passati
PAGES=”$(pdfgrep -in “$STRING” “$file” | cut -f1 -d “:” | uniq | tr ‘\n’ ‘ ‘)”
echo “Trovata stringa nella/e pagina/e numero: $PAGES”
## extract pages to new file in original directory
echo “Sto estraendo le pagine…”
pdftk “$file” cat $PAGES output “${PERCORSO}/${ARCHIVIO}/${BASENAME}_pagina_con_${STRING}.pdf”
RINOMINAFILE “${PERCORSO}/${ARCHIVIO}/${BASENAME}_pagina_con_${STRING}.pdf”
echo “Ciclo terminato per il file ${FILENAME}”
done < <(find $2 -type f -iname ‘*.pdf’ -exec pdfgrep -ircnHF “${STRING}” {} \;)
echo “Programma terminato!”

 

Opzioni da linea di comando con getopts

Nei miei script di studio, per il passaggio di dati agli script, fino ad ora, ho utilizzato i parametri posizionali ($1, $2,…${N}); è ora di imparare ad usare degli indici letterali come negli script “seri” del tipo:

nomescript -a parametro -b altro Parametro.

Per fare quello che voglio, ho trovato due possibili comandi: “getopts” e “getopt”; il primo, a differenza del secondo, non ammette l’uso di “stringhe opzione lunghe” (–opzione) ma solo ad un carattere (-a), ma ha il vantaggio di essere un “builtin” quindi presente di default in Bash; per questo motivo parlerò di “getopts”.

Ho fatto un piccolo script per le prove (più in basso) e mi segnerò su questa pagina qualche annotazione utile sull’uso del comando.

USO di base

Per prima cosa vanno decise le lettere da usare come opzioni letterali nel mio caso ‘a, b, c, d, e, h’ nell’utilizzo sulla linea di comando devono essere precedute dal “-” (meno) ed inserite singolarmente (non: ‘script -abc’ ma ‘script -a -b -c’ ).

Per l’utilizzo pratico conviene inserirle in un ciclo while con case, vedere lo script ed i commenti:

#!/bin/bash
clear script=$(basename $0)
help=”Questo script, ‘$script’, serve solo per vedere l’uso di getopts quindi affinché venga eseguito correttamente occorre passare almeno un’opzione. Le opzioni accettate sono: ‘-a’, ‘-b’, ‘-c’, ‘-d’, ‘-e’ e ‘-h’
Le opzioni ‘a,b,c,d,e’ mostrano solo l’opzione passata ed il proprio eventuale argomento. L’opzione ‘-h’ mostra l’help Solo ‘-c’ accetta un argomento, da passare da linea di comando, dopo l’opzione. Il ‘-‘ (meno) identifica, nella lettera che segue, un’opzione.\n Es.:./opzioni_prova.sh -a -b -c prova -d -e -h
# Controllo che sia stato passato almeno un argomento
if [ $# -eq 0 ] # se lo script è eseguito senza argomenti…
then
echo -e “$help” # … stampo l’help…
exit 1 # … ed esco.
fi
while getopts “:abc:deh” opzione # Dichiaro le opzioni accettate e il tipo
# i ‘:’ (due punti) iniziali sopprimono i messaggi di errore
# i ‘:’ (due punti) dopo un’opzione significano che ci si aspetta un argomento.
# Occhio! Qualsiasi cosa dopo ‘-c’ viene preso come argomento di ‘-c’
do
case $opzione in
# $OPTIND è il puntatore (numerico) all’opzione successiva
# $OPTARG è l’argomento passato, se esiste
a ) echo -e “\nhai inserito l’opzione -a con \$OPTIND: $OPTIND e argomento: $OPTARG”;;
b ) echo -e “\nhai inserito l’opzione -b con \$OPTIND: $OPTIND e argomento: $OPTARG”;;
c ) echo -e “\nhai inserito l’opzione -c con \$OPTIND: $OPTIND e argomento: $OPTARG”;;
d ) echo -e “\nhai inserito l’opzione -d con \$OPTIND: $OPTIND e argomento: $OPTARG”;;
e ) echo -e “\nhai inserito l’opzione -e con \$OPTIND: $OPTIND e argomento: $OPTARG”;;
h ) echo -e “\n$help”;; * ) echo -e “\nÈ stata inserita un’opzione non valida.\n\n $help”;;
esac
done shift $(($OPTIND – 1)) # resetto (come $OPTIND=1)
# Sposta il puntatore all’opzione che segue per esempio il parametro posizionale $1.
exit 0

Nella riga while getopts “:abc:deh” Opzione i primi : (due punti) servono per utilizzare il comando in modalità silenziosa, sopprimendo gli eventuali messaggi di errore.

I : (due punti) posti dopo la lettera c servono ad indicare che l’opzione -c accetta un parametro obbligatorio, se il parametro non viene inserito verrà preso come parametro qualsiasi stringa seguente -c quindi attenzione!

Nella stessa riga, la stringa “opzione” è la variabile impostata dal ciclo while che verrà utilizzata nel costrutto case.
Le righe in case sono quasi tutte del tipo:

a ) echo -e “\nhai inserito l’opzione -a con \$OPTIND: $OPTIND e argomento: $OPTARG”;;
servono solo per mostrare i valori dell’opzione passata, il valore di $OPTIND (che è l’indice numerico dell’opzione successiva) e dell’eventuale valore del parametro passato, contenuto in $OPTARG.
La riga:
h ) echo -e “\n$help”;;
a differenza delle precedenti stampa a video solo quanto scritto nella variabile $help.
La riga:
* ) echo -e “\nÈ stata inserita un’opzione non valida.\n\n $help”;;
intercetta tutto quanto è diverso dalle opzioni indicate precedentemente, quindi le opzioni non valide, informa del fatto e mostra l’help.
La riga:
shift $(($OPTIND – 1))
serve a “resettare” $OPTIND equivale a $OPTIND=1. Dopo aver resettato si potrebbero usare gli eventuali parametri posizionali o anche ripetere il ciclo precedente

Le prove

Conviene scaricare lo script opzioni_prova.sh renderlo eseguibile e provarlo; inizialmente in modo corretto con: ./opzioni_prova.sh -a -b -c prova -d -e -h in seguito conviene provare a passare dati incompleti, con parametro e senza, sbagliati etc. si comprenderà facilmente la forza ed i limiti del comando.

Ricercare i pdf e nei pdf

Un amico mi chiese una applicazione per poter cercare nei pdf….. 2 soluzioni

a) recoll http://www.lesbonscomptes.com/recoll/download.html#general

b) pdfgrep https://gitlab.com/pdfgrep/pdfgrep

presenti sia sotto linux che sotto windows.

Lo script per estrarre pagine pdf da un file pdf piu’ grande il file si chiama pdfselect.sh

#!/bin/bash
# extract pages from a big pdf file using gs
# Usage:
#           pdfselect.sh pdffile startPageNumber endPageNumber

function getPDFPages()
{
if [ -e $1 ]; then
pdfinfo $1 | grep Pages | awk {print $2}
else
echo 0;
fi
}

if [ $# -lt 2 ]; then
sed -n 3,4p `which pdfselect.sh`
exit
fi

oriPdf=$1
[ ! -e ${oriPdf} ] && echo ${oriPdf} does not exist! && exit

numPage=`getPDFPages ${oriPdf}`
[ ${numPage} -eq 0 ] && ZERO page is found in ${oriPdf} && exit

sPage=$2
[ ${sPage} -gt ${numPage} ] && ${sPage}=${numPage}
i

———————- SCRIPT FILE ESTRATTORE DI PAGINE DA FILE PDF IN BASE ALLA RICERCA ——

# ./extract_pdf_results.sh Lagrange ./test.pdf
# ./extract_pdf_results.sh “Text” $file

STRING=”$1″
FILE=”$2″
FILENAME=”${FILE##*/})”
BASENAME=”${FILENAME%.*}”
DIRNAME=”${FILE%/*}”

echo “Processing $FILE…”

## find pages that contain string, remove duplicates, convert newlines to spaces

echo “Looking for $STRING…”

PAGES=”$(pdfgrep -n “$STRING” “$FILE” | cut -f1 -d “:” | uniq | tr ‘\n’ ‘ ‘)”

echo “Matching pages:
$PAGES”

## extract pages to new file in original directory

echo “Extracting result pages…”

pdftk “$FILE” cat $PAGES output “${DIRNAME}/${BASENAME}_pages_with_${STRING}.pdf”

echo “Done.”

—— SCRIPT CHE COPIA FILE PDF CHE CONTENGONO STRINGA IN UNA OPPORTUNA DIR —

#!/bin/bash
# Ricerca Testo e copia file presso la directory di destinazione
# bash pdfgrepandmv.sh “Text” “./target/*” “./destination/”

while read line; do
file=$(echo $line|awk -F: ‘{print $1}’)
printf “$file: ”
echo “$line”|grep -q :0$ && echo STRINGA NON TROVATA! && continue
echo STRINGA TROVATA
cp -i “$file” $3
done < <(find $2 -type f -iname ‘*.pdf’ -exec pdfgrep -Hc “$1” {} \;)

Installare i pacchetti su linux Ubuntu

Debian e Ubuntu

Comandi per gestire i pacchetti  in Ubuntu, Debian e distribuzioni derivate: installare applicazioni eliminare,  cercare.

Comando dpkg

Installare un file .deb

sudo dpkg -i package_file.deb

Qualora ci siano problemi di dipendenze nell’installazione del pacchetto lanciare  di seguito

sudo apt-get -f install 

ed eventualmente nuovamente il comando  sudo dpkg -i package_file.deb

Rimuovere .deb file

sudo dpkg -r package_name

Per rimuovere pacchetti che danno problemi di rimozione con apt-get remove si può provare

sudo dpkg -P package_name

Cercare un pacchetto installato con dpkg

dpkg -l libgtk[0-9]* | grep ^i 

Visualizzare  tutto i pacchetti il software installato con dpkg

dpkg -get-selections 

Provare a riparare i pacchetti danneggiati

sudo dpkg --configure -a

Per elencare i pacchetti disponibili si può usare

sudo dpkg -l php*

Per elencare i pacchetti installati si può usare

sudo dpkg -l | grep php

Comando apt-get

apt-get ( advanced packagind tool è il gestore dei pacchetti standard della distribuzione Debian e anche della derivata Ubuntu

installare il pacchetto “package” con

sudo apt-get install package

cercare un pacchetto nella cache di apt-get

sudo apt-cache search mysql 

Per ottenere dettagli su un pacchetto utilizzare il comando

apt-cache policy mysql-server

Rimuovere il pacchetto “package” con

sudo apt-get remove package

Rimuovere il pacchetto package con tutti i files di configurazione

sudo apt-get --purge remove package

Rimuovere il pacchetto package con tutte le dipendenze inutilizzate

sudo apt-get autoremove package

Riparare le dipendenze dei pacchetti non soddisfatte

sudo apt-get -f install 

Convertire i pacchetti  .rpm

Convertire i pacchetti .rpm. in pacchetti .deb

sudo alien -k file.rpm

Repository importare chiave di autenticazione

Per importare la chiave di autenticazione di un repository utilizzare un comando del tipo che segue sostituendo con il numero della chiave le X :

gpg --keyserver keyserver.ubuntu.com --recv XXXXXXXX && gpg --export -a XXXXXXXX | sudo apt-key add -

Ubuntu – Debian

Controllare e risolvere eventuali errori o dipendenze rotte con:

sudo apt-get check 
sudo apt-get -f install

Provare a riparare pacchetti danneggiati

sudo dpkg --configure -a

Reinstallazione  ubuntu debian

Reinstallare da zero un sistema ubuntu o debian linux con tutti i pacchetti di una altra installazione.

Salvare la lista dei pacchetti in un file

sudo dpkg -get-selections > package_installed.txt

Utilizzare la lista dei pacchetti salvata per installare lo stesso software anche nel nuovo sistema

sudo dpkg -set-selections < package_installed.txt && apt-get dselect -upgrade

Ubuntu aggiornamenti ( update )

Per aggiornare la lista dei pacchetti disponibili

sudo apt-get update 

Scaricare e installare gli aggiornamenti per tutti i pacchetti installati

sudo apt-get upgrade 

Ubuntu upgrade di versione

Per aggiornare l’intero sistema ad una nuova versione

sudo do-release-upgrade

o

sudo apt-get dist-upgrade 

oppure è possibile digitare la combinazione Alt+F2 e scrivere

update-manager -d

Problemi ed errori installazione pacchetti: apt-get

Per quanto riguarda i problemi con i pacchetti abbiamo visto che è possibile provare a riparare i pacchetti danneggiati con:

sudo dpkg --configure -a

Inoltre che è possibile controllare e risolvere errori o dipendenze dipendenze non soddisfatte dei pacchetti con:

sudo apt-get check 
sudo apt-get -f install
Reading package lists... Error!
E: Encountered a section with no Package: header
E: Problem with MergeList /var/lib/apt/lists/security.ubuntu.com_ubuntu_dists_natty-security_restricted_binary-i386_Packages
E: The package lists or status file could not be parsed or opened.

Si può provare a risolvere usando :

sudo rm /var/lib/apt/lists/* -vf
sudo apt-get update

Centos

yum install package
yum remove package
yum update

Indicatore di presenza con domoticz Iphone/Android

Contenuto di uno script crontab per il riavvio ogni 10 minuti

*/10 * * * *  /home/pi/domoticz/scripts/check_device_online.py 192.168.30.27 47 10 2700 ‘ per Iphone5

*/10 * * * *  /home/pi/domoticz/scripts/check_device_online.py 192.168.30.37 48 10 120 ‘ per Android

la sintassi è

*/10 * * * * /home/pi/domoticz/scripts/nome_script.py IP_:address_ipv4  nr_idx_domoticz nr_secondi nr_secondi_di_cambio_stato

COPIA DA QUI—- LO SCRIPT check_device_online.py RICORDATI I PERMESSI

#!/usr/bin/python
#   Title: check_device_online.py
#   Author: Chopper_Rob
#   Date: 25-02-2015
#   Info: Checks the presence of the given device on the network and reports back to domoticz
#   URL : https://www.chopperrob.nl/domoticz/5-report-devices-online-status-to-domoticz
#   Version : 1.6.2

import sys
import datetime
import time
import os
import subprocess
import urllib2
import json
import base64

# Settings for the domoticz server
domoticzserver=”192.168.30.23:8080″
domoticzusername = “”
domoticzpassword = “”
domoticzpasscode = “”

# If enabled. The script will log to the file _.log
# Logging to file only happens after the check for other instances, before that it only prints to screen.
log_to_file = False

# The script supports two types to check if another instance of the script is running.
# One will use the ps command, but this does not work on all machine (Synology has problems)
# The other option is to create a pid file named _.pid. The script will update the timestamp
# every interval. If a new instance of the script spawns it will check the age of the pid file.
# If the file doesn’t exist or it is older then 3 * Interval it will keep running, otherwise is stops.
# Please chose the option you want to use “ps” or “pid”, if this option is kept empty it will not check and just run.
check_for_instances = “pid”

# DO NOT CHANGE BEYOND THIS LINE
if len(sys.argv) != 5 :
print (“Not enough parameters. Needs %Host %Switchid %Interval %Cooldownperiod.”)
sys.exit(0)

device=sys.argv[1]
switchid=sys.argv[2]
interval=sys.argv[3]
cooldownperiod=sys.argv[4]
previousstate=-1
lastsuccess=datetime.datetime.now()
lastreported=-1
base64string = base64.encodestring(‘%s:%s’ % (domoticzusername, domoticzpassword)).replace(‘\n’, ”)
domoticzurl = ‘http://’+domoticzserver+’/json.htm?type=devices&filter=all&used=true&order=Name’

if check_for_instances.lower() == “pid”:
pidfile = sys.argv[0] + ‘_’ + sys.argv[1] + ‘.pid’
if os.path.isfile( pidfile ):
print datetime.datetime.now().strftime(“%H:%M:%S”) + “- pid file exists”
if (time.time() – os.path.getmtime(pidfile)) < (float(interval) * 3):
print datetime.datetime.now().strftime(“%H:%M:%S”) + “- script seems to be still running, exiting”
print datetime.datetime.now().strftime(“%H:%M:%S”) + “- If this is not correct, please delete file ” + pidfile
sys.exit(0)
else:
print datetime.datetime.now().strftime(“%H:%M:%S”) + “- Seems to be an old file, ignoring.”
else:
open(pidfile, ‘w’).close()

if check_for_instances.lower() == “ps”:
if int(subprocess.check_output(‘ps x | grep \” + sys.argv[0] + ‘ ‘ + sys.argv[1] + ‘\’ | grep -cv grep’, shell=True)) > 2 :
print (datetime.datetime.now().strftime(“%H:%M:%S”) + “- script already running. exiting.”)
sys.exit(0)

def log(message):
print message
if log_to_file == True:
logfile = open(sys.argv[0] + ‘_’ + sys.argv[1] + ‘.log’, “a”)
logfile.write(message + “\n”)
logfile.close()

def domoticzstatus ():
json_object = json.loads(domoticzrequest(domoticzurl))
status = 0
switchfound = False
if json_object[“status”] == “OK”:
for i, v in enumerate(json_object[“result”]):
if json_object[“result”][i][“idx”] == switchid:
switchfound = True
if json_object[“result”][i][“Status”] == “On”:
status = 1
if json_object[“result”][i][“Status”] == “Off”:
status = 0
if switchfound == False: print (datetime.datetime.now().strftime(“%H:%M:%S”) + “- Error. Could not find switch idx in Domoticz response. Defaulting to switch off.”)
return status

def domoticzrequest (url):
request = urllib2.Request(url)
request.add_header(“Authorization”, “Basic %s” % base64string)
response = urllib2.urlopen(request)
return response.read()

log (datetime.datetime.now().strftime(“%H:%M:%S”) + “- script started.”)

lastreported = domoticzstatus()
if lastreported == 1 :
log (datetime.datetime.now().strftime(“%H:%M:%S”) + “- according to domoticz, ” + device + ” is online”)
if lastreported == 0 :
log (datetime.datetime.now().strftime(“%H:%M:%S”) + “- according to domoticz, ” + device + ” is offline”)

while 1==1:
# currentstate = subprocess.call(‘ping -q -c1 -W 1 ‘+ device + ‘ > /dev/null’, shell=True)
currentstate = subprocess.call(‘sudo arping -q -c1 -W 1 ‘+ device + ‘ > /dev/null’, shell=True)

if currentstate == 0 : lastsuccess=datetime.datetime.now()
if currentstate == 0 and currentstate != previousstate and lastreported == 1 :
log (datetime.datetime.now().strftime(“%H:%M:%S”) + “- ” + device + ” online, no need to tell domoticz”)
if currentstate == 0 and currentstate != previousstate and lastreported != 1 :
if domoticzstatus() == 0 :
log (datetime.datetime.now().strftime(“%H:%M:%S”) + “- ” + device + ” online, tell domoticz it’s back”)
domoticzrequest(“http://” + domoticzserver + “/json.htm?type=command&param=switchlight&idx=” + switchid + “&switchcmd=On&level=0” + “&passcode=” + domoticzpasscode)
else:
log (datetime.datetime.now().strftime(“%H:%M:%S”) + “- ” + device + ” online, but domoticz already knew”)
lastreported=1

if currentstate == 1 and currentstate != previousstate :
log (datetime.datetime.now().strftime(“%H:%M:%S”) + “- ” + device + ” offline, waiting for it to come back”)

if currentstate == 1 and (datetime.datetime.now()-lastsuccess).total_seconds() > float(cooldownperiod) and lastreported != 0 :
if domoticzstatus() == 1 :
log (datetime.datetime.now().strftime(“%H:%M:%S”) + “- ” + device + ” offline, tell domoticz it’s gone”)
domoticzrequest(“http://” + domoticzserver + “/json.htm?type=command&param=switchlight&idx=” + switchid + “&switchcmd=Off&level=0” + “&passcode=” + domoticzpasscode)
else:
log (datetime.datetime.now().strftime(“%H:%M:%S”) + “- ” + device + ” offline, but domoticz already knew”)
lastreported=0

time.sleep (float(interval))

previousstate=currentstate
if check_for_instances.lower() == “pid”: open(pidfile, ‘w’).close()