Come posso fare in modo che uno script acceda a un file separato il numero di volte in cui è stato eseguito?

10

Ho bisogno di scrivere uno script che scrive su un file quante volte è stato eseguito questo script.

Come posso farlo?

    
posta Milen Grigorov 20.12.2017 - 14:43

4 risposte

14

Presumo che tu voglia avere un singolo file countfile che contiene solo un singolo numero che rappresenta il contatore di esecuzione.

Puoi leggere questo contatore in una variabile di shell $counter e.g. utilizzando una di queste linee:

  • read counter < countfile
    
  • counter=$(cat countfile)
    

Le semplici aggiunte di interi possono essere fatte in Bash stessa usando la sintassi $(( EXPRESSION )) . Quindi scrivi semplicemente il risultato sul nostro countfile :

echo "$(( counter + 1 ))" > countfile

Probabilmente dovresti anche salvaguardare lo script per il caso in cui countfile non esiste ancora e crearne uno inizializzato con il valore 1 quindi.

Il tutto potrebbe assomigliare a questo:

#!/bin/bash
if [[ -f countfile ]] ; then
    read counter < countfile
else
    counter=0
fi
echo "$(( counter + 1 ))" > countfile
    
risposta data Byte Commander 20.12.2017 - 14:51
5

Lascia che lo script crei un file di registro, aggiungi ad esempio una riga nello script alla fine:

echo "Script has been executed at $(date +\%Y-\%m-\%d) $(date +\%H-\%M-\%S)" >> ~/script.log

In questo modo puoi formattare il modo in cui ti presenti la data e l'ora, ma se vuoi semplicemente andare con una data e un'ora complete (e HH:MM:SS è un formato accettabile per te) puoi semplicemente usare:

echo "Script has been executed at $(date +\%F-\%T)" >> ~/script.log

Quindi potresti fare:

wc -l ~/script.log

Che conta i caratteri di nuova riga e ti danno una stima di quante linee si trovano all'interno del file di registro. Fino a questo puoi vedere all'interno del file di log anche quando è stato eseguito. Per adattarlo alle proprie esigenze, è possibile modificare i percorsi e i nomi utilizzati per la registrazione. Ho appena fatto un esempio qui che salva il file di registro in ~ .

Quindi, ad esempio, vuoi che lo script aggiunga questo conteggio alla riga che hai aggiunto alla fine del tuo script, potresti fare qualcosa di simile all'inizio del tuo script:

count=$(( $(wc -l ~/script.log | awk '{print $1}') + 1 ))
# the next line can be simply skipped if you not want an output to std_out
echo "Script execution number: $count"

E cambia la tua linea alla fine dello script con qualcosa che includa anche quelle informazioni:

echo "Script has been executed $count times at $(date +\%F-\%T)" >> ~/script.log
    
risposta data Videonauth 20.12.2017 - 14:53
5

Questa soluzione utilizza lo stesso approccio della risposta di Byte Commander ma non si basa sull'aritmetica della shell o su altri Bashism.

exec 2>&3 2>/dev/null
read counter < counter.txt || counter=0
exec 3>&2 3>&-
expr "$counter" + 1 > counter.txt

