it-swarm.com.de

Wie kann ich ein Skript veranlassen, sich so oft in einer separaten Datei anzumelden, wie es ausgeführt wurde?

Ich muss ein Skript schreiben, das in eine Datei schreibt, wie oft dieses Skript ausgeführt wurde.

Wie kann ich das machen?

10
Milen Grigorov

Ich nehme an, Sie möchten eine einzelne Datei countfile haben, die nur eine einzige Zahl enthält, die den Ausführungszähler darstellt.

Sie können diesen Zähler in eine Shell-Variable $counter einlesen, z. mit einer dieser Zeilen:

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

Einfache Ganzzahladditionen können in Bash selbst unter Verwendung der $(( EXPRESSION )) -Syntax durchgeführt werden. Dann schreiben Sie einfach das Ergebnis zurück in unser countfile:

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

Sie sollten Ihr Skript wahrscheinlich auch für den Fall schützen, dass countfile noch nicht vorhanden ist, und dann ein Skript mit dem Wert 1 erstellen.

Das Ganze könnte so aussehen:

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

Diese Lösung verwendet den gleichen Ansatz wie Antwort von Byte Commander , basiert jedoch nicht auf Shell-Arithmetik oder anderen Bashismen.

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

Die Stream-Umleitungen

  1. den Standardfehlerstrom (2) in einen anderen Dateideskriptor (3) duplizieren,
  2. ersetzen Sie es (2) durch eine Umleitung zu /dev/null (um die Fehlermeldung bei der nachfolgenden Umleitung der Eingabe des Befehls read zu unterdrücken, wenn die Zählerdatei erwartungsgemäß fehlt).
  3. duplizieren Sie später den ursprünglichen Standardfehlerstrom (jetzt bei 3) wieder an Ort und Stelle (2) und
  4. schließen Sie die Kopie des Standardfehlerstroms (3).
5
David Foerster

Lassen Sie das Skript einfach eine Protokolldatei erstellen und fügen Sie am Ende beispielsweise eine Zeile in Ihr Skript ein:

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

Auf diese Weise können Sie die Art und Weise, wie Sie Datum und Uhrzeit darstellen, selbst formatieren. Wenn Sie jedoch nur Datum und Uhrzeit eingeben möchten (und HH:MM:SS ein für Sie akzeptables Format ist), können Sie auch einfach Folgendes verwenden:

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

Dann könnten Sie tun:

wc -l ~/script.log

Dies zählt die Zeilenumbrüche und gibt Ihnen eine Schätzung, wie viele Zeilen sich in der Protokolldatei befinden. Bis dahin können Sie innerhalb der Protokolldatei sehen, auch wenn es ausgeführt wurde. Um es an Ihre Bedürfnisse anzupassen, können Sie die für die Protokollierung verwendeten Pfade und Namen ändern. Ich habe hier nur ein Beispiel gemacht, das das Logfile in ~ speichert.

Wenn Sie beispielsweise möchten, dass das Skript diese Anzahl zu der Zeile hinzufügt, die Sie am Ende des Skripts hinzugefügt haben, können Sie zu Beginn des Skripts Folgendes tun:

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"

Und ändern Sie Ihre Zeile am Ende des Skripts in etwas, das auch diese Informationen enthält:

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

Ein anderer Versuch

Eine separate Zählerdatei hat Nachteile:

  • Es dauert 4096 Bytes (oder was auch immer Ihre Blockgröße ist) für jede Zählerdatei.
  • Sie müssen den Namen der Datei im Bash-Skript nachschlagen und dann die Datei öffnen, um die Anzahl zu sehen.
  • Es gibt keine Dateisperrung (bei anderen Antworten), daher ist es möglich, dass zwei Personen den Zähler genau zur gleichen Zeit aktualisieren (in den Kommentaren unter der Antwort von Byte Commander als Race Condition bezeichnet).

Diese Antwort beseitigt also eine separate Zählerdatei und fügt die Zählung in das Bash-Skript selbst ein!

  • Durch das Einfügen des Zählers in das Bash-Skript selbst können Sie in Ihrem Skript selbst sehen, wie oft es ausgeführt wurde.
  • Durch die Verwendung von flock wird sichergestellt, dass für einen kurzen Moment nicht zwei Benutzer gleichzeitig das Skript ausführen können.
  • Da der Name der Zählerdatei nicht fest codiert ist, müssen Sie den Code für verschiedene Skripte nicht ändern. Sie können ihn einfach als Quelle verwenden oder aus einer Stub-/Boilerplate-Datei kopieren und einfügen.

Der Code

#!/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

Ein anderer Ansatz unter Verwendung einer Protokolldatei

Ähnlich der Antwort von Videonauth habe ich hier eine Antwort auf eine Protokolldatei geschrieben: Bash-Skript zur Aufrechterhaltung des Prüfpfads/Protokolls der zugegriffenen Dateien um jedes Mal zu protokollieren, wenn Root-Kräfte mit gedit oder nautilus verwendet wurden .

Der Haken ist jedoch, dass das Skript nicht gksu verwendet, sondern gsu heißt und pkexec die "moderne" Art und Weise aufruft, Sudo in der GUI zu verwenden.

Ein weiterer Vorteil ist, dass nicht nur jedes Mal angegeben wird, wann Root-Potenzen mit gedit verwendet wurden, sondern auch der bearbeitete Dateiname protokolliert wird. Hier ist der Code.

~/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

Inhalt der Protokolldatei gsu-log-file-for-geditnach ein paar Änderungen:

__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"
1