Sunday, November 24, 2019

Was für ein Shebang (Für einen Cronjob)!?

Ich nutze folgenden Shebang in einigen Skripten, die ich als Cronjob starte:

#!/usr/bin/env -S chronic flock -n .lockfile.lock xvfb-run -a sh

Dieser Shebang verhindert doppelte Ausführung mittels Lockfile und erzeugt nur im Fehlerfall eine Ausgabe.

  • chronic: run program quietly unless it fails
  • flock: run program with a lock held
  • xvfb-run: run program in a virtual X server environment

Mit chronic(1) aus dem Paket moreutils, welches zusätzliche Unix-Hilfsprogramme bietet, wird das handeln des Quiet, Verbose- und Debug-Flags i.d.R. hinfällig. Denn es unterdrückt die Ausgabe und erzeugt nur im Fehlerfall die Ausgabe.

Das flock(1) richtet eine Sperrungen mittels Lockfile für das Skript ein und wartet solange, bis eine bereits laufende Instanz beendet ist. Mit dem Schalter -n beendet sich das Skript, wenn bereits eine Instanz läuft. Wird das Lockfile relativ angegeben, gilt es in der Crontab relativ zu HOME. Das flock(1) ist aus dem Paket util-linux, welches essential ist und hat das lckdo(1) aus moreutils abgelöst. In der Manpage zu lckdo(1) findet sich der Hinweis:

Now that util-linux contains a similar command named flock, lckdo is deprecated, and will be removed from some future version of moreutils.

Das xvfb-run(1) braucht es natürlich nur, wenn X benötigt wird.

Um den Shebang zu umgehen, z.B. beim testen, kann das Skript auch explizit mit dem Interpreter gestartet werden:

sh path/to/script.sh

Das alles funkioniert z.B. auch für Perl-Skripte.

PS: Vorher hatte ich hier lckdo(1) genutzt. Also vielen Dank an Flo, der in den Kommentaren darauf hinwies.

Friday, August 9, 2019

Doppelte Zeilen aus unsortierten Dateien entfernen

Das Kommando uniq(1) aus den Coreutils entfernt wiederholt auftretende Zeilen aus sortierten Dateien. D.h. die Zeilen müssen vorher z.B. mit sort(1) sortiert werden und die Daten verlieren durch die Sortierung die Reihenfolge. Soll die Reihenfolge aber erhalten bleiben, findet sich für das Problem keine Lösung in den Coreutils.

Die Lösung: Folgendes AWK entfernt wiederholt auftretende Zeilen in einer unsortierten Datei, so das in der Ausgabe keine Zeile doppelt vorhanden ist, wobei aber die ursprüngliche Reihenfolge der Zeilen erhalten bleibt, denn es ist keine Voraussetzung, dass die Eingabe sortiert sein muss:

awk '!a[$0]++' path/to/file

Nur bestimmte Spalten berücksichtigen

Sollen nur bestimmte Spalten berücksichtigt werden, gibt man die Position der Spalten entsprechend an: Für die erste Spalte awk '!a[$1]++' path/to/file, für die zweite Spalte awk '!a[$2]++' path/to/file usw. usf. Es können auch mehrere Spalten angegeben werden: Hier ein Beispiel für die zweite, dritte und fünfte Spalte: awk '!a[$2$3$5]++' path/to/file.

PS: Der Spaltentrenner kann mit dem AWK Schalter -F angegeben werden.

Doppelte Zeilen aus sortierten Dateien entfernen

Der Vollständigkeit halber noch die gängige Lösung, um doppelte Zeilen aus sortierten Dateien zu entfernen.

sort -u path/to/file

Oder wenn doch Eingenschaften aus uniq(1) benötigt werden:

sort path/to/file | uniq

Sunday, November 4, 2018

LibreOffice: Inhalts- und Stichwortverzeichnis automatisch aktualisieren

Die Verzeichnisse wie Inhalts- oder Stichwortverzeichnis in einem LibreOffice Writer Dokument, können beim Speichern oder Exportieren automatisch aktualisiert werden. Dazu verknüpft man folgendes Makro an die Ereignisse Dokument speichern und Dokumentkopie speichern oder exportieren.

Den Dialog dazu findet man unter Extras/Makros/Bearbeiten und für das Zuweisen unter Extras/Makros/Verwalten/LibreOffice Basic/Zuweisen.

loMakroDocumentIndexesUpdate1.png

loMakroDocumentIndexesUpdate2.png

Das Makro

REM  *****  BASIC  *****

Sub Main

End Sub	

