将多个特定文件从一个文件夹复制到另一个


133

我有一个很大的图片文件夹(上千个),并且我有一长串文件(按确切的文件名),需要将其复制到另一个文件夹。我想知道是否有一种方法可以从该文件夹中按名称选择几个特定文件,然后使用终端将它们复制到另一个文件夹中,而不必分别复制它们?


Fyi,用于复制特定文件夹,请使用:cp -rp /copying/from/{folder1/,folder2/,folder3/} path/to/folder,其中p用于复制文件夹权限。
拉克蒂姆·比斯瓦斯

Answers:


179

只需从命令行一次复制多个文件

有几种方法可以实现此目的。我见过的最简单的方法是使用以下内容。

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

该语法使用cp命令,后跟所需文件所在目录的路径,所有要复制的文件都用方括号括起来并用逗号分隔。

请确保注意文件之间没有空格。该命令的最后一部分/home/usr/destination/是您要将文件复制到的目录。

或者如果所有文件都具有相同的前缀但结尾不同,则可以执行以下操作:

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

其中file1,file2,file3和file4将被复制。

从问题的措辞来看,我相信这是您要查找的内容,但是听起来您可能正在寻找一条命令,以从文件列表中读取文件并将它们全部复制到某个目录中。如果是这种情况,请告诉我,我将编辑答案。

使用python处理重复项

所以我写了一些python脚本,我相信应该可以完成工作。但是,我不确定您是否精通python(如果完全精通),因此我将尽力解释如何使用此脚本,并请根据需要询问尽可能多的问题。

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

该脚本应该相对简单易用。首先,将以上代码复制到程序gedit(应在Ubuntu中预安装)或任何其他文本编辑器中。

完成此操作后,将文件另存为您的主目录中的move.py(它可以是任何目录,但为了便于说明,请仅使用主目录),或将文件所在的目录添加到PATH中。然后cd从终端到您的主目录(或保存了move.py的任何目录),并键入以下命令:

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

这应该将源目录中列出的所有文件复制到目标目录中,并带有格式为pic(1).jpg,pic(2).jpg等的重复项。 file.txt应该是一个文件,其中列出您要复制的所有图片,并且每个条目都在其单独的行上。

此脚本绝不会影响源目录,但是请确保输入正确的源目录和目标目录路径,最糟糕的情况是将文件复制到错误的目录。

笔记

  • 该脚本假定所有原始图片都在同一目录中。如果您还希望它检查子目录,则需要修改脚本。
  • 如果您不小心输入了错误的文件名,脚本将吐出错误
    “文件不存在”,并提示您“按Enter”以继续,脚本将继续复制列表的其余部分。
  • 不要忘记/
    目录路径和目标目录路径上的尾随。否则,脚本将向您吐出一个错误。

谢谢,这解决了我的大部分问题,但是,某些文件出现在列表中两次或更多次,如何使它自动重命名这些重复项?(是的,我需要做的是重复的事情。)
有人pict太多了

是来自不同子文件夹的重复项,还是带有诸如file.jpg和file(1).jpg之类的标签?否则,我不确定您的文件是否相同。为了以某种方式回答您的问题,我认为您将无法找到一种简单的衬纸,可以自动为您重命名重复项。我认为必须编写bash或其他类型的脚本才能获得这种功能。但是,我看到了一些非常荒谬的单行命令,因此也许某些Linux向导可能会出现并提供答案。
布莱恩

我最初每个文件只有一个,但是文件名在列表中两次或多次。尝试将文件放置在新文件夹中并且已经存在该名称的文件时,我或多或少需要执行该操作,我需要在文件名的末尾添加(2)左右并放置它。
某人的图片太多了(2013年

我只想建议强调有关要复制的文件列表中没有空格的部分。如果在文件{foo,bar,..}之间有空格,该命令将不起作用。
franksands

对于那些寻求进一步的快捷方式,你可以利用命令替换的站在了文件,即绝对路径cp $(pwd)/{file1,file2} /path/to/dst/cp $(pwd)/{file1,file2} $(pwd)/{renamed1,renamed2}
baelx

49

也许我缺少您的问题的详细信息,但给出的答案似乎过多。如果要命令行解决方案而不是脚本,为什么不这样做:

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

这样做的好处是您可以使用Tab键完成文件名


4
这将在macOS Sierra中返回“非法选项--t”
geoyws,2016年

好的答案,简单得多。@geoyws也许是苹果版本所没有的POSIX或GNU。它在Debian Linux或带有MSYS2的Windows上对我来说很好用。
underscore_d

好建议!在Arch Linux中工作。
Edu Ruiz

brew install coreutils那么您可以获得带g前缀的常用gnu内容。这样就可以了gcp -t ....
T.Chmelevskij

Mac OS使用的BSD版本cp,尤其是OpenBSDFreeBSD都没有该选项,因此是的-这是GNU cp 特定的。POSIX标准也未指定。由于这是Ubuntu特定站点,因此可以接受,但是对于在OS之间移植脚本,最好坚持使用POSIX标准
Sergiy Kolodyazhnyy

7

这是一个纯bash解决方案。它将从输入文件中读取文件名(每行一个)并复制每个文件名,重命名重复项。

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

将此脚本保存在您的文件夹中,$PATH并以路径列表作为输入进行调用:

auto_copy.sh < file_paths.txt

您还可以从终端作为命令运行整个程序:

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;

1

根据问题的描述,我的理解是:

  • 有文件列表,大概是文本文件 input.txt
  • 该列表仅包含文件名
  • 这些文件名位于一个特定的目录中。

因此,可以使用以下命令:

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

说明:

  • -I % 指定要在命令中使用的当前处理文件的符号
  • --arg-file=input.txt 指定接受参数作为命令 input.txt
  • cp /path/to/origin_dir/% /path/to/destination/将执行cp命令,/path/to/origin_dir/%并替换为/path/to/origin_dir/和当前处理的文件名。

实际示例:

$ 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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.