Como mover 30 GB de arquivos de uma pasta contendo 80 GB de arquivos?

Como mover 30 GB de arquivos de uma pasta contendo 80 GB de arquivos?

Tenho uma pasta com mais de 500 vídeos e o tamanho da pasta é de cerca de 80 GB.

Quero mover 30 GB de vídeos para outra pasta, mas como?

Estou usando o terminal e não consigo instalar uma GUI.

Responder1

Não seletivamente (automaticamente)

Não conheço uma única ferramenta de linha de comando que possa fazer isso ... Mas você pode usar um script para mover arquivos até que um determinado tamanho total seja movido, por exemplo, assim (Execute o script apenas uma vez... Se você executá-lo novamente, ele moverá o tamanho especificado novamente dos arquivos restantes):

#!/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

Ou até mesmo uma linha única (nenhum arquivo de script necessário) que você pode executar no terminal, por exemplo:

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

Você pode querer unset sizeexecutá-lo novamente na mesma instância do shell.

Seletivamente(manualmente)

Você sempre pode especificar um padrão de shell ou canal em uma ferramenta de pesquisa com base em nomes de arquivos, tamanhos, tipos... etc.

Ou, mais convenientemente, você pode usar um gerenciador de arquivos baseado em console que suporta seleção múltipla de arquivos como, por exemplo, o conhecido e rico em recursosComandante da meia-noite GNUque está disponível nos repositórios oficiais do Ubuntu e pode ser instalado assim:

sudo apt install mc

e para executá-lo digite mce pressione Enter... Você será então apresentado a uma interface de usuário navegável onde poderá usar a Inserttecla do teclado para selecionar vários arquivos ... Você poderá ver o tamanho total dos arquivos selecionados e sua contagem em tempo real assim:

insira a descrição da imagem aqui

Depois de terminar de selecionar todos os arquivos que deseja mover, pressione a F6tecla do teclado para abrir a caixa de diálogo mover/renomear e entre no diretório de destino e escolha [< OK >]mover os arquivos selecionados de uma vez, assim:

insira a descrição da imagem aqui

Ou mesmo o menos conhecido e com menos recursosaff (Gerenciador de arquivos muito rápido):-) ... Isso está interessantemente escrito em bash... Embora suporte a seleção de vários arquivos, pode ser necessário personalizá-lo um pouco para poder ver o tamanho total dos arquivos selecionados, por exemplo, como um patch rápido, você pode alterar a linha 159no arquivo de origem fffdeste:

local mark_ui="[${#marked_files[@]}] selected (${file_program[*]}) [p] ->"

para isso:

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] ->"

Então você pode simplesmente executar esse arquivo assim (Não é necessária instalação):

bash fff

Ou veja a ajuda sobre o uso assim:

bash fff -h

Então tudo que você precisa fazer é simplesmente navegar até o diretório de origem e começar a selecionar os arquivos para mover com o m(minúsculas) tecla do teclado assim:

insira a descrição da imagem aqui

Ao terminar de selecionar os arquivos, navegue até o diretório de destino e mova os arquivos previamente selecionados para ele pressionando o botão p(minúsculas) tecla do teclado.

Responder2

Aqui está uma alternativa paraRaffaé a ideia de que não requer um dudiretório completo para cada arquivo. Em vez disso, ele faz um statem cada arquivouma vez, usando find's -printf %spara obter o tamanho e %po caminho para o arquivo a ser movido.

#!/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

Responder3

@TedLyngmo apontou que a solução tar que apresentei pela primeira vez copia efetivamente os arquivos e não os move. Esta distinção é importante por 2 razões:

  1. Com uma cópia, os arquivos de origem permanecem, enquanto com uma movimentação, os arquivos de origem não existem mais em seus locais de origem.
  2. Se os arquivos forem movidos dentro do mesmo sistema de arquivos, como pode ser o caso nesta questão, mvsimplesmente vinculará novamente o arquivo de origem ao novo local e não copiará o conteúdo. Normalmente, isso será significativamente mais rápido do que copiar, especialmente para arquivos grandes.

Mover cenário

