1

我得到了需要找到并复制到新位置的文件夹列表。

我有 bash 的基本知识,并创建了一个脚本来查找和复制。

我正在使用的基本命令在一定程度上是有效的:

find ./ -iname "*searchString*" -type d -maxdepth 1 -exec cp -r {} /newPath/ \;

我要解决的问题是每个找到的文件夹都包含我想要的文件,但也包含我不想要的子文件夹。

有没有办法限制递归,以便只复制找到的文件夹的根级别的文件:应该忽略其中的所有子目录和文件。

提前致谢。

4

3 回答 3

0

如果删除 -R,cp 不会复制目录:

cp *searchstring*/* /newpath

上面的命令将 dir1/file1 复制到 /newpath/file1,但是这些命令将它复制到 /newpath/dir1/file1:

  • cp --parents *searchstring*/*(.) /newpath
    • 对于 GNU cp 和 zsh
    • . 是 zsh 中常规文件的限定符
    • cp --parents dir1/file1 dir2在 GNU cp 中将 file1 复制到 dir2/dir1
  • t=/newpath;for d in *searchstring*/;do mkdir -p "$t/$d";cp "$d"* "$t/$d";done
  • find *searchstring*/ -type f -maxdepth 1 -exec rsync -R {} /newpath \;
    • -R (--relative) 就像 GNU cp 中的 --parents
  • find . -ipath '*searchstring*/*' -type f -maxdepth 2 -exec ditto {} /newpath/{} \;
    • 同上仅在 OS X 上可用
    • ditto file dir/file如果目录不存在则创建
于 2013-10-30T15:09:33.953 回答
0

所以......你已经得到了一个文件夹列表。也许在文本文件中?您没有提供示例,但您在评论中说不会有名称冲突。

一种选择是使用rsync,它可作为大多数 Unix 和 Linux 版本的附加包使用。Rsync 基本上是一种高级复制工具——你为它提供一个或多个源和一个目标,它确保事情是同步的。它知道如何递归地复制事物,但不能告诉它将递归限制在特定的深度,因此以下将复制指定的每个项目到您的目标,但它会递归地这样做。

xargs -L 1 -J % rsync -vi -a % /path/to/target/ < sourcelist.txt

如果 sourcelist.txt 包含带有 的行/foo/bar/slurm,则该slurm目录将被完整复制到/path/to/target/slurm/. 但这将包括包含在slurm.

这几乎可以在任何 shell 中工作,而不仅仅是 bash。但是如果 sourcelist.txt 中的某一行包含空格或各种特殊字符,它将失败。因此,确保您的源(在命令行或 sourcelist.txt 中)格式正确非常重要。此外,如果源目录包含尾部斜杠,则 rsync 具有不同的行为,您应该阅读手册页并确定您想要的行为。

您可以在 sh 或 bash 中相当轻松地清理输入文件。例如:

#!/bin/sh

# Avoid commented lines...
grep -v '^[[:space:]]*#' sourcelist.txt | while read line; do

    # Remove any trailing slash, just in case
    source=${line%%/}

    # make sure source exist before we try to copy it
    if [ -d "$source" ]; then
        rsync -vi -a "$source" /path/to/target/
    fi

done

但这仍然使用 rsync 的-a选项,它递归地复制东西。

我看不到单独使用 rsync 的方法。Rsync 没有-depth选择,因为find有。但我可以看到这样做分两遍——一次复制所有目录,一次复制每个目录中的文件。

所以我将举一个例子,并进一步假设文件夹名称不包含空格或换行符等特殊字符。 (这个很重要。)

首先,让我们对所有目录本身进行一次复制,而不是递归到它们:

xargs -L 1 -J % rsync -vi -d % /path/to/target/ < sourcelist.txt

-d选项创建在 sourcelist.txt 中指定的目录(如果存在)。

其次,让我们浏览一下来源列表,复制每个来源:

# Basic sanity checking on input...
grep -v '^[[:space:]]*#' sourcelist.txt | while read line; do

    if [ -d "$line" ]; then

        # Strip trailing slashes, as before
        source=${line%%/}

        # Grab the directory name from the source path
        target=${source##*/}

        rsync -vi -a "$source/" "/path/to/target/$target/"

    fi 

done

$source注意rsync 行后面的斜杠。这会导致 rsync 复制目录的内容,而不是目录

这一切有意义吗?是否符合您的要求?

于 2013-11-02T17:06:27.037 回答
-1

您可以使用 find 的ipath参数:

find . -maxdepth 2 -ipath './*searchString*/*' -type f -exec cp '{}' '/newPath/' ';'

请注意,路径./以匹配 find 的搜索目录开始,/*以排除顶级目录中的文件结束,并maxdepth设置为 2 以仅递归一级深度。

编辑:

重新阅读您的评论,您似乎想保留您从中复制的目录?例如在搜索时foo*

  • ./foo1/* ---> 复制到 /newPath/foo1/*(不是 /newPath/*)
  • ./foo2/* ---> 复制到 /newPath/foo2/*(不是 /newPath/*)

maxdepth此外,出于速度原因,另一个要求是保持为 1。

(正如评论中所指出的,以下解决方案存在特制名称的安全问题) 结合两者,您可以使用:
find 。-maxdepth 1 -type d -iname ' searchString ' -exec sh -c "mkdir -p '/newPath/{}'; cp "{}/*" '/newPath/{}/' 2>/dev/null" ';'

编辑2:

为什么不完全放弃find并使用纯bash解决方案:

for d in *searchString*/; do mkdir -p "/newPath/$d"; cp "$d"* "/newPath/$d"; done

请注意/搜索字符串末尾的 ,这会导致仅考虑匹配目录。

于 2013-10-30T15:32:03.710 回答