REM Verzeichnisse aktualisieren
REM Siehe auch: https://www.oooforum.de/viewtopic.php?f=18&t=70890
REM             https://forum.openoffice.org/en/forum/viewtopic.php?f=20&t=2557
Sub DocumentUpdateIndexes
	On Error Goto ErrorHandler ' Enables error handling

	oIndexes = ThisComponent.getDocumentIndexes()
	for i = 0 to oIndexes.getCount () - 1
		oIndexes (i).update
	next

	' Label
	ErrorHandler:
End Sub

Sub DokumentSpeichern
	DocumentUpdateIndexes
End Sub

Sub DokumentkopieSpeichernOderExportieren
	DocumentUpdateIndexes
End Sub

Friday, August 4, 2017

Perl: Zufälligen Schlüssel/Key eines Hash

Auf einen zufälligen Schlüssel eines Hash, kann man mit der Funktion keys zugreifen. Die Funktion keys, gibt alle Schlüssel eines Hash, als Liste zurück, von der dann ein Wert zufällig abgefragt werden kann:

#!/usr/bin/perl

my %alphabet = (
    A => 1,
    B => 2,
    C => 3,
    D => 4,
    E => 5,
    F => 6,
    G => 7,
    H => 8,
    I => 9,
    J => 10,
    K => 11,
    L => 12,
    M => 13,
    N => 14,
    O => 15,
    P => 16,
    Q => 17,
    R => 18,
    S => 19,
    T => 20,
    U => 21,
    V => 22,
    W => 23,
    X => 24,
    Y => 25,
    Z => 26,
);

my @keys = keys %alphabet;

# zufälliger Key

my $buchstabe = $keys[ rand @keys ];
my $position  = $alphabet{$buchstabe};

printf "Der Buchstabe %s, ist der %i. im Alphabet.\n", $buchstabe, $position;

Es ist auch möglich, direkt auf einen zufälligen Wert eines Hash zuzugreifen. Das funktioniert, analog mit der Funktion values:

my @values = values %alphabet;
print $values[ rand @values ] . "\n";

PS: In den Kommentaren, hat Christian eine etwas schnellere Möglichkeit aufgezeigt:

my @list = %alphabet;
my $random_key = $list[(1|rand@list) -1];
my $random_val = $list[1|rand@list];

Das bitweise ODER mit 1 sorgt dafür, dass das letzte Bit des Ergebnisses von rand auf 1 gesetzt wird. Dadurch entsteht immer eine ungerade Zahl (1|0 => 1, 1|1 => 1, 1|2 => 3, 1|3 => 3, …). Es wird also nur auf ungerade Indizes des Arrays zugegriffen, wo in diesem Fall die Values abgelegt sind. Da dabei immer eine Zahl größer 0 generiert wird, kann mit einem einfachen -1 immer auf die geraden Indizes mit den Keys zugegriffen werden.

Thursday, June 8, 2017

Perl: Dateien von I2P Eepsites und/oder Tor hidden services downloaden

Ich programmiere einen Feedreader.

Dieser hat nun auch das Proxy Attribut des Perl Moduls LWP::UserAgent implementiert, um z.B. Feeds von I2P Eepsites und/oder Tor hidden services abonnieren zu können.

Wie man mittels der Perl Module URI::Fetch und LWP::UserAgent, eine solche URL downloadet, will ich hier kurz skizzieren:

#!/usr/bin/env perl

use URI;
use URI::Fetch;

use LWP::UserAgent;
use LWP::Protocol::socks;

my $uri = URI->new("http://example.i2p/");

my $ua = LWP::UserAgent->new();
$ua->proxy( "http", "http://localhost:4444" );

my $response = URI::Fetch->fetch( $uri, UserAgent => $ua )
  || die URI::Fetch->errstr;

print $response->content;

Eepsite: Die (Pseudo-)Top-Level-Domain .i2p

Es wird mittels $ua->proxy( "http", "http://localhost:4444" ); der zu verwendende HTTP-Proxy gesetzt. Analog funktioniert das so auch mit anderen Protokollen, wie z.B. HTTPS, FTP usw.

Siehe auch: http://search.cpan.org/perldoc/LWP::UserAgent.

Tor hidden services: Die (Pseudo-)Top-Level-Domain .onion

Für das SOCKS-Protokoll, muss zusätzlich das Modul LWP::Protocol::socks eingebunden werden.

Um bspw. eine Datei von einem Tor hidden service downzuloaden, muss $ua->proxy( "http", "socks://localhost:9050" ); gesetzt werden.

Siehe auch: http://search.cpan.org/perldoc/LWP::Protocol::socks.