Как переместить 30 ГБ файлов из папки, содержащей 80 ГБ файлов?

Как переместить 30 ГБ файлов из папки, содержащей 80 ГБ файлов?

У меня есть папка, в которой находится более 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, которое я впервые представил, фактически копирует файлы, а не перемещает их. Это различие важно по двум причинам:

  1. При копировании исходные файлы сохраняются, тогда как при перемещении исходные файлы больше не существуют в своих исходных расположениях.
  2. Если файлы перемещаются в пределах одной файловой системы, как это может быть в этом вопросе, 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

Связанный контент