Copiando vários arquivos específicos de uma pasta para outra

91

Eu tenho uma grande pasta de fotos (milhares), e tenho uma longa lista de arquivos, pelo nome exato do arquivo, que eu preciso copiar para outra pasta. Eu quero saber se existe uma maneira que eu possa selecionar vários arquivos específicos desta pasta, pelo nome, e copiá-los para outra pasta, usando o terminal, sem copiá-los individualmente?

    
por Someone with far too many pict 01.08.2013 / 07:44

4 respostas

125

Basta copiar vários arquivos de uma vez da linha de comando

Existem várias maneiras de conseguir isso. O mais fácil que vi é usar o seguinte.

cp /home/usr/dir/{file1,file2,file3,file4} /home/usr/destination/

A sintaxe usa o comando cp seguido pelo caminho para o diretório onde os arquivos desejados estão localizados, com todos os arquivos que você deseja copiar, agrupados entre parênteses e separados por vírgulas.

Lembre-se de que não há espaços entre os arquivos. A última parte do comando, /home/usr/destination/ , é o diretório no qual você deseja copiar os arquivos.

ou se todos os arquivos tiverem o mesmo prefixo, mas diferentes finais, você poderá fazer algo assim:

cp /home/usr/dir/file{1..4} ./

Em que file1, file2, file3 e file4 seriam copiados.

De como você redigiu a pergunta Eu acredito que é isso que você está procurando, mas também parece que você pode estar procurando por um comando para ler a partir de uma lista de arquivos e copiar todos eles para um determinado diretório. Se for esse o caso, deixe-me saber e eu vou editar a minha resposta.

Lidando com duplicatas com python

Então eu escrevi um pequeno script python que acredito que deveria fazer o trabalho. No entanto, eu não tenho certeza de quão bem versado você é em python (se for versado em tudo), então vou tentar explicar como usar este script da melhor maneira possível e, por favor, faça quantas perguntas forem necessárias.

import os,sys,shutil
### copies a list of files from source. handles duplicates.
def rename(file_name, dst, num=1):
    #splits file name to add number distinction
    (file_prefix, exstension) = os.path.splitext(file_name)
    renamed = "%s(%d)%s" % (file_prefix,num,exstension)

    #checks if renamed file exists. Renames file if it does exist.
    if os.path.exists(dst + renamed):
        return rename(file_name, dst, num + 1)
    else:
        return renamed

def copy_files(src,dst,file_list):
    for files in file_list:
        src_file_path = src + files
        dst_file_path = dst + files
        if os.path.exists(dst_file_path):
            new_file_name =  rename(files, dst)
            dst_file_path = dst + new_file_name

        print "Copying: " + dst_file_path
        try:
            shutil.copyfile(src_file_path,dst_file_path)
        except IOError:
            print src_file_path + " does not exist"
            raw_input("Please, press enter to continue.")

def read_file(file_name):
    f = open(file_name)
    #reads each line of file (f), strips out extra whitespace and 
    #returns list with each line of the file being an element of the list
    content = [x.strip() for x in f.readlines()]
    f.close()
    return content

src = sys.argv[1]
dst = sys.argv[2]
file_with_list = sys.argv[3]

copy_files(src,dst,read_file(file_with_list))

Esse script deve ser relativamente simples de usar. Primeiro, copie o código acima no programa gedit (deve estar pré-instalado no Ubuntu) ou em qualquer outro editor de texto.

Depois disso, salve o arquivo como move.py no seu diretório pessoal (pode ser qualquer diretório, mas para facilidade de instrução permite usar apenas o diretório pessoal) ou adicione o diretório ao arquivo está contido no seu PATH. Então cd para o seu diretório home (ou qualquer diretório que você salvou move.py) do terminal e digite o seguinte comando:

python move.py /path/to/src/ /path/to/dst/ file.txt

Isso deve copiar todos os arquivos que estão listados no diretório de origem para o diretório de destino com duplicatas, tirando o formato pic (1) .jpg, pic (2) .jpg e assim por diante. file.txt deve ser um arquivo que lista todas as imagens que você gostaria de copiar com cada entrada em sua própria linha separada.

