phpMyAdmin – Excel-CSV mit Zeilenumbrüchen importieren

Wenn man in Excel eine Tabelle als CSV exportiert, die in den Zellen Zeilenumbrüche enthält, so sind diese Zeilenumbrüche nur als Linefeeds (LF, 0x10) in der CSV enthalten. Die Datensätze (Zeilen) sind mit Windows-üblichen „Carriage Return/Linefeed“ (CRLF, 0x13 0x10) separiert.

Will man eine solche Datei per phpMyAdmin in eine Datenbank importieren, so muss man als Import-Format „CSV using LOAD DATA“ wählen und bei „Zeilen enden auf:“ statt „auto“ \r\n eintragen.

Beim einfachen Format „CSV“ funktioniert dort nur „auto“, welches auch die LFs als Datensatztrenner interpretiert und den Import fehlschlagen lässt.

Hintergrund: Bei „CSV“ wird wohl der phpMyAdmin-interne Parser benutzt, der nichts anderes als „auto“ versteht. Bei „CSV using LOAD DATA“ macht MySQL den Job, phpMyAdmin erzeugt ein SQL-Statement in der Art: LOAD DATA LOCAL INFILE '/tmp/phpFzMK4B' INTO TABLE `stoerChrono` FIELDS TERMINATED BY ';' ENCLOSED BY '\"' ESCAPED BY '\\' LINES TERMINATED BY '\r\n' IGNORE 1 LINES;

Dateien mit scp und Key, aber ohne Passphrase übertragen

Man kann scp ganz wunderbar dazu benutzen, um Dateien auf einen anderen Rechner zu übertragen. Allerdings muss man i.d.R. jedes mal das Passwort des Zielbenutzers angeben. Das ist für automatisierte Prozesse ziemlich unpraktisch.
Nun kann man aber auch einen SSH-Key ohne Passphrase erzeugen und diesen auf dem Zielrechner in der authorized_keys des entsprechenden Nutzers hinterlegen. Dann kann zwar nur derjenige User, der im Besitz des privaten Schlüssels ist, ohne Passwort/Passphrase auf diesen Rechner zugreifen, aber ganz so sicher ist das nicht. Allerdings kann man SSH-Keys auch mit einem sog. „forced Command“ verknüpfen, so dass mit diesem Key nur das definierte Kommando ausgeführt wird, unabhängig davon, was auf der Kommandozeile angegeben wurde. Dies geschieht in der authorized_keys auf dem Zielrechner, in dem man in der Zeile mit den entspr. Key vor diesem das gewünschte Kommando angibt, i.d.R. mit weiteren nützlichen Parametern:

no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty,command="mache_nur_was_ich_will" ssh-rsa AAAAB3NzaC…

Aber wie muss das Kommando auf der Zielseite bei scp nun aussehen? Das lässt sich herausfinden, in dem man ein normalen scp-Befehl mit den Debug-Parameter -v absetzt. In der Ausgabe findet man u.a. dann so was wie (wenn nicht: siehe unten):

debug1: Sending command: scp -v -t myfile.txt

Hier taucht der undokumentierte scp-Parameter -t auf, der auch nur vom Programm auf der Zielseite verwendet wird. Wenn wir also das folgenden in der authorized_keys angeben, können wir mit den entspr. Key Dateien in das Verzeichnis /var/local/Backups kopieren – mehr nicht!

no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty,command="scp -t /var/local/Backups/" ssh-rsa AAAAB3NzaC…

Aber das funktioniert nicht …

Es kann passieren, dass die Verbindung zwar aufgebaut wird, danach aber nichts mehr passiert. Die Verbindung „hängt“, es findet keine Datenübertagung statt.

Die Ursache ist, dass scp ab Version 9.0 standardmäßig das SFTP-Protokoll benutzen. Man erkennt es daran, dass in der oben erwähnten Debug-Ausgabe nicht das erwartete scp -v -t … steht, sondern:

debug1: Sending subsystem: sftp

Man muss scp auf der aufrufenden Seite also mit dem Parameter –O (großes O) dazu zwingen, das SCP-Protokoll zu verwenden.


Siehe auch: https://serverfault.com/a/88864

Git – Bereits eingecheckte Dateien ignorieren

Wenn man eine Datei, die schon mal eingecheckt wurde, ignorieren will, geht das nicht ohne weiteres per .gitignore, denn .gitignore wirkt nur auf neue Dateien.

Daher müsste man die Datei(en) aus dem Repo löschen, was mit git rm –cached myfile.log geht. Die Datei bleibt in Working-Dir erhalten. Allerdings wird die Datei dann in einem anderen Working-Dir gelöscht, wenn man dort ein git pull macht! Daher ist das u.U. keine so gute Lösung.

Lokal kann man die Datei mit

git update-index --skip-worktree myfile.log

ignorieren. Das wird aber nicht in das Upstream-Repo übertragen; Das ist eine rein lokale Angelegenheit und muss ggf. in den anderen Workdirs ebenso gemacht werden.

Bei vielen zu ignorierenden Dateien kann man

git update-index --skip-worktree temp/myfile*

oder ggf.

git update-index --skip-worktree temp/myfile{1..7}.log 

verwenden. git update-index funktioniert übrigens nicht bei Dateien, die mit einem Punkt (.) beginnen!

Siehe auch die Diskussionen und Kommentare in

Aktuellste/älteste Dateien in einem Verzeichniszweig ermitteln

Will man in einem einzelnen Verzeichnis die aktuellsten (oder ältesten) Dateien finden, geht das mit den Sortierungs-Optionen von ls:

ls -tr | tail

zeigt die neusten Dateien an (aktuellste am Ende). Umgekehrt für die ältesten:

ls -t | tail

