So dumm, dass ich ungeduldig das folgende Skript auf meinem 19.04-Server verwendet habe, um eine Reihe von Videodateien in Ordner mit Präfixen zu verschieben:
dirs=(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z)
shopt -s nocasematch
for file in *
do
for dir in "${dirs[@]}"
do
if [ -d "$file" ]; then
echo 'this is a dir, skipping'
break
else
if [[ $file =~ ^[$dir] ]]; then
echo "----> $file moves into -> $dir <----"
mv "$file" "$dir"
break
fi
fi
done
done
Keine Ahnung, wo es schief gelaufen ist, aber anstatt die Dateien in Ordner zu verschieben, ging es zu einer einzelnen Ausgabe. Also:
----> a1.ts moves into -> A <----
----> a2.ts moves into -> A <----
----> a3.ts moves into -> A <----
----> a4.ts moves into -> A <----
----> a5.ts moves into -> A <----
----> c1.ts moves into -> C <----
----> c2.ts moves into -> C <----
----> c3.ts moves into -> C <----
----> c4.ts moves into -> C <----
----> c5.ts moves into -> C <----
Zum Glück habe ich den Vorgang gestoppt (STRG + C), sobald ich bemerkte, dass er nicht wie beabsichtigt lief und nicht den gesamten Ordner durchlief.
Jetzt habe ich also diese Dateien A
und C
, die weniger als ein GB groß sind, und wie es aussieht, handelt es sich um ein EINZIGES Video.
In der gesamten Festplattennutzung des Ordners selbst sind 50 GB nicht berücksichtigt, aber der gesamte Festplattenspeicher des Computers ist gleich geblieben. Lassen Sie mich denken, dass die Dateien nicht gelöscht werden?
Jede Hilfe geschätzt, danke :)
Bearbeiten: Die Dateien sind tatsächlich verschwunden, es bleibt nur die letzte zu schreibende Datei übrig. Es dauerte nur einige Zeit, bis die Informationen zur Datenträgerverwendung aktualisiert wurden. Moral der Geschichte, führen Sie Ihre Skripte zuvor auf Scheindateien aus!
quelle
A
,B
und so weiter existierte , bevor das Skript ausgeführt wird ? Wenn nicht, haben Sie die Dateien einfach umbenannt. Alle Dateien, mit denen Namen begonnen habena
oderA
in die umbenannt wurdeA
, sodass nur die zuletzt umbenannte Datei erhalten bleibt, die anderen werden überschrieben. Das Aufrufen einer Variablendir
erstellt kein Verzeichnis!mv "$file" "$dir/"
mit einem nachlaufenden/
; Wenn$dir
dies nicht der Fall ist,mv
wird ein Fehler angezeigt$file
, anstatt ihn in umzubenennen$dir
. Berücksichtigen Sie auchmv -i
undmv -n
. Und machen Sie immer einemkdir -p
vor dem Umzug, für ein gutes Maß.Antworten:
Ich denke, das ist das Problem: Sie sollten Verzeichnisse A, B, C ... Z erstellt haben. Wenn Sie dies getan haben, sollte der
mv
Befehl die Dateien in diese Verzeichnisse verschoben haben.Wenn nicht, verschiebt der
mv
Befehl die Dateien in Dateien mit den Namen A, B, C ... und ich denke, das haben Sie getan.Um das Shellscript sicherer zu machen, sollten Sie die Verzeichnisse erstellen (falls diese noch nicht vorhanden sind), bevor Sie mit dem Verschieben beginnen.
Wenn Sie möchten, dass die Dinge noch sicherer werden, können Sie sie auch
mv
mit dieser-i
Option verwendenquelle
touch
Wäre das Hinzufügen ein guter Ersatz,mkdir
um Konflikte zu vermeiden, wenn das Skript mehrmals ausgeführt wird?touch
Erstellt eine Datei, wenn der Name nicht vorhanden ist. In diesem Fall wird es also nicht das tun, was Sie wollen.mkdir -p
kann mit dem Skript mehrmals umgehen.mv
sicherer machen können, besteht darin, sich daran zu gewöhnen, dem Zielnamen einen abschließenden Schrägstrich hinzuzufügen, wenn das Ziel ein Verzeichnis ist, d. H.mv "$file" "$dir/"
@Sudodus hat bereits erklärt, was schief gelaufen ist, aber hier ist eine einfachere Version Ihres Skripts für das nächste Mal:
Erläuterung
for letter in {a..z}; do
: wird{a..z}
auf alle Kleinbuchstaben zwischena
und erweitertz
:Dies wird also alle Kleinbuchstaben durchlaufen und jeweils als speichern
$letter
.dir=${letter^}
: Die Syntax${var^^}
gibt den Inhalt der Variablen$var
mit dem ersten Zeichen in Großbuchstaben zurück (da dies nur ein Zeichen hat, ist das alles, was wir brauchen). Also, wenn$letter
jaa
, dann${letter^^}
istA
und daher$dir
die Großbuchstabenversion des Stroms ist$letter
.mkdir -p -- "$dir"
: Erstellen Sie das Verzeichnis. Wenn es bereits existiert, tun Sie nichts (-p
). Das--
kennzeichnet das Ende der Optionen und ist nützlich, um sich vor Namen zu schützen, die mit beginnen-
.mv -- "$letter"* "${letter^}"* "$dir"
: Verschieben Sie jede Datei (oder jedes Verzeichnis) zum entsprechenden Ziel.Das Problem dabei ist, dass es auch alle Verzeichnisse verschiebt, die Sie möglicherweise haben. Die Zielverzeichnisse werden nicht verschoben, da sie entweder noch nicht vorhanden sind oder Sie versuchen, sie in sich selbst zu verschieben, aber alle vorhandenen Verzeichnisse, die nicht das Zielverzeichnis sind, werden verschoben.
Wenn das ein Problem ist, müssen Sie Folgendes tun:
quelle
${letter^}
und${letter^^}
, und wenn sie identisch sind, warum${letter^^}
anstelle von verwenden$dir
?${var^}
nur den ersten Buchstaben${var^^}
groß , während alle Buchstaben groß geschrieben werden. Es macht hier keinen Unterschied, da es$letter
nur einen Buchstaben gibt.$dir
immv
Befehl einen Verzeichnis-Schrägstrich hinzufügen . (In seiner jetzigen Form wird es fehlschlagen, wenn eine Datei mit einem Großbuchstaben aus einem Buchstaben vorbesteht)Anstatt jede Datei mit einem Wörterbucharray zu vergleichen, das eine Menge Iteration erzeugt, können Sie Dateien mit Mustern abgleichen.
Sehr einfache Sorte:
quelle
Schutz in Ihrer .bashrc:
quelle
-n Do not overwrite an existing file. (The -n option overrides any previous -f or -i options.)
also ist es wichtig, dass das -n- tag vor den folgenden tags steht? Das --backup = nummeriert erzeugt ein Doppel von jedem Recht, ist das nicht ein bisschen übertrieben (und platzsparend / verbrauchend), wenn es um übergroße Videodateien (sprechende Terabyte) geht. Vielen Dank !Einige Möglichkeiten, um das
mv
Überschreiben vorhandener Dateien zu verhindern:Wenn Sie in ein Verzeichnis wechseln möchten, fügen Sie dem Ziel einen Schrägstrich hinzu, dh verwenden Sie
mv "$file" "$dir"/
anstelle vonmv "$file" "$dir"
. Wenn$dir
es kein Verzeichnis gibt oder kein Verzeichnis ist,mv
wird sich beschweren:Dies scheint den Systemaufruf zu veranlassen
rename("a", "z/")
, daher sollte er vor Sicherheitslücken bei der Überprüfung bis zur Verwendung geschützt sein, falls jemand denselben Satz von Dateien gleichzeitig verarbeitet.Alternativ verwenden
mv -t "$dir" "$file"
. Wieder wird es sich beschweren, wenn$dir
es kein Verzeichnis ist.Verwenden Sie die
-n
Option, um das Überschreiben vorhandener Dateien zu verhindern:Es wird nicht daran gehindert, die erste Datei umzubenennen, aber es wird sie dann nicht mit den anderen in den Papierkorb werfen.
Dies scheint eine Ebene zu sein
rename()
, daher ist es bei gleichzeitiger Handhabung möglicherweise nicht sicher. (Es gibtrenameat2()
eine Flagge, die ein Überschreiben verhindert.)quelle
Obwohl dies bei Ihnen anscheinend nicht der Fall ist, ist es möglich, dass Sie dies tun und die Dateien nicht verlieren. Dies würde eines von zwei Dingen erfordern, um wahr zu sein:
In Unix-Dateisystemen können mehrere Verzeichniseinträge auf genau denselben Dateiinhalt verweisen . Dies wird als " harte Verbindung " bezeichnet. Sie können mit dem
ln
Befehl feste Verknüpfungen erstellen , ohne die allgemeine-s
Option (weich / symbolisch). Solange mindestens ein fester Link zum Dateiinhalt vorhanden ist, wird er vom Dateisystem nicht wiederverwendet.(Randnotiz: Berechtigungen gelten normalerweise für den Dateiinhalt und nicht für den Verzeichniseintrag. Aus diesem Grund kann ein normaler Benutzer manchmal eine Datei löschen, deren Eigentümer er ist
root
, aber nicht darauf schreiben. Durch den Löschvorgang wird der Ordner und nicht die Datei selbst geändert. )Das Dateisystem wird den Dateiinhalt auch nicht wiederverwenden, solange mindestens ein Prozess die Datei geöffnet hat. Selbst wenn kein Verzeichniseintrag vorhanden ist, betrachtet das Dateisystem den Speicherplatz erst dann als frei, wenn kein Prozess ihn geöffnet hat. Die Datei kann aus dem virtuellen Dateisystem wiederhergestellt
/proc/<pid>/fd
werdenroot
, solange die Datei geöffnet bleibt. (Danke @fluffysheap.)quelle