De modo algum este script deve afetar o diretório de origem, no entanto, apenas certifique-se de inserir os caminhos corretos para o diretório de origem e destino e o pior que pode acontecer é copiar os arquivos para o diretório errado.

Notas

  • Este script pressupõe que todas as imagens originais estão no mesmo diretório. Se você quiser verificar sub-diretórios, bem como o script precisará ser modificado.
  • Se você digitar acidentalmente um nome de arquivo, o script irá gerar o erro. "arquivo não existe" e solicita que você "pressione enter" para continuar e o script continuará copiando o restante da lista.
  • Não se esqueça do rastreio / no caminho para a origem
    diretório e caminho para o diretório de destino. Caso contrário, o roteiro vai cuspir um erro de volta para você.

Espero que isso ajude!

    
por Bryan 01.08.2013 / 08:04
25

Talvez eu esteja perdendo um detalhe da sua pergunta, mas as respostas dadas parecem excessivas. Se você quer uma solução de linha de comando e não um script, por que não:

cd /path/to/src/
cp -t /path/to/dst/ file1 file2 file3 ...

O bom de fazer isso dessa maneira é que você pode aba completar os nomes dos arquivos

    
por Ross Allen 25.08.2016 / 19:48
6

Aqui está uma solução pura. Ele lerá nomes de arquivos de um arquivo de entrada (um por linha) e copiará cada um deles, renomeando duplicados.

#!/usr/bin/env bash

## The destination folder where your files will
## be copied to.
dest="bar";

## For each file path in your input file
while read path; do 
    ## $target is the name of the file, removing the path. 
    ## For example, given /foo/bar.txt, the $target will be bar.txt.
    target=$(basename "$path"); 
    ## Counter for duplicate files
    c=""; 
    ## Since $c is empty, this will check if the
    ## file exists in target.
    while [[ -e "$dest"/"$target"$c ]]; do
        echo "$target exists"; 
        ## If the target exists, add 1 to the value of $c
        ## and check if a file called $target$c (for example, bar.txt1)
        ## exists. This loop will continue until $c has a value
        ## such that there is no file called $target$c in the directory.
        let c++; 
        target="$target"$c; 
    done; 
    ## We now have everything we need, so lets copy.
    cp "$path" "$dest"/"$target"; 
done

Salve este script em uma pasta no seu $PATH e chame-o com a lista de caminhos como entrada:

auto_copy.sh < file_paths.txt

Você também pode executar o item inteiro como um comando no terminal:

while read path; do 
   target=$(basename "$path"); 
   c=""; 
   while [[ -e bar/"$target"$c ]]; do 
    echo "$target exists"; 
    let c++; 
    target="$target"$c; 
   done; 
   cp "$file" bar/"$target"; 
done < file_names;
    
por terdon 01.08.2013 / 17:24
0

De acordo com a descrição da pergunta, meu entendimento é que:

  • há uma lista de arquivos, presumivelmente um arquivo de texto input.txt
  • a lista contém somente nomes de arquivos
  • existe um diretório específico em que esses nomes de arquivos estão localizados.

Assim, pode-se usar o seguinte comando:

xargs -I % --arg-file=input.txt cp  /path/to/origin_dir/%  /path/to/destination

Explicação:

  • -I % especifica o símbolo para o arquivo atualmente processado a ser usado no comando
  • --arg-file=input.txt especifica para levar argumentos para o comando de input.txt
  • cp /path/to/origin_dir/% /path/to/destination/ executará o comando cp com /path/to/origin_dir/% sendo substituído por /path/to/origin_dir/ e nome do arquivo atualmente processado.

Exemplo prático:

$ cat input.txt
file2.txt
file1.txt
file3.txt
$ ls ./docs
file1.txt  file2.txt  file3.txt
$ xargs -I % --arg-file=input.txt cp ./docs/% ./docs_destination/
$ ls ./docs_destination/
file1.txt  file2.txt  file3.txt
    
por Sergiy Kolodyazhnyy 26.05.2018 / 09:32