使用 find 制作目录副本

使用 find 制作目录副本

我有一个目录,里面有很多子目录。因此

/usr/local/src/ccl/ccl-1.8/x86-headers$ ls
elf  gl  gmp  gnome2  gtk2  jni  libc

C每个目录中都有一个子目录,其中包含一个文件populate.sh.我想创建一组具有相同结构的并行子目录,但在目录名称后附加一个随机值(随机值在所有情况下都应相同),并且仅包含带有文件的 C 子目录populate.sh。这些目录中除该populate.sh文件外还包含其他文件。

这是针对 makefile 的,因此为了简单起见,应该使用标准的 unix 实用程序。我正在考虑使用该-exec标志来查找,或者可能xargs会起作用,但我在理解文档时遇到了困难,而且我对 shell 脚本编写经验很少。 Perl 可能有用,但我没有使用过它,并且不想在这里使用它。

mktemp -u --tmpdir=.我过去一直使用类似的方法来生成随机字符串,但它并不理想,所以我愿意接受其他建议。理想情况下,我想要一个看起来像的名字libc.tmp_xw3st。 IE。tmp_后跟 5 位字母数字字符串。

到目前为止,我已经找到了获取顶级目录列表的方法。 :-)

find . -maxdepth 1 -type d -print0

../gmp./jni./gl./elf./libc./gtk2./gnome2

更完整的目录列表位于本文末尾。总而言之,我想创建其他目录,例如x86-headers/libc.tmpvalue,其中仅包含进一步的文件x86-headers/libc.tmpvalue/C/populate.sh

一种可能的方法的概述是分两步处理这个问题,如下所示:

步骤 1:使用 遍历顶级目录列表find,并创建相应的目录结构,例如dirname.tmpvalue/C/usingexec或通过管道传输到xargs和 using mkdir -p

步骤 2:再次运行顶级目录列表并 cppopulate.sh进入C子目录。这有点草率,因为理论上目录列表可能在两次调用之间发生变化find,但在本例中这不是问题。

/usr/local/src/ccl/ccl-1.8/x86-headers$ ls -laR

[...]

./jni:
total 96
drwxr-sr-x 3 faheem staff  4096 Jul 31 00:53 .
drwxr-sr-x 9 faheem staff  4096 Jul 31 00:53 ..
drwxr-sr-x 2 faheem staff  4096 Jul 31 00:53 C
-rw-r--r-- 1 faheem staff 19535 Jul 31 00:53 constants.cdb
[more .cdb files]

./jni/C:
total 12
drwxr-sr-x 2 faheem staff 4096 Jul 31 00:53 .
drwxr-sr-x 3 faheem staff 4096 Jul 31 00:53 ..
-rw-r--r-- 1 faheem staff  148 Jul 31 00:53 populate.sh

./libc:
total 1276
drwxr-sr-x 3 faheem staff   4096 Jul 31 00:53 .
drwxr-sr-x 9 faheem staff   4096 Jul 31 00:53 ..
drwxr-sr-x 2 faheem staff   4096 Jul 31 00:53 C
-rw-r--r-- 1 faheem staff 593125 Jul 31 00:53 constants.cdb
[more .cdb files]

./libc/C:
total 20
drwxr-sr-x 2 faheem staff  4096 Jul 31 00:53 .
drwxr-sr-x 3 faheem staff  4096 Jul 31 00:53 ..
-rwxr-xr-x 1 faheem staff 10544 Jul 31 00:53 populate.sh

答案1

这不是 的工作find,因为不涉及递归。

for x in */C/populate.sh; do
  mkdir -- "${x%%/*}$suffix"
  mkdir -- "${x%%/*}$suffix/C"
  cp -p -- "$x" "./${x%%/*}$suffix/C"
done

如果您不想保留文件的修改时间,请删除该-p选项。cp

生成随机后缀,BSD/Linuxmktemp尽可能便携。

suffix=$(mktemp -u tmp_XXXXX)

如果你想要一些看起来模糊随机并且符合 POSIX 标准的东西,这会给出一个每秒都会变化并且随位置变化的字符串;仅使用 POSIX 工具确实无法做得更好:

suffix=$({ hostname; pwd; date; } |
         cksum | uuencode -m /dev/stdin | awk 'NR==2 {print substr($0,3,5)}')

如果将此代码放入 makefile 中,请记住:

  • 所有标志加倍$
  • 将所有代码放在一行上,使用;而不是分隔 shell 指令(您可以使用反斜杠+换行符+制表符在 makefile 中放置换行符,但该序列将被删除以构建 shell 命令);
  • 以 启动 shell 片段set -e,以便在出现任何错误时中止。

答案2

您可以使用以下命令创建每个顶级目录的副本

$ find . -maxdepth 1 -type d -exec mkdir {}".tmpvalue" \;

然后,您可以迭代该.sh文件并将其复制到每个目录。

答案3

尝试这样的事情:

#!/bin/sh
# Create a temporary partial clone of the current directory
tcopy=`mktemp -d /tmp/tmp_XXXXX`
tbase=`basename $tcopy`
find . -name populate.sh -print | cpio -pud "$tcopy"

# Randomize the clone
for d in "$tcopy"/*
do
    mv "$d" "$d.$tbase"
done

# Merge the clone back into the current tree
mv "$tcopy"/* .

这取决于mv知道如何跨文件系统移动整个目录的实现。 GNUmv可以,但我记得在一些旧的 Unix 机器上工作时,最后一行不起作用。find | cpio在这种情况下,您可以使用另一个通道。mv如果有效,效率会更高。

答案4

如果其他人搜索如何复制find结果并创建中间目录,您可以使用--parentsGNU cprsync -Rpax -rwcpio -pd

find . -type f -exec cp --parents -t /tmp {} +
  --parents creates intermediate directories in GNU cp
  -t specifies a target directory in GNU cp
find . -type f -print0|xargs -0I, rsync -R , /tmp
  -R is --relative
find . -type f|pax -rw /tmp
  -rw (read and write) copies files
  pax is required by POSIX but not LSB and not included by some Linux distributions
find . -type f|cpio -pdu /tmp
  -p (pass-through) copies paths from stdin to a specified directory
  -d creates intermediate directories
  -u unconditionally overwrites existing files

相关内容