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.

Tar-Archive vergleichen

Ich sichere bestimmte Verzeichnisse von Rechnern täglich in Tar-Archiven (siehe auch „Verzeichnisse auf einen anderen Rechner übertragen“). Nun kommt es vor, dass diese Archive plötzlich oder auch mit der Zeit größer werden. Dann will man natürlich wissen, wieso. Um im ersten Schritt zu vermeiden, dass ich die Archive auspacken und dann vergleichen muss, lese ich den Inhalt zwei Tar-Dateien aus, bereite sie mittels sed auf und vergleiche sie mit diff:

tar tvf 20140822.tgz | sed 's/^([a-zA-Z-]{1,}) ([^[:blank:]]{1,}) {1,}([0-9]{1,}) .* (.*)$/4 3/' > 20140822.content 
tar tvf 20140901.tgz | sed 's/^([a-zA-Z-]{1,}) ([^[:blank:]]{1,}) {1,}([0-9]{1,}) .* (.*)$/4 3/' > 20140901.content
diff -y -W 200 --suppress-common-lines 20140822.content 20140901.content > 20140822vs20140901

Sofern sich nicht all zu viele Dateien geändert haben oder dazu gekommen sind, kann das Ergebnis schon erste Hinweise geben. Ansonsten muss man mit den üblichen Werkzeugen (z.B. grep) weiter filtern und analysieren.