Ainda podemos usar os tarconceitos do cenário de cópia fornecido originalmente para construir uma lista de arquivos contendo apenas os primeiros 30 GB de arquivos encontrados tare, em seguida, mover apenas esses arquivos:

#!/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

Isso é mais complexo do que eu gostaria:

  • mvnão oferece tanto controle dos caminhos de origem e destino para vários arquivos (especificamente nenhum análogo da cpopção --parents), portanto, as movimentações de arquivos são obtidas criando links físicos nos locais de destino e, em seguida, desvinculando os arquivos de origem

  • Como os diretórios de origem contêm uma combinação de entradas que devem ou não ser movidas, os diretórios devem ser recriados no destino e não simplesmente movidos (junto com todo o conteúdo). Portanto, os diretórios de destino apropriados são criados antes de mover os arquivos, e os diretórios de origem correspondentes são removidos após a movimentação dos arquivos, se estiverem vazios.

Ressalvas

  • tar -vproduzirá uma entrada de arquivo por linha. Isto irá falhar espetacularmente se houver caracteres especiais nos nomes de caminho, por exemplo, novas linhas. Esperamos que os nomes dos caminhos de origem sejam nomeados de maneira sensata.

  • Isso moverá um pouco menos de 30 GB de dados reais do arquivo, pois o fluxo contém metadados (nomes de arquivos, carimbos de data e hora, etc.), bem como o conteúdo real, e tudo isso está sujeito ao limite de 30 GB.

  • Estou jogando um pouco rápido e solto com KB vs. kb aqui. Como o -Lparâmetro funciona em unidades de 1.024 bytes, isso limita a movimentação a 3.072.000.000 bytes de fluxo tar. Ajuste os números conforme apropriado.

  • filelist.txt é criado no diretório atual. Serão necessárias permissões de gravação para isso, o que provavelmente é um dado adquirido, já que as operações de movimentação exigirão permissões de gravação de qualquer maneira.

Copiar cenário

Você pode usar tarpara transformar sua pasta em um fluxo e, em seguida, tarnovamente para transformar o fluxo novamente em arquivos em um novo local. O primeiro tarlimita -Lo "comprimento da fita" a 3.000.000 KB, antes de solicitar uma nova fita. tarusa -F para executar falseapós cada "fita". Porque falseretorna um erro, a transferência para após a primeira "fita", ou seja, 30GB. Fazer com que todos os dados passem por apenas 2 invocações de tar deve ser mais rápido do que fazer um loop em todos os arquivos com loops bash.

mkdir dest.dir
tar -cv -L 3000000 -F false -C src.dir . | tar -x -C dest.dir/

Isso copiará os arquivos até que o limite de 30 GB seja atingido e, em seguida, o tars apresentará um erro:

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

tarnão transferirá o arquivo que estava sendo transferido quando o limite foi atingido - ele não será gravado no destino.

Ressalvas

  • Isso copiará um pouco menos de 30 GB de dados reais do arquivo, pois o fluxo contém metadados (nomes de arquivos, carimbos de data e hora, etc.), bem como o conteúdo real, e tudo isso está sujeito ao limite de 30 GB.

  • Estou jogando um pouco rápido e solto com KB vs. kb aqui. Como o -Lparâmetro funciona em unidades de 1.024 bytes, isso limita a transferência a 3.072.000.000 bytes de fluxo tar. Ajuste os números conforme apropriado.


As edições anteriores desta resposta usaram find-cpio-head-cpio e depois tar-head-tar. A solução tar-tar agora apresentada deve ser suficiente, mas inspecione o histórico de edições se as outras soluções forem de interesse.

Responder4

Vá para a pasta onde estão seus arquivos:

cd SOURCE_FOLDER

faça uma lista de arquivos nessa pasta

ls > list.txt

Edite-o em qualquer editor e remova os arquivos que você NÃO deseja mover. Salve o resultado para que agora list.txt tenha apenas os arquivos que você deseja mover. Agora execute este script simples que lê cada linha do seu arquivo list.txt e move esse arquivo para o diretório de destino.

while IFS= read -r line; do mv "$line" ../DESTINATION_DIRECTORY/"$line"; done < list.txt

informação relacionada