四时宝库

程序员的知识宝库

shell中如何重新创建目录层次结构,但不包括文件?

  • 使用 cpio 程序:
cd -- "$srcdir" &&
find . -type d -print | cpio -dumpv -- "$dstdir"
  • 或者使用 pax 程序:
cd -- "$srcdir" &&
find . -type d -print | pax -rwdv -- "$dstdir"
  • 或者使用 GNU tar 和更详细的语法:
cd -- "$srcdir" &&
find . -type d -print | tar c --files-from - --no-recursion |
  tar x --directory "$dstdir"

这个方法使用 find 创建一个目录名称列表,将只添加目录到归档文件中,并将其传输到第二个 tar 实例以在目标位置解压。可以看出,tar 最不适合此任务,但由于人们普遍喜爱它,因此在这里介绍以满足 tar 粉丝的需求。(注意:使用典型的 Unix tar 完全无法完成此任务。另请注意:“标准 tar”并不存在,因为 POSIX 故意省略了 tar 和 cpio,选择了 pax。)

上述所有解决方案在目录名称包含换行符时会失败。在许多现代 BSD/GNU 系统上,可以轻松修改这些解决方案以处理这种情况,方法是使用 find -print0 和 pax -0 或 cpio -0 或 tar --null(请查看您的系统文档,了解您的系统支持哪些命令以及可用的扩展)。如果您确实无法使用这些选项,那么您可能至少可以使用 ! -path ' \n' -prune -o -type d -print(而不是 -type d -print),以忽略路径中包含换行符的目录。请确保以 C/POSIX 区域设置运行 find,以排除包含换行符以及用户区域设置中无效字符序列的文件路径。

  • 使用 find:
export dstdir
mkdir -p -- "$dstdir" &&
cd -- "$srcdir" &&
find . -type d -exec sh -c \
  'cd -- "$dstdir" && mkdir -- "$@"' sh {} +

或者使用 bash 4 的 globstar:

shopt -s globstar nullglob &&
cd -- "$srcdir" && dirs=(**/) && (( ${#dirs[@]} )) &&
cd -- "$dstdir" && mkdir -- "${dirs[@]}"

(请注意,这也会将符号链接复制为目录;旧版本的 bash 在遍历目录树时也会遍历符号链接)。

  • 或者使用 zsh 的递归通配符和通配符修饰符:
export srcdir dstdir
zsh -ec '
cd -- "$srcdir"
dirs=(**/*(/D))
cd -- "$dstdir"
mkdir -- $dirs'
  • 如果您想要创建占位文件而不是完整大小的文件,以下可能是最简单的解决方案。find 命令使用“虚拟”文件(具有相同时间戳的空文件)重新创建常规文件:
cd -- "$srcdir" &&
DSTDIR=$dstdir find . -type f -exec sh -c \
  'for i do touch -r "$i" -- "$DSTDIR/$i"; done' sh {} +

如果您的 find 无法处理 -exec +,则可以在命令的末尾使用 ; 替代 +。


如果您觉得文章内容对你有一点帮助可以关注我,我在头条平台会持续分享更多实用的shell技巧和最佳实践,如果想系统的快速学习shell的各种高阶用法和生产环境避坑指南可以看看《shell脚本编程最佳实践》专栏,专栏里有更多的实用小技巧和脚本代码分享。

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言
    友情链接