Mover arquivos para várias pastas [closed]

1

Eu procurei por essa função e há muitas respostas, mas não consegui encontrar nada que funcione para mim.

Eu tenho uma pasta com cerca de 30.000 arquivos e quero um comando de terminal ou script bash que mova esses arquivos para pastas diferentes. Cerca de 3000 arquivos para cada pasta. Alguns dos nomes de arquivos têm sublinhados, espaços e hífens, portanto, o comando deve permitir que eu mova esses arquivos, bem como os arquivos sem sublinhados, espaços e hifens. Os arquivos são .jpgs, mas gostaria de um comando que eu possa personalizar para qualquer tipo de arquivo e quantidade de arquivo, caso eu precise usá-lo no futuro para diferentes formatos e quantidades.

ATUALIZAÇÃO:

Eu encontrei um script que responde às minhas necessidades. Ele moverá arquivos em uma pasta para subpastas. Funciona com qualquer tipo de arquivo. O número "3001" representa o número de arquivos que você deseja mover para cada subpasta. Este número pode ser alterado. Portanto, se você tiver uma pasta com 20000 arquivos e desejar que os 20000 arquivos sejam divididos em lotes de 500 e movidos para subpastas, substitua "3001" por "500". Você também pode modificar o script para mover apenas determinados tipos de arquivo, por exemplo: para mover somente arquivos .jpg, altere "para arquivo em *" para "para arquivo_jpg em * .jpg". Mude também "$ file" para "$ jpg_file".

#!/bin/bash

c=1; d=1; mkdir -p dir_${d}

for file in *
do
        if [ $c -eq 3001 ]
        then
                d=$(( d + 1 )); c=0; mkdir -p dir_${d}
        fi
        mv "$file" dir_${d}/
        c=$(( c + 1 ))
done
    
por user8547 13.08.2014 / 19:47

5 respostas

3

Eu tentei todos os scripts, mas nenhum deles funcionou por algum motivo, ou apenas parcialmente trabalhado. Eu encontrei este script bash e ajustei para procurar arquivos .jpg em vez de arquivos .xml:

#!/bin/bash

c=1; d=1; mkdir -p dir_${d}

for jpg_file in *.jpg
do
        if [ $c -eq 501 ]
        then
                d=$(( d + 1 )); c=0; mkdir -p dir_${d}
        fi
        mv "$jpg_file" dir_${d}/
        c=$(( c + 1 ))
done

Funcionou bem e rápido. Agora meu único problema é conseguir mover qualquer arquivo para pastas, não apenas ".jpg". Também é sensível a maiúsculas e minúsculas e não moverá ".JPG" .Qualquer idéia de como ajustá-lo para mover qualquer arquivo ou, no mínimo, qualquer arquivo de imagem?

    
por 14.08.2014 / 00:05
2

Como sobre o seguinte:

for letter in {A..Z}; do
   dir=/path/to/sorted/directories/$letter
   mkdir $dir
   mv "${letter}*.jpg" $dir/
done

E, claro, o mesmo loop com as letras minúsculas {a..z} , exceto que, nesse caso, você não deseja criar um diretório separado de letras minúsculas. Em seguida, a linha de movimento muda para:

mv "${letter}*.jpg" ${dir^^}/

Usar ${var^^} para criar uma versão maiúscula de uma variável requer o Bash 4.0.

Editar: corrige uma cotação ausente. Obrigado G-man por apontar isso.

    
por 13.08.2014 / 20:21
1

Eu penso em algo como:

#!/bin/bash
shopt -s nullglob
for i in <directory>; do
    mv *.jpg "$dir"
done

Isso moverá todos os jpegs para $ dir, que você precisará configurar, ou precisará criar um array com o (s) nome (s) do diretório. Você pode personalizar facilmente esse código alterando *.jpg para qualquer formato diferente. Você precisará ajustar esse snippet para personalizá-lo da maneira que quiser.

UPDATE Para que esta seja uma função, tente isto:

#!/bin/bash
echo "Enter Directory: ";
read dir
mkdir $dir

moveFiles(){
    arg1=$1    
    counter=0;
    while[$counter -ne 3000]; do
          mv <source> *.jpg "$dir"
          counter++;
          if[$counter -e 3000];
          then
               exit;
          fi
     done
}   
moveFiles "$dir"
exit