I reindirizzamenti del flusso

  1. duplica il flusso di errori standard (2) in un diverso descrittore di file (3),
  2. sostituirlo (2) con un reindirizzamento a /dev/null (per sopprimere il messaggio di errore nel successivo reindirizzamento dell'input del comando read se il file contatore è mancante previsto),
  3. in seguito duplica il flusso di errori standard originale (ora in 3) di nuovo in posizione (2) e
  4. chiude la copia del flusso di errori standard (3).
risposta data David Foerster 21.12.2017 - 00:39
0

Un approccio diverso

Un file contatore separato presenta degli svantaggi:

  • Sono necessari 4096 byte (o qualsiasi sia la dimensione del blocco) per ogni file contatore.
  • Devi cercare il nome del file nello script bash e quindi aprire il file per vedere il conteggio.
  • Non c'è il blocco dei file (in altre risposte), quindi è possibile che due persone aggiornino il contatore allo stesso tempo (chiamate condizioni di competizione nei commenti sotto la risposta di Byte Commander).

Quindi questa risposta elimina un file contatore separato e inserisce il conteggio nello script bash stesso!

  • Mettere il contatore nello script bash stesso ti permette di vedere all'interno del tuo script quante volte è stato eseguito.
  • L'utilizzo di flock garantisce che per un breve momento non è possibile per due utenti eseguire lo script contemporaneamente.
  • Poiché il nome del file contatore non è codificato in modo rigido, non è necessario modificare il codice per diversi script, basta semplicemente copiarlo o copiarlo e incollarlo da un file stub / boilerplate.

Il codice

#!/bin/bash

# NAME: run-count.sh
# PATH: $HOME/bin
# DESC: Written for AU Q&A: https://askubuntu.com/questions/988032/how-can-i-cause-a-script-to-log-in-a-separate-file-the-number-of-times-it-has-be

# DATE: Mar 16, 2018.

# This script run count: 0

# ======== FROM HERE DOWN CAN GO INTO FILE INCLUDED WITH SOURCE COMMAND =======

[ "${FLOCKER}" != "$0" ] && exec env FLOCKER="$0" flock -en "$0" "$0" "[email protected]" || :
#     This is useful boilerplate code for shell scripts.  Put it at the top  of
#     the  shell script you want to lock and it'll automatically lock itself on
#     the first run.  If the env var $FLOCKER is not set to  the  shell  script
#     that  is being run, then execute flock and grab an exclusive non-blocking
#     lock (using the script itself as the lock file) before re-execing  itself
#     with  the right arguments.  It also sets the FLOCKER env var to the right
#     value so it doesn't run again.

# Read this script with entries separated newline " " into array
mapfile -t ScriptArr < "$0"

# Build search string that cannot be named
SearchStr="This script"
SearchStr=$SearchStr" run count: "

# Find our search string in array and increment count
for i in ${!ScriptArr[@]}; do
    if [[ ${ScriptArr[i]} = *"$SearchStr"* ]]; then
        OldCnt=$( echo ${ScriptArr[i]} | cut -d':' -f2 )
        NewCnt=$(( $OldCnt + 1 ))
        ScriptArr[i]=$SearchStr$NewCnt
        break
    fi
done

# Rewrite our script to disk with new run count
# BONUS: Date of script after writing will be last run time
printf "%s\n" "${ScriptArr[@]}" > "$0"

# ========= FROM HERE UP CAN GO INTO FILE INCLUDED WITH SOURCE COMMAND ========

# Now we return you to your original programming....

exit 0

Un altro approccio che utilizza un file di registro

Simile alla risposta di Videonauth ho scritto una risposta al file di registro qui: script Bash per mantenere traccia di controllo / registro dei file accessibili per registrare ogni volta che i poteri di root sono stati usati con gedit o nautilus .

Il problema è piuttosto che usare gksu lo script è chiamato gsu e invoca pkexec il modo "moderno" di usare sudo nella GUI, così mi è stato detto.

Un altro vantaggio non è solo dire ogni volta che i poteri di root sono stati usati con gedit ma registra il nome del file che è stato modificato. Ecco il codice.

~/bin/gsu :

#!/bin/bash

# Usage: gsu gedit file1 file2...
#  -OR-  gsu natuilus /dirname

# & is used to spawn process and get prompt back ASAP
# > /dev/null is used to send gtk warnings into dumpster

COMMAND="$1" # extract gedit or nautilus

pkexec "$COMMAND" "${@:2}"

log-file "${@:2}" gsu-log-file-for-"$COMMAND"

/usr/local/bin/log-file :

#! /bin/bash

# NAME: log-file
# PATH: /usr/local/bin
# DESC: Update audit trail/log file with passed parameters.
# CALL: log-file FileName LogFileName
# DATE: Created Nov 18, 2016.
# NOTE: Primarily called from ~/bin/gsu

ABSOLUTE_NAME=$(realpath "$1")
TIME_STAMP=$(date +"%D - %T")
LOG_FILE="$2"

# Does log file need to be created?
if [ ! -f "$LOG_FILE" ]; then
    touch "$LOG_FILE"
    echo "__Date__ - __Time__ - ______File Name______" >> "$LOG_FILE"
    #     MM/DD/YY - hh:mm:ss - "a/b/c/FileName"
fi

echo "$TIME_STAMP" - '"'"$ABSOLUTE_NAME"'"' >> "$LOG_FILE"

exit 0

Contenuto del file di registro gsu-log-file-for-gedit dopo alcune modifiche:

__Date__ - __Time__ - ______File Name______
11/18/16 - 19:07:54 - "/etc/default/grub"
11/18/16 - 19:08:34 - "/home/rick/bin/gsu"
11/18/16 - 19:09:26 - "/home/rick/bin/gsu"
    
risposta data WinEunuuchs2Unix 17.03.2018 - 03:42

Leggi altre domande sui tag