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

133

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

Alguém com muitas fotos demais
fonte
Para copiar, use pastas específicas:, cp -rp /copying/from/{folder1/,folder2/,folder3/} path/to/folderonde pé para copiar a permissão da pasta.
Raktim Biswas

Respostas:

179

Simplesmente copie vários arquivos de uma vez da linha de comando

Existem várias maneiras de conseguir isso. O mais fácil que eu já 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 em que os arquivos desejados estão localizados, com todos os arquivos que você deseja copiar entre colchetes e separados por vírgulas.

Certifique-se de observar 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 com finais diferentes, você poderá fazer algo assim:

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

Onde arquivo1, arquivo2, arquivo3 e arquivo4 seriam copiados.

De como você formulou a pergunta, acredito que é isso que você está procurando, mas também parece que você pode estar procurando um comando para ler uma lista de arquivos e copiá-los para um determinado diretório. Se for esse o caso, avise-me e editarei minha resposta.

Lidando com duplicatas com python

Então, escrevi um pequeno script python que acredito que deve fazer o trabalho. No entanto, não tenho certeza de quão bem você é versado em python (se é que é versado), então tentarei explicar como usar esse script da melhor maneira possível e por favor, faça quantas perguntas você precisar.

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))

Este 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.

Após a conclusão, salve o arquivo como move.py no diretório inicial (pode ser qualquer diretório, mas para facilitar as instruções, basta usar o diretório inicial) ou adicione o diretório em que o arquivo está contido no PATH. Em seguida, cdvá para o diretório inicial (ou qualquer diretório que você salvou move.py in) no terminal e digite o seguinte comando:

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

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

De maneira alguma esse script deve afetar o diretório de origem, no entanto, certifique-se de inserir os caminhos corretos para o diretório de origem e destino e o pior que pode acontecer é que você copie os arquivos para o diretório errado.

Notas

  • Este script supõe que todas as imagens originais estejam no mesmo diretório. Se você quiser verificar também os subdiretórios, o script precisará ser modificado.
  • Se você digitar um nome de arquivo acidentalmente, o script emitirá o erro
    "o arquivo não existe" e solicitará que você "pressione enter" para continuar e o script continuará copiando o restante da lista.
  • Não esqueça a /trilha no caminho para o
    diretório de origem e no caminho para o diretório de destino. Caso contrário, o script cuspirá um erro de volta para você.
Bryan
fonte
Obrigado, que resolveu a maior parte do meu problema, no entanto, alguns arquivos aparecem na lista duas ou mais vezes. Como posso renomear essas duplicatas automaticamente? (Sim, preciso das duplicatas para o que estou fazendo.)
Alguém com muitas fotos em
As duplicatas de diferentes subpastas ou são rotuladas como file.jpg e file (1) .jpg? caso contrário, não tenho certeza de como você tem arquivos idênticos. Para responder de alguma forma à sua pergunta, não acredito que você consiga encontrar um simples liner que renomeie automaticamente duplicatas para você. Eu acho que um bash ou algum outro tipo de script precisaria ser escrito para obter esse tipo de funcionalidade. No entanto, eu vi alguns comandos de uma linha bastante ridículos, então talvez algum assistente do linux possa aparecer e fornecer a resposta.
Bryan
Eu tenho apenas um de cada arquivo originalmente, no entanto, os nomes dos arquivos estão na lista duas ou mais. Mais ou menos o que eu preciso fazer, ao tentar colocar um arquivo na nova pasta, e um arquivo com esse nome já existe, eu preciso adicionar um (2) ou mais ao final do nome do arquivo e coloque.
Alguém com muitas fotos em
Eu só quero sugerir enfatizar a parte de não ter espaços na lista de arquivos para copiar. Se houver espaços, mesmo entre os arquivos {foo, bar, ..}, o comando não funcionará.
19418 franksands
Para aqueles que procuram mais atalhos, você pode usar a substituição de comandos para substituir o caminho absoluto dos arquivos, cp $(pwd)/{file1,file2} /path/to/dst/ou seja cp $(pwd)/{file1,file2} $(pwd)/{renamed1,renamed2}, etc.
baelx 17/01
49

Talvez esteja faltando um detalhe da sua pergunta, mas as respostas dadas parecem excessivas. Se você deseja 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 dessa maneira é que você pode tabular os nomes dos arquivos

Ross Allen
fonte
5
Este retorna um "--CAMISA opção ilegal" no MacOS Sierra
geoyws
Ótima resposta, muito mais simples. @geoyws Talvez seja uma coisa POSIX ou GNU que a versão da Apple não tenha. Funciona bem para mim no Debian Linux ou Windows com MSYS2.
Sublinhado #
boa sugestão! trabalhou em arch linux.
Edu Ruiz
brew install coreutilsentão você pode obter coisas gnu usuais com gprefixo. Então, isso será o seguintegcp -t ....
T.Chmelevskij 22/17
O Mac OS usa a versão BSD do cp, e particularmente o OpenBSD e o FreeBSD não têm essa opção, então sim - isso é cp específico ao GNU . Também não é especificado pelo padrão POSIX . Uma vez que este é o Ubuntu site específico, isto é aceitável, mas para portar certificados entre sistemas operacionais, é melhor ficar com padrão POSIX
Sergiy Kolodyazhnyy
7

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

#!/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 $PATHe chame-o com a lista de caminhos como entrada:

auto_copy.sh < file_paths.txt

Você também pode executar a coisa toda 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;
terdon
fonte
1

Conforme descrição da pergunta, meu entendimento é que:

  • existe uma lista de arquivos, presumivelmente um arquivo de texto input.txt
  • a lista contém apenas 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 do arquivo processado atualmente a ser usado no comando
  • --arg-file=input.txt especifica receber argumentos para comandar de input.txt
  • cp /path/to/origin_dir/% /path/to/destination/executará o cpcomando /path/to/origin_dir/%sendo substituído por /path/to/origin_dir/e nome do arquivo processado atualmente.

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
Sergiy Kolodyazhnyy
fonte