将特定目录中的一种文件复制到另一个目录

Copying a type of file, in specific directories, to another directory

我有一个包含目录列表的 .txt 文件。我想制作一个脚本来遍历此 .txt 文件,将目录中列出的某种文件类型的所有内容复制到另一个目录。

我从来没有对目录做过,只对文件做过。

我如何编辑这个简单的脚本来读取目录列表、查找 .csv 文件并将其复制到另一个目录?

cat filenames.list | \
while read FILENAME
do
  find . -name "$FILENAME" -exec cp '{}' new_dir\;
done
for DIRNAME in $(dirname.list); do find $DIRNAME -type f -name "*.csv" -exec cp \{} dest \; ; done;

抱歉,在我的第一个回答中,我不明白您的要求。 第一行代码,简单地说,将目录列表中的目录名条目作为路径,并在其中搜索每个以“.csv”扩展名结尾的文件;然后将其复制到您想要的目的地。 但是你可以用更少的代码来做:

for DIRNAME in $(dirname.list); do cp $DIRNAME/*.csv dest ; done

尽管列表的文件名是 filenames.list,但我假设该文件包含目录名列表,而不是文件名。那你试试看:

while IFS= read -r dir; do
    find "$dir" -type f -name "*.mp3" -exec cp -p -- {} new_dir \;
done < filenames.list

find 命令在“$dir”中搜索扩展名为 .mp3 的文件,然后将它们复制到 new_dir.
上面的脚本不关心文件名的重复。如果您想保留原始目录树and/or需要文件名重复的对策,请告诉我。

在 while 循环中使用 find 可以工作,但是 find 会在文件的每一行上 运行,另一种方法是将列表保存在数组中,这样 find 就可以在列表中的目录中搜索一次搜索。

如果你有 bash4+,你可以使用 mapfile。

mapfile -t directories < filenames.list

如果你卡在 bash3 上。

directories=()
while IFS= read -r line; do
  directories+=("$lines")
done < filenames.list

现在,如果您只是在寻找一种文件类型,例如以 *.csv.

结尾的文件
find "${directories[@]}" -type f -name '*.csv' -exec sh -c 'cp -v -- "$@" /newdirectory' _ {} +

如果您有多个文件类型要匹配并且有多个目录要复制文件。

while IFS= read -r -d '' file; do
  case $file in
    *.csv) cp -v -- "$file" /foodirectory;;  ##: csv file copy to foodirectory
    *.mp3) cp -v -- "$file" /bardirectory;;  ##: mp3 file copy to bardirectory
    *.avi) cp -v -- "$file" /bazdirectory;;  ##: avi file copy to bazdirectory
  esac
done < <(find "${directories[@]}" -type f -print0)
在处理带有空格和换行符的文件时,

find 的 print0 将与 read 的 -d '' 一起工作。见 How can I find and deal with file names containing newlines, spaces or both?

-- 在那里,所以如果你有一个有问题的文件名,以破折号开头 - cp 不会将它解释为 option.

考虑到 find 处理多个文件夹的能力,并假设目标是 'flatten' 将所有 csv 文件放入一个目的地,请考虑以下内容。

请注意,它假定文件夹名称没有特殊字符(包括 space、制表符、换行符等)。

附带的好处是,它将最大限度地减少 'cp' 调用的次数,从而使处理过程在大量 files/folders.

中变得高效
find $(<filename.list) -name '*.csv' | xargs cp -t DESTINATION/

对于更复杂的情况,文件夹 names/file 名称可以是任何内容(包括 space、'*' 等),请考虑使用 NUL 分隔符(-print0 和 -0)。

xargs -I{} -t find '{}' -name '*.csv' <dd -print0 | xargs -0 -I{} -t cp -t new/ '{}'

这将分叉多个 find 和多个 cp