У меня есть папка, в которой находится более 500 видео, а размер папки составляет около 80 ГБ.
Я хочу переместить 30 ГБ видео в другую папку, но как?
Я использую терминал и не могу установить графический интерфейс.
решение1
Неизбирательно(автоматически)
Я не знаю ни одного инструмента командной строки, который мог бы это сделать... Но вы можете использовать скрипт для перемещения файлов до тех пор, пока не будет перемещен определенный общий размер, например, вот так(Запустите скрипт только один раз... Если вы запустите его снова, он снова переместит указанный размер из оставшихся файлов.):
#!/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
Или даже однострочный(файл скрипта не нужен), который можно запустить в терминале, например, так:
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
Возможно, вам захочется unset size
иметь возможность повторно запустить его в том же экземпляре оболочки.
Выборочно(вручную)
Вы всегда можете указать шаблон оболочки или трубы с помощью инструмента поиска на основе имен файлов, размеров, типов и т. д.
Или, что более удобно, вы можете использовать консольный файловый менеджер, который поддерживает множественный выбор файлов, например, хорошо известный и многофункциональныйGNU Midnight Commanderкоторый доступен в официальных репозиториях Ubuntu и может быть установлен следующим образом:
sudo apt install mc
и чтобы запустить его, введите mc
и нажмите Enter... Затем вам будет представлен пользовательский интерфейс с возможностью навигации, в котором вы можете использовать клавиши Insertклавиатуры для выбора нескольких файлов ... Вы сможете увидеть общий размер выбранных файлов и их количество в режиме реального времени, например, так:
После того, как вы закончите выбирать все файлы, которые хотите переместить, нажмите F6клавишу на клавиатуре, чтобы открыть диалоговое окно перемещения/переименования, и введите целевой каталог, а затем выберите [< OK >]
одновременное перемещение выбранных файлов, как показано ниже:
Или даже менее известные с меньшим количеством функцийффф (Чертовски быстрый файловый менеджер):-) ... Интересно, что написано на bash
... Хотя он поддерживает выбор нескольких файлов, вам, возможно, придется немного его настроить, чтобы увидеть общий размер выбранных файлов, например, в качестве быстрого исправления вы можете изменить строку 159
в исходном fff
файле с этой:
local mark_ui="[${#marked_files[@]}] selected (${file_program[*]}) [p] ->"
к этому:
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] ->"
Затем вы можете просто запустить этот файл вот так(Установка не требуется):
bash fff
Или просмотрите справку по использованию, например:
bash fff -h
Затем все, что вам нужно сделать, это просто перейти в исходный каталог и начать выбирать файлы для перемещения с помощью m(нижний регистр) клавиша клавиатуры выглядит так:
Закончив выбор файлов, перейдите в целевой каталог и переместите в него ранее выбранные файлы, нажав кнопку p(нижний регистр) клавиша клавиатуры.
решение2
Вот альтернативаРаффаИдея, которая не требует du
для всего каталога для каждого файла. Вместо этого она делает stat
для каждого файлаодин раз, используя find
's -printf
%s
для получения размера и %p
пути к файлу, который необходимо переместить.
#!/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
решение3
@TedLyngmo указал, что решение tar, которое я впервые представил, фактически копирует файлы, а не перемещает их. Это различие важно по двум причинам:
- При копировании исходные файлы сохраняются, тогда как при перемещении исходные файлы больше не существуют в своих исходных расположениях.
- Если файлы перемещаются в пределах одной файловой системы, как это может быть в этом вопросе,
mv
просто перелинкует исходный файл в новое местоположение и вообще не скопирует содержимое. Обычно это будет значительно быстрее копирования, особенно для больших файлов.
Сценарий перемещения
Мы по-прежнему можем использовать tar
концепции, изначально представленные в сценарии копирования, чтобы создать список файлов, содержащий только первые 30 ГБ найденных файлов tar
, а затем переместить только эти файлы:
#!/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
Это сложнее, чем мне бы хотелось:
mv
не обеспечивает достаточного контроля над исходными и целевыми путями для нескольких файлов (в частности, нет аналогаcp
опции --parents), поэтому перемещение файлов достигается путем создания жестких ссылок в местах назначения с последующим удалением ссылок на исходные файлыПоскольку исходные каталоги содержат смесь записей, которые подлежат и не подлежат перемещению, каталоги должны быть созданы заново в месте назначения, а не просто перемещены (вместе со всем содержимым). Поэтому соответствующие каталоги назначения создаются до перемещения файлов, а соответствующие исходные каталоги удаляются после перемещения файлов, если они пусты.
Предостережения
tar -v
выведет одну запись файла на строку. Это будет иметь катастрофические последствия, если в именах путей есть специальные символы, например, символы новой строки. Надеюсь, имена исходных путей разумно названы.При этом будет перемещено чуть меньше 30 ГБ фактических данных файла, поскольку поток содержит метаданные (имена файлов, временные метки и т. д.), а также фактическое содержимое, и все это подпадает под ограничение в 30 ГБ.
Я немного играю с КБ против кб здесь. Поскольку
-L
параметр работает с блоками по 1024 байта, это фактически ограничивает перемещение до 3 072 000 000 байт потока tar. Отрегулируйте числа соответствующим образом.filelist.txt создается в текущем каталоге. Для этого потребуются права на запись, это, вероятно, само собой разумеется, поскольку операции перемещения в любом случае потребуют права на запись.
Сценарий копирования
Вы можете использовать tar
, чтобы превратить вашу папку в поток, а затем tar
снова превратить поток обратно в файлы в новом месте. Первый tar
использует -L
для ограничения "длины ленты" до 3000000 КБ, прежде чем запрашивать новую ленту. tar
использует -F для запуска false
после каждой "ленты". Поскольку false
возвращается ошибка, передача останавливается после первой "ленты", т. е. 30 ГБ. Прохождение всех данных всего через 2 вызова tar должно быть быстрее, чем цикл по всем файлам с помощью циклов bash.
mkdir dest.dir
tar -cv -L 3000000 -F false -C src.dir . | tar -x -C dest.dir/
Это приведет к копированию файлов до тех пор, пока не будет достигнут лимит в 30 ГБ, после чего tar
возникнет ошибка:
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
не перенесет файл, который передавался при достижении лимита — он вообще не будет записан в место назначения.
Предостережения
При этом будет скопировано чуть меньше 30 ГБ фактических данных файла, поскольку поток содержит метаданные (имена файлов, временные метки и т. д.), а также фактическое содержимое, и все это подпадает под ограничение в 30 ГБ.
Я немного играю с КБ против кб здесь. Поскольку
-L
параметр работает с блоками по 1024 байта, это фактически ограничивает передачу 3 072 000 000 байт потока tar. Отрегулируйте числа соответствующим образом.
Предыдущие правки этого ответа использовали find-cpio-head-cpio, а затем tar-head-tar. Представленное сейчас решение tar-tar должно быть достаточным, но, пожалуйста, проверьте историю правок, если другие решения представляют интерес.
решение4
Перейдите в папку, где находятся ваши файлы:
cd SOURCE_FOLDER
составьте список файлов в этой папке
ls > list.txt
Отредактируйте его в любом редакторе и удалите файлы, которые вы НЕ хотите перемещать. Сохраните результат, чтобы теперь в list.txt были только те файлы, которые вы хотите переместить. Теперь запустите этот простой скрипт, который считывает каждую строку из вашего файла list.txt и перемещает этот файл в ваш целевой каталог.
while IFS= read -r line; do mv "$line" ../DESTINATION_DIRECTORY/"$line"; done < list.txt