Comando para criar diretórios direcionados numerados sequencialmente e mover arquivos em lote

4

Estou criando um vídeo de lapso de tempo dividindo um vídeo em imagens individuais, usando o G'MIC por meio da linha de comando para calcular a média a cada 7 quadros e exibindo os resultados em novas imagens que resultarão nos quadros do lapso de tempo maneira eu recebo vídeo livre de ruído que parece ótimo). Como você pode imaginar, eu tenho muitos frames - milhares de imagens individuais em um diretório, chamadas sequencialmente ( image1.tiff, image2.tiff, etc. ). Eu encontrei um script que funciona perfeitamente para mover os arquivos - uma vez ...

k=1; find source/ -type f | while read file; do
     [[ k++ -le 7 ]] && mv "$file" target/ 
done 

O que eu preciso agora é fazer este script

  1. repita-se até que todos os arquivos sejam movidos e
  2. crie diretórios de destino com numeração sequencial (1, 2, 3, etc.) conforme o resultado, e acabo com várias centenas de diretórios, cada um com 7 imagens internas.

Só para esclarecer, o diretório 1 deve conter as imagens 1-7, o diretório 2 deve conter as imagens 8-14, etc.

Qualquer ajuda é muito apreciada, estou bastante preso a esta.

    
por Tim 29.12.2014 / 04:48

4 respostas

3

O script (python) abaixo cria subpastas e organiza seus arquivos nas pastas:

Além disso:

  • O script calcula o número de pastas e adiciona zeros à esquerda aos nomes das pastas para classificação adequada (desde que você mencionou milhares de arquivos, ou seja, centenas de pastas)
  • O número de arquivos por pasta pode variar, dependendo da sua configuração na cabeça do script

O script pressupõe:

  • Todos os arquivos têm uma extensão, todos os arquivos têm a mesma extensão
  • Seus arquivos são nomeados image1.tiff , image2.tiff etc (sem zeros à esquerda).

O script

#!/usr/bin/env python3
import os
import math
import shutil
#---
directory = "/path/to/files"      # path to your files
n_perfolder = 7                   # number of files per sub folder
#--
# creating file list, extension
f_list = os.listdir(directory); ext = f_list[0].split(".")[-1]
# calculate number of folders
n_folders = math.ceil(len(f_list)/n_perfolder)
# creating folder names, including leading zeros
folders = [str(fn+1) for fn in range(n_folders)]
fl_names = [(len(max(folders, key=len))-len(fl))*"0"+fl for fl in folders]
# creating folders and allocate files 
for i in range(len(fl_names)):
    mkfolder = directory+"/"+fl_names[i]
    if not os.path.exists(mkfolder):
        os.makedirs(mkfolder)
        r = range(i*n_perfolder+1, i*n_perfolder+n_perfolder+1)
        for n in r:
            try:
                file = directory+"/"+"image"+str(n)+"."+ext
                target = mkfolder+"/"+"image"+str(n)+"."+ext
                shutil.copyfile(file, target)
            except FileNotFoundError:
                pass

Como usar

Copie o script em um arquivo vazio, na seção head, defina o diretório para seus arquivos e o número de arquivos por subdiretório, salve-o como organize.py .

Execute-o pelo comando:

python3 /path/to/organize.py

Nota

Se você quiser mover os arquivos em vez de copiá-los, substitua a linha:

shutil.copyfile(file, target)

por:

shutil.move(file, target)

(note o recuo!)

    
por Jacob Vlijm 29.12.2014 / 09:42
3

Se você não se importar em mudar tudo de uma vez:

#! /bin/bash
for ((i = 1; ; i++))
do
    mkdir -p target-$i
    for j in $(seq $((i*7 - 6)) $((i*7)))
    do
        mv -t "target-$i" "source/image$j.tiff" || exit 1
    done
done

Ou mais conciso:

find source -type f -name 'image*.tiff' -print0 | \
  sort -z --version-sort | \
  xargs -0n7 bash -c 'TARGET=target-$((${1//[^0-9]/} / 7 + 1)); \
    echo mkdir -p "$TARGET"; \
    echo mv -t "$TARGET" "$@"' move-7

Explicação:

  1. -print0 imprime os nomes dos arquivos separados pelo caractere NUL ( sort ). É a maneira mais segura de passar nomes de arquivos como saída para outros comandos.
  2. -z com image2.tiff procura entrada delimitada por nul e a classificação da versão nos permite classificar com segurança números de comprimento variável, de modo que image119.tiff seja anterior a xargs
  3. -n pode limitar o número de argumentos aplicados a cada comando com -n7 , portanto, aqui usamos -0 . O $((${1//[^0-9]/} / 7 + 1)) é para entrada delimitada por nul.
  4. Extraímos o quociente do número do primeiro argumento ${1//[^0-9]/} - mv exclui tudo no argumento que não é um número. A divisão inteira garante que obtenhamos o quociente.
  5. Isso deve ser mais rápido, já que executamos exatamente o número de echo s necessário.

Inspecione os comandos produzidos e, se parecerem bem, execute-o novamente após remover o rename s.

KasiyA tem uma modificação interessante para isso.

A resposta de JJoao traz mkdir -p em mente. Primeiro, faça todos os diretórios:

FILES=(source/image*.tiff)
COUNT=${#FILES[@]}
DIR_NUM=$((COUNT / 7 + 1))
seq 1 $DIR_NUM | xargs bash -c 'mkdir -p "${@/#/target-}"'

rename -n 's;source/image(\d+)\.tiff$;"target-".int($1 / 7 - 1)."/image".$1.".tiff";e' source/image*.tiff

Na verdade, podemos aplicar as quatro primeiras linhas a todas as soluções aqui e pular as %code% repetidas.

    
por muru 29.12.2014 / 08:59
2
sevenfile=0
newdir=1
for file in 'ls -v /path/to/source/image*.tiff' ; do
    mkdir -p "$newdir" && mv "$file" "$newdir" 
    [[ ++sevenfile -eq 7 ]] && sevenfile=0 &&  ((newdir++))
done
  • O comando ls -v classifica os arquivos como uma espécie natural de números (versão).
    Você pode analisar o comando ls neste caso, porque todos os arquivos são específicos e são apenas image*.tiff .
  • mkdir -p $newdir cria o diretório com base na variável newdir .

  • mv "$file" "$newdir" move o arquivo para o diretório que newdir especifica.

  • Redefina sevenfile=0 para zero quando 7 arquivos forem movidos ( [[ ++sevenfile -eq 7 ]] ) e incremento para newdir value.

Observe que altere /path/to/source/ para o diretório de origem atual.

Se você não quiser analisar o comando ls e se o nome dos arquivos incluir espaços, novas linhas e etc:

find /path/to/source/ -type f -name 'image*.tiff' -print0 | \
     sort -z --version-sort | while IFS= read -d '' -r file; do \
     mkdir -p "$newdir" && mv "$file" "$newdir" ;
     [[ ++sevenfile -eq 7 ]] && sevenfile=0 &&  ((newdir++));
done
    
por devWeek 29.12.2014 / 09:41
1
#!/usr/bin/perl

open(F,"-|","ls source/*") or die;

while(<F>){ chomp;
  if(/(\d+).tiff/){
     $dir= "target-" . (1+int($1/7));
     mkdir($dir) unless -d $dir;
     system "mv $_ $dir";
  }
}
    
por JJoao 30.12.2014 / 12:45