rsync und Leerzeichen

Atelis

Akerö
Registriert
01.03.07
Beiträge
1.835
habe folgendes skript und 2 probleme:

Code:
zahlen[${#zahlen[*]}]="~/Ordner"
zahlen[${#zahlen[*]}]="~/Ordner 2"
zahlen[${#zahlen[*]}]="~/Ordner 3"
echo ${zahlen[@]}
echo
for i in ${zahlen[@]}
do
  echo
  echo "Backup von \""$i"\" erstellen..."
  echo "--------------------------------"
  rsync -avpt --stats --delete $i "/Volumes/LaCie 160 HD/Backup-Ordner/"
done

1. rsync trennt den einzelnen ordner beim leerzeichen (er sucht nach einem "ordner" und dann nach "2")
2. aus "~/Ordner" wird "/Users/atelis/~/Ordner" - warum?
 

stk

Grünapfel
Registriert
05.01.04
Beiträge
7.141
Moin,

weil Du Leer- und Sonderzeichen mit vorangestelltem \ maskieren mußt. Aus einem einfachen Leerzeichen wird: "\ "

Gruß Stefan
 

Atelis

Akerö
Registriert
01.03.07
Beiträge
1.835
weil Du Leer- und Sonderzeichen mit vorangestelltem \ maskieren mußt. Aus einem einfachen Leerzeichen wird: "\ "

nein, kommt das gleiche bei raus...

es hat irgendwas mit dem setzen der variablen zu tun: egal ob
Code:
i=/Users/atelis/Neuer\ Testordner
oder
Code:
i="/Users/atelis/Neuer Testordner"
der befehl
Code:
rsync -avpt --stats --delete $i "/Volumes/LaCie 160 HD/Backup-Ordner/"
trennt am leerzeichen... :( es kommt immer diese fehlermeldung:
Code:
building file list ... rsync: link_stat "/Users/atelis/Neuer" failed: No such file or directory (2)
rsync: link_stat "/Users/atelis/Testordner" failed: No such file or directory (2)
done
 

Rastafari

deaktivierter Benutzer
Registriert
10.03.05
Beiträge
18.150
Code:
# der befehl...
rsync -avpt --stats --delete $i "/Volumes/LaCie 160 HD/Backup-Ordner/"
# ...trennt am leerzeichen...
Aber der Befehl...
Code:
rsync -avpt --stats --delete [COLOR="Blue"]"[/COLOR]$i[COLOR="Blue"]"[/COLOR] "/Volumes/LaCie 160 HD/Backup-Ordner/"
...tut das nicht.
 

pepi

Cellini
Registriert
03.09.05
Beiträge
8.740
Dann schreib "$i" in Dein rsync Statement.

Was soll das ganze Ding eigentlich tun und wie sieht der Rest aus? Reine Neugierde weil ich Serverbackups mit meinem eigenen Rsync basierten Skript erledige und immer gerne neuen Input dazu habe.
Gruß Pepi

Hätte ich vorm Posten doch nochmal reloaden sollen... Rastafari war schneller :)
 

Atelis

Akerö
Registriert
01.03.07
Beiträge
1.835
danke! die anführungsstriche waren es... ;) und wen es interessiert - hier mein script (gibt mit sicherheit noch verbesserungsmöglichkeiten):

Code:
######################################################################################
########                                                                      ########
####                                     Backup                                   ####
########                                                                      ########
######################################################################################

Sichere_Ordner ()
{
  quelle[${#quelle[*]}]=$1
  ziel[${#ziel[*]}]=$2
}

Zeit ()
{
  sekunden=$(($2 - $1))
  echo $sekunden
}

######################################################################################


# Zu sichernde Ordner ---------------------------------------------------------------
Sichere_Ordner $HOME"/Documents" "/Volumes/LaCie 160 HD/Backup-Ordner/"
Sichere_Ordner $HOME"/Pictures" "/Volumes/LaCie 160 HD/Backup-Ordner/"
Sichere_Ordner $HOME"/Movies" "/Volumes/LaCie 160 HD/Backup-Ordner/"
Sichere_Ordner $HOME"/Music" "/Volumes/LaCie 160 HD/Backup-Ordner/"
Sichere_Ordner $HOME"/Projekte" "/Volumes/LaCie 160 HD/Backup-Ordner/"
Sichere_Ordner $HOME"/Library/" "/Volumes/LaCie 160 HD/Backup-Ordner/Private Library/"
Sichere_Ordner "/Library/" "/Volumes/LaCie 160 HD/Backup-Ordner/Globale Library/"
Sichere_Ordner "/Volumes/Windows HD/Dokumente und Einstellungen/Jakob" "/Volumes/LaCie 160 HD/Backup-Ordner/Windows HD/"
Sichere_Ordner "/Volumes/Windows HD/Dokumente und Einstellungen/All Users" "/Volumes/LaCie 160 HD/Backup-Ordner/Windows HD/"



######################################################################################

cd /
clear

if [ -d '/Volumes/LaCie 160 HD' ]
then
  echo
  timestamp_start=`date +%s`
  echo "Backup am" `date +%d.%m.%Y`", um" `date +%H:%M:%S` "Uhr gestartet"
  echo "==========================================================================="
  echo
  echo "Mounten von \"Windows HD\"..."
  diskutil mount disk0s3 > /dev/null
  echo
  echo
  i=0
  while [ $i -lt ${#quelle[*]} ]
  do
    echo
    echo "Backup von \"${quelle[$i]}\" erstellen..."
    echo "---------------------------------------------------------------------------"
    rsync -avpt --stats --delete "${quelle[$i]}" "${ziel[$i]}"
    echo
    echo "---------------------------------------------------------------------------"
    echo
    echo
    echo
    i=$(($i + 1))
  done
  echo "Auswerfen von \"Windows HD\"..."
  diskutil unmount disk0s3 > /dev/null
  echo
  echo
  echo "==========================================================================="
  timestamp_stopp=`date +%s`
  echo "Backup am" `date +%d.%m.%Y`", um" `date +%H:%M:%S` "Uhr beendet"
  echo
  echo "Zeit:" `Zeit $timestamp_start $timestamp_stopp` "Sek."
  echo
  echo
else
  echo "\"LaCie 160 HD\" ist nicht gemountet!"
  echo
  echo
fi
exit
 
Zuletzt bearbeitet:

pepi

Cellini
Registriert
03.09.05
Beiträge
8.740
Verbesserungsmöglichkeiten gibt es immer…

danke! die anführungsstriche waren es... ;) und wen es interessiert - hier mein script (gibt mit sicherheit noch verbesserungsmöglichkeiten):

Code:
#[...] snipped...

# Zu sichernde Ordner ---------------------------------------------------------------
Sichere_Ordner $HOME"/Documents" "/Volumes/LaCie 160 HD/Backup-Ordner/"
Sichere_Ordner $HOME"/Pictures" "/Volumes/LaCie 160 HD/Backup-Ordner/"

#[...] snipped...

  echo "Mounten von \"Windows HD\"..."
  diskutil mount disk0s3 > /dev/null

#[...] snipped...

    rsync -avpt --stats --delete "${quelle[$i]}" "${ziel[$i]}"

#[...] snipped...

Ja, Verbesserungsmöglichkeiten gibt es immer. :) Ich bin inzwischen bei Build 68 meines Backup Skriptes mit dem 2. Branch... Fertig wird es wohl nie, aber immer besser.

Sind ein paar interessante Ansätze drinnen in Deinem Skript und gehobene Bash 2 Syntax. :)

Was mir abgeht, bzw. wo ich verbesserungspotential sehe.
SheBang! Oder hast das nur nicht mitgepostet?

Warum führst Du nicht eine Variabel $backup_disk ein?
backup_disk="LaCie 160 HD"
backup_path="Mein toller Backup Ordner"
mount_point="/Volumes"
backup_target="$mount_point/$backup_disk/$backup_path"

rsync $rsync_options $backup_source $backup_target

So kann man einfach mal die Pade oder sonstiges ändern und muß nur eine Variable ausbessern.

Beim rsync fehlt meiner Ansicht nach die Option --extended-attributes

Du rufst rsync nicht über einen absoluten Pad auf, so kannst Du nicht sicher sein, daß auch das von Dir gewünschte rsync verwendet wird. Wenn Du fink oder DarwinPorts oder Emerge verwendest hast Du mit Sicherheit mehrere rsyncs auf der HD. Je nach $PATH kann das auch mal schiefgehen.


Warum schreibst Du die Quell Ordner nicht in eine Variable oder ein Array hinein und iterierst mit einer Schleife drüber? Deine anderen Schleifenkonstruktionen sind ja auch recht gut gebaut?

Wenn ich mich recht erinnere soll man beim Ziel bei rsync keinen trailing Slash verwenden.

Bis auf die Überprüfung ob Dein Ziel-Volume vorhanden ist (Großes plus dafür, das geht sonst böööse ins Auge wenn die HD mal fehlt) hast Du keine Fehlerüberprüfungen drinnen. Du gibst zwar aus, daß Dein Backup von Quelle-Blah fertig ist, aber schaust nicht nach ob das auch gut gegangen ist. Noch schlimmer, Du überprüfst nicht ob Du Dein Ziel-Volume erfolgreich mounten konntest sondern gehst davon aus, daß es geklappt hat. Das führt eigentlich die Überprüfung ad Absurdum.

Ein log geht mir auch noch ab, aber das bin wohl ich. :)

Gehe ich recht in der Annahme, daß Du Dein Skript immer manuell aufrufst?
Gruß Pepi
 
Zuletzt bearbeitet:

Atelis

Akerö
Registriert
01.03.07
Beiträge
1.835
ui, danke für deine sehr ausführliche stellungsnahme zu meinem skript - mache erste seit gestern richtig was mit bash-skripten - sonst waren es immer nur einzelne zeilen...

SheBang! Oder hast das nur nicht mitgepostet?

was?

Warum führst Du nicht eine Variabel $backup_disk ein?

habe ich jetzt auch gemacht und sieht so aus:

Code:
# Ziel -------------------------------------------------------------------------------
zielordner="/Volumes/LaCie 160 HD/Backup-Ordner/"


# Zu sichernde Ordner ----------------------------------------------------------------
Sichere_Ordner $HOME"/Documents" "$zielordner"
Sichere_Ordner $HOME"/Pictures" "$zielordner"
Sichere_Ordner $HOME"/Movies" "$zielordner"
Sichere_Ordner $HOME"/Music" "$zielordner"
Sichere_Ordner $HOME"/Projekte" "$zielordner"
Sichere_Ordner $HOME"/Library/" "${zielordner}Private Library/"
Sichere_Ordner "/Library/" "${zielordner}Globale Library/"
Sichere_Ordner "/Volumes/Windows HD/Dokumente und Einstellungen/Jakob" "${zielordner}Windows HD/"
Sichere_Ordner "/Volumes/Windows HD/Dokumente und Einstellungen/All Users" "${zielordner}Windows HD/"

# rsync Optionen ---------------------------------------------------------------------
rsync_optionen="-avpt --stats --delete --extended-attributes"

Beim rsync fehlt meiner Ansicht nach die Option --extended-attributes

ich hab gelesen, dass es mit dem parameter probleme gibt, da rsync dann immer zu viele dateien kopiert - werde es aber mal ausprobieren...
EDIT: wie ich es auch gelesen hatte: es werden jedes mal alle resourcefork dateien wieder neu kopiert... was nun? weglassen?

Du rufst rsync nicht über einen absoluten Pad auf, ...

meinst du ein "#!/bin/bash" am anfang? dann hab ich das jetzt...

Warum schreibst Du die Quell Ordner nicht in eine Variable oder ein Array hinein und iterierst mit einer Schleife drüber? Deine anderen Schleifenkonstruktionen sind ja auch recht gut gebaut?

ich wollte erst 2-dimensionale arrays machen, habe aber nicht so schnell rausgefunden, wie das genau geht. weiß, dass es unsauber ist, aber habe dann einfach 2 arrays genommen - die elemente der einzelnen arrays gehören dann dementsprechend zusammen...

Wenn ich mich recht erinnere soll man beim Ziel bei rsync keinen trailing Slash verwenden.

ich habe nur gefunden, dass es egal wäre...? oder weißt du mehr?

Bis auf die Überprüfung ob Dein Ziel-Volume vorhanden ist (Großes plus dafür, das geht sonst böööse ins Auge wenn die HD mal fehlt) hast Du keine Fehlerüberprüfungen drinnen. Du gibst zwar aus, daß Dein Backup von Quelle-Blah fertig ist, aber schaust nicht nach ob das auch gut gegangen ist.

das liegt daran, dass ich immer fehler habe... ;) und zwar zugriffsrechte-fehler:

sync: opendir "/Library/Logs/Console/0" failed: Permission denied (13)
rsync: opendir "/Library/Logs/Console/502" failed: Permission denied (13)

etc... ich will nicht mein admin-passwort eingeben müssen. wie kann ich solche fehler hinterher abfragen?

Gehe ich recht in der Annahme, daß Du Dein Skript immer manuell aufrufst?

ja, starte das skript mit dosomethingwhen, wenn dich die externe festplatte einschalte...

mal nebenbei: wie kann ich das skript unterbrechen und den benutzer zu der eingabe von ja oder nein bringen?
 

pepi

Cellini
Registriert
03.09.05
Beiträge
8.740
ui, danke für deine sehr ausführliche stellungsnahme zu meinem skript - mache erste seit gestern richtig was mit bash-skripten - sonst waren es immer nur einzelne zeilen...
Und ich dachte mir schon, daß es "zusammengestoppelt" wirkt. Als ob nicht alles aus ein und derselben Feder stammte. :) Die (()) Konstruktionen und die Schleifen passen einfach nicht zu den fehlenden Abstraktionsvariablen.
Literaturtip: Advanced Bash-Scripting Guide

Code:
# Snipped [...]
Sichere_Ordner $HOME"/Projekte" "$zielordner"
Sichere_Ordner $HOME"/Library/" "${zielordner}Private Library/"
Sichere_Ordner "/Library/" "${zielordner}Globale Library/"
Sichere_Ordner "/Volumes/Windows HD/Dokumente und Einstellungen/Jakob" "${zielordner}Windows HD/"
Du solltest Dich mit Dir selbst auf eine Syntax einigen. So ist das Kraut und Rüben. Einmal verwendest Du $zielordner, einmal ${zielordner}. Du solltest überall die idente Schreibweise verwenden. In dem Fall ${zielordner}. Das erleichtert im Zweielsfall ein Suchen und Ersetzen und man kann sicher sein, daß man alle erwischt. Es ist übrigens ein durchaus relevanter Unterschied zwischen /Library und /Library/. Bei letzterer Schreibweise wird im Ziel kein Ordner Library angelegt und nur dessen Inhalt gebackupped. Damit kopierst Du unter umständen die Inhalte zweier Ordner ineinander, was sie als Backup relativ wertlos macht und im blödesten Fall überschreibt einer den anderen.

ich hab gelesen, dass es mit dem parameter probleme gibt, da rsync dann immer zu viele dateien kopiert - werde es aber mal ausprobieren...
EDIT: wie ich es auch gelesen hatte: es werden jedes mal alle resourcefork dateien wieder neu kopiert... was nun? weglassen?
Besser als wenn garkeine Resourceforks übertragen werden und Dein Backup einige defekte oder unvollständige Dateien enthält sowie sämtliche Finder Kommentare verliert. Mit 10.4.9 sind solche Probleme zum Glück Vergangenheit, da Apple rsync wieder mal upgedatet hat.

meinst du ein "#!/bin/bash" am anfang? dann hab ich das jetzt...
Ja, das ist das Shebang mit dem jedes Shell Skript eingeleitet wird.

ich wollte erst 2-dimensionale arrays machen, habe aber nicht so schnell rausgefunden, wie das genau geht.[...]
Was wohl hauptsächlich daran liegt, daß bash2 nur eindimensionale Arrays unterstützt und man mehrdimensionale Arrays nur mit viel Aufwand simulieren kann. Das ist definitv Advanced Shell Scripting.

das liegt daran, dass ich immer fehler habe... ;) und zwar zugriffsrechte-fehler:

sync: opendir "/Library/Logs/Console/0" failed: Permission denied (13)
rsync: opendir "/Library/Logs/Console/502" failed: Permission denied (13)

etc... ich will nicht mein admin-passwort eingeben müssen. wie kann ich solche fehler hinterher abfragen?
Zwei Ansätze zu diesem "Problem".
Laß die Dinge von denen Du weist, daß Du sie nicht kopieren können wirst, bzw. die unsinnig sind einfach präventiv weg. Es ist nicht sinnvoll die Console Logs zu kopieren, ebenso wie es abartig wäre Ordner wie ~/Library/Caches zu sichern. Die brauchst Du definitiv nicht, wenn Du Dein Backup brauchst. Spar Dir daher die Zeit und den Speicherplatz. (siehe rsync excludes)
In /Library mußt Du damit rechnen als nicht-Admin Leseprobleme zu haben. da hilft nur, entweder als admin bzw. gar als root (mit sudo) Aufrufen, oder diese Dinge weglassen.

Der andere Ansatz wäre den Rückgabewert von rsync abzufragen. In der Variable $? steht immer der Exit Status des letzten Commands drinnen. Ist alles gut gegangen bekommst Du überlicherweise, und auch bei rsync eine 0 zurück. Somit kannst Du also festellen ob ein Fehler aufgetreten ist. Ein Problem bei rsync ist, daß ein Rückgabewert ungleich 0 nicht zwangsläufig bedeutet, daß nur dieser Fehler aufgetreten ist, sondern nur, daß dies der letzte Fehler war. Um alle Fehler zu finden müßte man den Kompletten Output von rsync in ein Log schreiben und dann dort rausparsen und bewerten. Eine Aufgabe der ich mich gerade mit meinem eigenen Skript widme. Einigermaßen Aufwändig kann ich Dir sagen.

ja, starte das skript mit dosomethingwhen, wenn dich die externe festplatte einschalte...

mal nebenbei: wie kann ich das skript unterbrechen und den benutzer zu der eingabe von ja oder nein bringen?
User Input im Terminal gibts mit read(1). Das setzt aber voraus, daß Dein Skript in einer interaktiven Shell läuft. Je nachdem wie DSW das Aufruft kann es sein, daß Du keine Möglichkeit hast als User auf die Frage zu antworten, wenn beispielsweise kein Terminal geöffnet wird.
Einfach wäre das für Dich so zu lösen, daß Du mit DSW ein AppleSkript aufrufst in dem der User gefragt wird ob er nun Backuppen möchte und wenn er ja sagt, dann aus AppleSkript heraus das ShellSkript aufrufen.
Gruß Pepi
 

Atelis

Akerö
Registriert
01.03.07
Beiträge
1.835
Es ist übrigens ein durchaus relevanter Unterschied zwischen /Library und /Library/.

ich weiß und es ist in diesem fall absicht, da es sonst 2 ordner mit dem namen library gegeben hätte...

Mit 10.4.9 sind solche Probleme zum Glück Vergangenheit, da Apple rsync wieder mal upgedatet hat.

welches problem gibt es nicht mehr? er kopiert immernoch jedes mal alles...

Einfach wäre das für Dich so zu lösen, daß Du mit DSW ein AppleSkript aufrufst in dem der User gefragt wird ob er nun Backuppen möchte und wenn er ja sagt, dann aus AppleSkript heraus das ShellSkript aufrufen.

das wird schon gemacht :-D ich wollte nur einbauen, dass der benutzer mit "j" und "n" order "y" und "n" auf einige fragen antworten kann, die das abbrechen nach fehler angehen... werde mir den read-befehl mal ansehen und ein bisschen googlen...
 

pepi

Cellini
Registriert
03.09.05
Beiträge
8.740
ich weiß und es ist in diesem fall absicht, da es sonst 2 ordner mit dem namen library gegeben hätte...

welches problem gibt es nicht mehr? er kopiert immernoch jedes mal alles...

das wird schon gemacht :-D ich wollte nur einbauen, dass der benutzer mit "j" und "n" order "y" und "n" auf einige fragen antworten kann, die das abbrechen nach fehler angehen... werde mir den read-befehl mal ansehen und ein bisschen googlen...

Was hältst Du von Unterordnern für Deine Backups? Also unterschiedliche Zielordner für Deine Quellen? Wobei ich immer noch nicht verstehe warum Du nicht gleich Dein ganzes $HOME ins Backup aufnimmst, aber Du magst Deine Gründe dafür haben.

Zu rsync sei der Artikel The State of rsync on Tiger empfohlen, auch wenn er Dich und mich nicht wirklich glücklich machen wird.

Zu read(1) gibts natürlich wie immer eine man page und auch im bereits verlinkten Bash Scripting Guide ist User Input ein Kapitel gewidmet.
Gruß Pepi
 

Atelis

Akerö
Registriert
01.03.07
Beiträge
1.835
Was hältst Du von Unterordnern für Deine Backups? Also unterschiedliche Zielordner für Deine Quellen?

hab ich doch gemacht? die beiden ordner von der "windows hd" kommen in einen entsprechenden ordner und die dateien der beiden library-ordner werden in einen andersnamigen ordner kopiert...

den befehl "read" hab ich schon gefunden und auch eingebaut - er behandelt den fall, dass die rechtereparatur mal scheintern sollte und fragt ab, ob das backup trotzdem gemacht werden soll...
 

Atelis

Akerö
Registriert
01.03.07
Beiträge
1.835
ein problem habe ich noch: will die exclude-parameter in eine variable schreiben und dann in den rsync-befehl einfügen...
sind die " den ' übergeordnet, oder wie ist das hier? folgendes funktioniert nämlich nicht:

Code:
"--exclude='Startmen?' --exclude='Eigene Dateien/Eigene Bilder/Hintergr?nde'"

und wenn ich nur " verwende, natürlich auch nicht...

aufgerufen wird die variable dann folgendermaßen:

Code:
rsync $rsync_optionen $ignorieren "${quelle[$i]}" "${ziel[$i]}"

wie mache ich das?
 

pepi

Cellini
Registriert
03.09.05
Beiträge
8.740
Single Quote sind stärker als Double Quotes. Innerhalb von Single Quotes gibt es keine Variablen Expansion, innert Double Quotes schon. Wenn Du das aber nicht brauchst, kannst Du grundsätzlich schachteln wie Du möchtest.

Viel besser wäre es wenn Du all Deine Excludes in eine eigene Datei tust und nur noch diese einbindest. So kannst Du ein neu gefundenes Exclude einfach dort eintragen und mußt nicht den Code Deines Skriptes verändern und Du kannst diese Datei auch kommentieren, damit Du später auch noch weist was und warum Du diese Datei ausnimmst.

Code:
ignorieren="--exclude-from=/pfad/zu/meiner/Datei/mit/den/exclusions"
Gruß Pepi
 

pepi

Cellini
Registriert
03.09.05
Beiträge
8.740
Gewöhn Dir doch Pfade mit Leerzeichen einfach ab! :-D

ignorieren='--exclude-from="/pfad mit nervige Leerzeichen/zu/meiner/Datei/mit/den/exclusions"'
Gruß Pepi
 

Atelis

Akerö
Registriert
01.03.07
Beiträge
1.835
will dich ja wirklich nicht ärgern, aber:

Code:
ignore='--exclude-from="/Volumes/LaCie 160 HD/Ex/Test.exclude"'
rsync $rsync_optionen "$ignore" "${quelle[$i]}" "${ziel[$i]}"

Code:
rsync: failed to open exclude file "/Volumes/LaCie 160 HD/Ex/Test.exclude": No such file or directory (2)

das verzeichnis existiert aber ganz sicher!
 
Zuletzt bearbeitet:

pepi

Cellini
Registriert
03.09.05
Beiträge
8.740
Ok, dann haben wir vielleicht doch ein Schachtelungsproblem mit den Quotes.

Bau bitte mal eine Zeile vor Deinem rsync folgendes ein und poste die Ausgabe davon.

Code:
echo ***
echo rsync $rsync_optionen "$ignore" "${quelle[$i]}" "${ziel[$i]}"
echo ***

Die *** sind nur dazu da, damit man es leichter findet, falls Dein Skript viel Text ausgibt.
Gruß Pepi