Novamente, esse código pode precisar de ajustes. Este é apenas um exemplo.

    
por 13.08.2014 / 19:58
1

Isto irá listar arquivos com ls *.jpg , pegue primeiro 3000 com head -n 3000 , crie o diretório para eles com outro nome definido em $FOLDERLIST e mova os arquivos para dentro dele, este laço se repete 10 vezes

LISTFILESCMD='ls *.jpg' 
FQUANTITY=3000
FOLDERLIST='seq -w 1 10'

for FOLDER in $FOLDERLIST; do mkdir $FOLDER; mv '$LISTFILESCMD | head -n $FQUANTITY' $FOLDER; done

u pode alterar parâmetros, leia man ls para opções de classificação. isso é apenas um exemplo e não uma solução ótima (chamar ls toda vez, dar tantos parâmetros para mv não é uma boa idéia, é melhor usar xargs se o comprimento total for muito grande) mas eu acho que irá ajudá-lo a entender o que você realmente precisa.

seção de teste

 $ ls|wc -w
41978
 $ LISTFILESCMD='ls *.jpg'
 $ FQUANTITY=3000
 $ FOLDERLIST='seq -w 1 13'
 $ time(for FOLDER in $FOLDERLIST; do mkdir $FOLDER; mv '$LISTFILESCMD | head -n  $FQUANTITY' $FOLDER; done)
real    0m7.396s
user    0m4.543s
sys     0m2.513s
 $ ls|wc -w 
2991
 $ ls -d */
01/  02/  03/  04/  05/  06/  07/  08/  09/  10/  11/  12/  13/
 $ for fldr in 'ls -d */';do ls $fldr|wc -w;done
3000
3000
...
    
por 13.08.2014 / 22:11
1

Supondo que você tenha um diretório para o qual deseja mover arquivos de .

Você pode usar:

$ mv <source folder/*.jpg <destination folder/>

Editar:

O script abaixo encontra todos os arquivos que correspondem aos critérios de pesquisa definidos por file_screen e, em seguida, executa um loop while para mover os arquivos selecionados.

Novos diretórios são criados com base nos critérios do módulo: loop iteration mod files_in_each . Se mod retorna zero, o novo diretório é criado e os arquivos serão movidos para ele.

Parâmetros para ajustar nas suas execuções:

files_in_each=3000  # controls how many files are placed in each directory
directory_to_move="/home/shadowe/test1/test2" # where are the files located
file_screen="jpg"   # only move files that match this criteria

Por favor, ajuste conforme necessário.

#!/bin/bash

# basic definitions and calculations
files_in_each=3000
directory_to_move="/home/shadowe/test1/test2"
file_screen="jpg"
folders_created=0
i=0

# while loop through all of the files that match screening criteria
find $directory_to_move/* -maxdepth 1 -type f -name "*${file_screen}" -print0 | sort -n | while IFS= read -r -d '' file; 
do
    # modulo control for creating directories every files in each completion
    create_dir='expr $i % $files_in_each'
    if [ $create_dir -eq "0" ]
    then
            new_folder=folder$folders_created
            mkdir $new_folder
            echo "created new folder: " $new_folder
            folders_created=$[$folders_created+1]
    fi
    mv "$file" $new_folder
    i=$[$i+1]
done

Pequenos resultados de amostra após a execução:

$ ls test2/
not a picture.txt
$ ls folder0/
one.jpg      one*two.jpg       picture 1.jpg  two-one.jpg
one-two.jpg  picture 1111.jpg  picture *.jpg  two three.jpg

Resultados de amostras grandes:

$ ls folder0 | wc -l
3000
$ ls folder1 | wc -l
2008
$ ls test2 | wc -l
7501
$ ls test2/ | grep "jpg"
$

Script para gerar arquivos de teste:

#!/bin/bash

mkdir test2
touch test2/one.jpg
touch test2/'one-two.jpg'
touch test2/'one*two.jpg'
touch test2/'two-one.jpg'
touch test2/'two three.jpg'
touch test2/'picture 1.jpg'
touch test2/'picture *.jpg'
touch test2/'picture 1111.jpg'
touch test2/'not a picture.txt'
#for large test sample uncomment below
#for i in 'seq 1 7500'; do touch test2/test$i.txt; done
#for j in 'seq 1 5000'; do touch test2/picture$j.jpg; done
    
por 13.08.2014 / 20:04