我有一个目录,里面有很多子目录。因此
/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
结果并创建中间目录,您可以使用--parents
GNU cp
、rsync -R
、pax -rw
或cpio -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