Will (oder muss 😉 ) man aber eine ganze Verzeichnisstruktur durchsuchen, geht das mit ls nicht. Hier muss man find und stat zu Hilfe nehmen:

find . -exec stat --format '%y %n' {} ; | sort | tail

So erhält man die neusten Dateien, z.B.:

2010-11-08 10:55:49.000000000 +0100 ./javascript/selectm.js
2010-11-08 10:55:59.000000000 +0100 ./Formulareinm.php
2010-11-08 10:57:16.000000000 +0100 ./Eintragenm.php
2012-04-02 10:52:40.000000000 +0200 ./nop.html
2012-04-02 11:02:00.000000000 +0200 ./.htaccess
2012-07-10 17:06:16.000000000 +0200 ./phpinclude/autoabfrage.inc
2012-07-10 17:13:34.000000000 +0200 ./phpinclude/ergebnis.inc
2014-03-04 16:17:58.000000000 +0100 ./phpinclude
2018-10-23 10:22:02.000000000 +0200 ./phpinclude/send_infoMail.inc
2019-04-26 11:51:36.000000000 +0200 .

Will man die ältesten, so muss man die Reihenfolge mit den Sort-Parameter -r umkehren:

find . -exec stat --format '%y %n' {} ; | sort -r | tail

Zwei Output-Streams zusammenfassen

In einem Tweet von climagic gab es einen Tipp, wie man die Ausgabe von zwei (oder mehreren) Programmen in der Shell zusammenfassen und als Eingabe für ein anderes Kommando nutzen kann:

{ find /one; find /two; } | tar zcvf one-and-two.tar.gz -T -

Das kann nicht nur dazu dienen, um mehrere verschiedene Verzeichnisse zu taren (mit -T - werden die zu archivierenden Dateinamen über die Std-Eingabe übermittelt), man kann beispielsweise auch mehrere greps zusammenfassen.

Shell: Zeitstempel in die Ausgabe einfügen

Loggt man innerhalb eines Shellskripts in eine Logdatei, so ist es häufig sinnvoll, den Einträgen einen Zeitstempel voran zu stellen. Das macht das kleine Tool ts (von Timestamp) ganz einfach:

echo "Eine ganz wichtige Meldung" | ts '[%Y-%m-%d %H:%M:%S]' >> meine-Logdatei

Das Tool ts ist Bestandteil von moreutils, das Paket muss also ggf. erst installiert werden. Will/kann man das nicht, kann man sich auch mit awk, perl und anderen Tools helfen. Wie das geht, ist in einem Post auf StackExchange erklärt (wo ich auch den Tipp mit ts her habe).

Dateien mit find suchen und verschieben

Will man Dateien, die sich per find finden lassen, in ein anderes Verzeichnis verschieben, gelingt das nur mit ein paar kleinen Tricks.

Beispielsweise sollen in einem Doku-Wiki-Verzeichnis alle zu foo.txt gehörenden Dateien in das Unterverzeichnis bar verschoben werden (wobei die entspr. bar-Verzeichnisse bereits existieren). Man denk natürlich zunächst an so was:

find . -name "foo*" -exec mv "{} `dirname {}`/bar/`basename {}`" ;

Leider funktioniert das so nicht, weil dirname {} nur . (einen Punkt) zurück liefert.

Nun kann man dirname ja durch ${VAR%/*} ersetzen, aber das funktioniert mit find nur in einer Sub-Shell:

find . -name "foo*" -ok sh -c 'mv -v $0 ${0%/*}/bar/${0##*/}' {} ;

Das funktioniert und dank -ok statt -exec fragt find vor jeder Befehlsausführung, ob das tatsächlich gemacht werden soll. Dabei fällt dann auf, dass find auch gerne die gerade eben verschobene Datei nochmal verschieben möchte. Um das zu verhindern, muss der Zielpfad ausgeklammert werden. Das gelingt so:

find . -name "foo*" -not -path '*/bar/*' -ok sh -c 'mv -v $0 ${0%/*}/bar/${0##*/}' {} ;

In einem Tar-Archiv die größten Dateien ermitteln

Wie in „Tar-Archive vergleichen“ beschrieben, werden Backups manchmal plötzlich größer. Wenn man nun einfach wissen möchte, welches denn die größten Dateien in dem Archiv sind, geht das ohne viel Aufwand mit

tar tvf 20141117.tgz | sed 's/ \{1,\}/\t/g' | cut -f 3,6 | sort -n | tail

Hierbei werden durch sed alle aufeinanderfolgende Leerzeichen durch ein Tab-Zeichen ersetzt, so dass dann die relevanten Spalten per cut ausgeschnitten werden können. Anschließend wird nummerisch sortiert und mit tail die Ausgabe begrenzt.

Tar gibt die Größe in Bytes aus. Leider kenne ich keine Option, mit welcher sich bei tar die Anzeige der Größe beeinflussen lässt.

Prüfen, ob es im Verzeichnis neue Dateien gibt

Neulich hatte ich die Aufgabe zu prüfen, ob es in einer Reihe von Unterverzeichnissen aktuelle Dateien gibt (d.h.: ob die Backups tatsächlich was übertragen hatten und wo es nicht funktioniert hatte). Die zu prüfenden Verzeichnisse waren allesamt Unterverzeichnisse von netdir, so dass man gut mit einer For-Schleife arbeiten kann:

cd netdir
for dir in `ls -1`
do
   echo $dir
   cd $dir > /dev/null || exit 99
   res=`find . -mtime -2 -type f`
   if [ -z "$res" ]
   then
      echo "$dir - nichts aktuelles gefunden!"
   fi
   cd ..
done

Wenn es also in dem zu prüfenden Verzeichnis keine Datei gibt, die jünger als zwei Tage ist, wird „nichts aktuelles gefunden!“ gemeldet.