Ich habe einen Ordner mit mehr als 500 Videos und die Ordnergröße beträgt etwa 80 GB.
Ich möchte 30 GB Videos in einen anderen Ordner verschieben, aber wie?
Ich verwende ein Terminal und kann keine GUI installieren.
Antwort1
Unselektiv(automatisch)
Mir ist kein einziges Kommandozeilentool bekannt, das das kann ... Aber man kann ein Skript verwenden, um Dateien zu verschieben, bis eine bestimmte Gesamtgröße erreicht ist, z. B. so (Führen Sie das Skript nur einmal aus. Bei erneuter Ausführung verschiebt es die angegebene Größe erneut aus den verbleibenden Dateien.):
#!/bin/bash
sourc_dir="/path/to/directory" # Set the path to the source directory "no trailing /"
dest_dir="/path/to/directory" # Set the path to the destination directory "no trailing /"
move_size="30" # Set the total size of files to move in Gigabytes
# Don't edit below this line
move_size=$(( move_size * 1000000 ))
current_size=$(du -sk "$sourc_dir" | awk '{printf "%d", $1}')
remaining_size=$(( current_size - move_size ))
for f in "$sourc_dir"/*; do
[ -f "$f" ] || continue
new_size=$(du -sk "$sourc_dir" | awk '{printf "%d", $1}')
(( new_size <= remaining_size )) && exit
mv -n -- "$f" "$dest_dir"/
done
Oder sogar ein Einzeiler(keine Script-Datei nötig), das Sie im Terminal beispielsweise wie folgt ausführen können:
for f in /path/to/source/*; do [ -f "$f" ] || continue; (( size >= (30*(1000**3)) )) && break || (( size += $(stat --printf "%s" "$f") )) && mv -n -- "$f" /path/to/destination/; done
Möglicherweise möchten Sie unset size
es in derselben Shell-Instanz erneut ausführen können.
Selektiv(manuell)
Sie können jederzeit ein Shell-Muster oder eine Pipe aus einem Suchtool basierend auf Dateinamen, Größen, Typen usw. angeben.
Oder, bequemer, Sie können einen konsolenbasierten Dateimanager verwenden, der die Auswahl mehrerer Dateien unterstützt, wie z. B. den bekannten und funktionsreichenGNU Midnight CommanderDas ist in den offiziellen Ubuntu-Repositories verfügbar und kann wie folgt installiert werden:
sudo apt install mc
und um es auszuführen, geben Sie ein mc
und drücken Sie Enter.... Ihnen wird dann eine navigierbare Benutzeroberfläche angezeigt, in der Sie mithilfe der InsertTastenkombination mehrere Dateien auswählen können ... Sie können die Gesamtgröße der ausgewählten Dateien und ihre Anzahl in Echtzeit wie folgt sehen:
Wenn Sie alle zu verschiebenden Dateien ausgewählt haben, drücken Sie die F6entsprechende Taste auf der Tastatur, um das Dialogfeld „Verschieben/Umbenennen“ zu öffnen und das Zielverzeichnis einzugeben. Wählen Sie anschließend die Option [< OK >]
zum gleichzeitigen Verschieben der ausgewählten Dateien wie folgt aus:
Oder auch die weniger bekannten mit weniger FunktionenF f f (Verdammt schneller Dateimanager):-) ... Das ist interessanterweise so geschrieben bash
... Obwohl es die Auswahl mehrerer Dateien unterstützt, müssen Sie es unter Umständen ein wenig anpassen, um die Gesamtgröße der ausgewählten Dateien sehen zu können. Als schnelle Lösung können Sie beispielsweise die folgende Zeile 159
in der Quelldatei ändern fff
:
local mark_ui="[${#marked_files[@]}] selected (${file_program[*]}) [p] ->"
dazu:
local mark_ui="[${#marked_files[@]}] $(for f in "${marked_files[@]}"; do (( tsize += $(stat --printf "%s" "$f") )); done; tsize=$((tsize/(1000**2))); printf '[%d M]' "$tsize";) selected (${file_program[*]}) [p] ->"
Dann können Sie die Datei einfach wie folgt ausführen (Keine Installation nötig):
bash fff
Oder sehen Sie sich die Hilfe zur Verwendung wie folgt an:
bash fff -h
Dann müssen Sie nur noch zu Ihrem Quellverzeichnis navigieren und mit der Auswahl der zu verschiebenden Dateien beginnen m(Kleinbuchstaben)-Taste wie folgt:
Wenn Sie mit der Dateiauswahl fertig sind, navigieren Sie zum Zielverzeichnis und verschieben Sie die zuvor ausgewählten Dateien dorthin, indem Sie auf die Schaltfläche p(Kleinbuchstaben) Tastaturtaste.
Antwort2
Hier ist eine Alternative zuRaffaDie Idee von erfordert nicht du
für jede Datei ein auf dem gesamten Verzeichnis. Stattdessen wird ein stat
auf jeder Datei ausgeführt.einmal, wobei find
's verwendet werden, -printf
%s
um die Größe und %p
den Pfad zur zu verschiebenden Datei abzurufen.
#!/bin/bash
src='foo'
dest='bar'
# 30GB in bytes to move:
(( bytestomove=30*(1000**3) ))
movedbytes=0
while IFS=$'\t' read -r -d '' bytes file
do
# if we already moved enough, break out
(( movedbytes >= bytestomove )) && break;
# try to move it, break out if it fails
mv -n -- "$file" "$dest" || break
# successfully moved, add bytes to movedbytes
(( movedbytes += bytes ))
done < <(find "$src" -type f -printf "%s\t%p\0")
(( movedmegs=movedbytes/(1000**2) ))
printf "Moved %d MB\n" $movedmegs
Antwort3
@TedLyngmo wies darauf hin, dass die Tar-Lösung, die ich zuerst vorgestellt habe, die Dateien effektiv kopiert und nicht verschiebt. Diese Unterscheidung ist aus zwei Gründen wichtig:
- Bei einer Kopie bleiben die Quelldateien erhalten, während bei einer Verschiebung die Quelldateien nicht mehr an ihren Quellspeicherorten vorhanden sind.
- Wenn Dateien innerhalb desselben Dateisystems verschoben werden, wie es in dieser Frage der Fall sein kann,
mv
wird die Quelldatei einfach mit dem neuen Speicherort verknüpft und der Inhalt überhaupt nicht kopiert. Dies ist in der Regel deutlich schneller als das Kopieren, insbesondere bei großen Dateien.
Szenario verschieben
Wir können weiterhin die tar
Konzepte des ursprünglich angegebenen Kopierszenarios verwenden, um eine Dateiliste mit nur den ersten 30 GB der tar
gefundenen Dateien zu erstellen und dann nur diese Dateien zu verschieben:
#!/bin/bash
# Convert human-readable number, e.g. 1M, 30G to number of 1024 byte blocks
limit=$(numfmt --from=auto $1 --to-unit 1024)
src_dir=$2
dest_dir=$3
mkdir $dest_dir
filelist=$(readlink -f $(mktemp -p $dest_dir))
# create a list of files to be moved. tar -v outputs filenames to stdout, and
# the dest archive is /dev/null
tar -v -L $limit -F false -c -f /dev/null -C $src_dir . > $filelist 2> /dev/null
tar_result=$?
if [ "$tar_result" = 2 ]; then
echo "$1 limit was hit - some unmoved files will remain in $dest_dir"
else
echo "All files will be moved"
fi
pushd $dest_dir > /dev/null
abs_dest_dir=$PWD
# create directories in the destination
grep '/.*/$' $filelist | xargs mkdir -p
popd > /dev/null
pushd $src_dir > /dev/null
# create hard links in the destination
grep -v '/$' $filelist | xargs cp -l --parents -t $abs_dest_dir
# unlink source files
grep -v '/$' $filelist | xargs rm
# remove source directories in reverse order, if they are empty
grep '/.*/$' $filelist | tac | xargs rmdir --ignore-fail-on-non-empty
popd > /dev/null
rm $filelist
Das ist komplexer als ich möchte:
mv
bietet nicht so viel Kontrolle über Quell- und Zielpfade für mehrere Dateien (insbesondere kein Analogon zurcp
Option --parents), daher werden die Dateien verschoben, indem Hardlinks an den Zielorten erstellt und die Verknüpfungen der Quelldateien dann aufgehoben werdenDa Quellverzeichnisse eine Mischung aus Einträgen enthalten, die verschoben werden sollen und solchen, die nicht verschoben werden sollen, müssen Verzeichnisse im Ziel neu erstellt und nicht einfach (mitsamt dem gesamten Inhalt) verschoben werden. Daher werden die entsprechenden Zielverzeichnisse vor dem Verschieben von Dateien erstellt und die entsprechenden Quellverzeichnisse nach dem Verschieben von Dateien gelöscht, wenn sie leer sind.
Vorbehalte
tar -v
gibt einen Dateieintrag pro Zeile aus. Dies schlägt fehl, wenn die Pfadnamen Sonderzeichen enthalten, z. B. Zeilenumbrüche. Hoffentlich sind die Quellpfadnamen sinnvoll.Dabei werden etwas weniger als 30 GB an tatsächlichen Dateidaten verschoben, da der Stream sowohl Metadaten (Dateinamen, Zeitstempel usw.) als auch die eigentlichen Inhalte enthält und für all dies die 30-GB-Begrenzung gilt.
Ich gehe hier etwas locker mit KB vs. kb um. Da der
-L
Parameter mit Einheiten von 1024 Bytes arbeitet, begrenzt dies die Verschiebung tatsächlich auf 3.072.000.000 Bytes Tar-Stream. Passen Sie die Zahlen entsprechend an.filelist.txt wird im aktuellen Verzeichnis erstellt. Hierfür sind Schreibberechtigungen erforderlich. Dies ist wahrscheinlich eine Selbstverständlichkeit, da für die Verschiebungsvorgänge ohnehin Schreibberechtigungen erforderlich sind.
Szenario kopieren
Sie können tar
Ihren Ordner in einen Stream umwandeln und tar
den Stream dann wieder in Dateien an einem neuen Speicherort umwandeln. Die erste tar
Methode -L
begrenzt die „Bandlänge“ auf 3000000 KB, bevor ein neues Band angefordert wird. tar
verwendet -F, um nach jedem „Band“ zu laufen false
. Da false
ein Fehler zurückgegeben wird, wird die Übertragung nach dem ersten „Band“, also nach 30 GB, beendet. Alle Daten durch nur 2 Aufrufe von Tar zu leiten, sollte schneller sein, als alle Dateien mit Bash-Schleifen zu durchlaufen.
mkdir dest.dir
tar -cv -L 3000000 -F false -C src.dir . | tar -x -C dest.dir/
Dadurch werden die Dateien kopiert, bis die Grenze von 30 GB erreicht ist. Anschließend tar
wird folgender Fehler ausgegeben:
tar: Unexpected EOF in archive
tar: Unexpected EOF in archive
tar: Error is not recoverable: exiting now
tar: ‘false’ command failed
tar: Error is not recoverable: exiting now
tar
überträgt die Datei nicht, die übertragen wurde, als das Limit erreicht wurde – sie wird überhaupt nicht in das Ziel geschrieben.
Vorbehalte
Dabei werden etwas weniger als 30 GB der tatsächlichen Dateidaten kopiert, da der Stream sowohl Metadaten (Dateinamen, Zeitstempel usw.) als auch die eigentlichen Inhalte enthält und für all dies die 30-GB-Begrenzung gilt.
Ich gehe hier etwas locker mit KB vs. kb um. Da der
-L
Parameter mit Einheiten von 1024 Bytes arbeitet, begrenzt dies die Übertragung tatsächlich auf 3.072.000.000 Bytes Tar-Stream. Passen Sie die Zahlen entsprechend an.
Frühere Bearbeitungen dieser Antwort verwendeten find-cpio-head-cpio und dann tar-head-tar. Die jetzt vorgestellte Tar-Tar-Lösung sollte ausreichen, aber überprüfen Sie bitte den Bearbeitungsverlauf, wenn die anderen Lösungen von Interesse sind.
Antwort4
Gehen Sie zu dem Ordner, in dem sich Ihre Dateien befinden:
cd SOURCE_FOLDER
Erstellen Sie eine Liste der Dateien in diesem Ordner
ls > list.txt
Bearbeiten Sie es in einem beliebigen Editor und entfernen Sie Dateien, die Sie NICHT verschieben möchten. Speichern Sie das Ergebnis, sodass list.txt jetzt nur die Dateien enthält, die Sie verschieben möchten. Führen Sie nun dieses einfache Skript aus, das jede Zeile aus Ihrer list.txt-Datei liest und diese Datei in Ihr Zielverzeichnis verschiebt.
while IFS= read -r line; do mv "$line" ../DESTINATION_DIRECTORY/"$line"; done < list.txt