“树”的相反 - 从文本文件内容重建文件和目录结构?

“树”的相反 - 从文本文件内容重建文件和目录结构?

我们都知道我们可以使用它tree来获得目录结构的格式良好的文本“可视化”;说:

$ tree -spugD /usr/include/boost/accumulators/numeric/
/usr/include/boost/accumulators/numeric/
├── [drwxr-xr-x root     root            4096 Dec 19  2011]  detail
│   ├── [-rw-r--r-- root     root            2681 Oct 21  2010]  function1.hpp
│   ├── [-rw-r--r-- root     root             406 Oct 21  2010]  function2.hpp
│   ├── [-rw-r--r-- root     root             409 Oct 21  2010]  function3.hpp
│   ├── [-rw-r--r-- root     root             409 Oct 21  2010]  function4.hpp
│   ├── [-rw-r--r-- root     root            6725 Oct 21  2010]  function_n.hpp
│   └── [-rw-r--r-- root     root             530 Oct 21  2010]  pod_singleton.hpp
├── [drwxr-xr-x root     root            4096 Dec 19  2011]  functional
│   ├── [-rw-r--r-- root     root            2316 Oct 21  2010]  complex.hpp
│   ├── [-rw-r--r-- root     root           16627 Oct 21  2010]  valarray.hpp
│   └── [-rw-r--r-- root     root           12219 Oct 21  2010]  vector.hpp
├── [-rw-r--r-- root     root            9473 Oct 21  2010]  functional_fwd.hpp
└── [-rw-r--r-- root     root           21312 Oct 21  2010]  functional.hpp

2 directories, 11 files

我想要的是相反的 - 给定一个包含上述内容的文本文件dirstruct.txt,我可以写这样的东西(伪):

$ reverse-tree dirstruct.txt -o /media/destpath

...所以,/media/destpath如果目录不存在,就会创建目录,并且在里面我会得到detail包含文件function1.hpp等的子文件夹;根据上面的树。

当然,我总是可以复制一份cp -a并获得相同的结果;这里的想法是,我可以更改文本文件中的文件名、目录名、大小、权限和时间戳 - 并且有在输出结构中重建。对于文件,我首先想到的是,只要它们被touched(即大小为 0 字节)就好了 - 但最好也重建大小 - 通过填充 0x00 或随机字节,直到达到请求的大小。

它的主要用途实际上是发布问题:)- 其中一些依赖于目录结构,例如我安装的程序;但程序本身与问题无关;然后,我可以简单地询问有关“匿名”目录树的问题,而不是针对可能碰巧安装了该程序的回答者,他们自己可以在自己的计算机上快速重建该目录树,只需将树文本描述粘贴到帖子中即可。

那么 - 有没有一种简单的方法可以实现这一目标?

答案1

我从未见过这样的工具。您可以使用多种脚本语言(包括 Bash)编写脚本,以解析输出tree并在磁盘上重建与其匹配的相应目录。查看文本文件需要使用whileorfor循环并使用mkdirormkdiir -p创建目录或嵌套目录结构,然后使用该touch命令在文本文件中创建文件的空版本。

如果您想完全复制结构,您甚至可以复制自此以来关联的时间戳mkdir,并且两者都将其作为参数提供。touch

答案2

当我再次需要这个时,我编写了一个 Perl 脚本来完成它;结果有点复杂,所以我在这里发布:

它的作用是解析 - 的输出tree,但与 OP 示例不同,它还需要该--dirsfirst选项。为了避免记住所有这些,revrs-tree.pl可以首先像这样使用:

perl revrs-tree.pl --getdir /usr/include/boost/accumulators/ > test.tree

...这将简单地tree使用正确的选项进行调用,输出到标准输出 - 我们将其捕获在文件中test.tree

然后,我们在 this 内容上调用相同的脚本test.tree;但诀窍是,输出不是目录/文件本身 - 而是bash脚本中的行,打印到标准输出。调用看起来像这样:

perl revrs-tree.pl --zerofill test.tree > test-tree.sh
# alternatively, can receive tree text from stdin:
cat test.tree | perl revrs-tree.pl --zerofill > test-tree.sh

...然后test-tree.sh包含以下内容:

RTD="/usr/include/boost/accumulators";
read -p "WARNING! will output in '$RTD' directory!
Press [Enter] key to start output...";
if [ ! -d "$RTD" ] ; then mkdir "$RTD" ; fi ;

TDIR="$RTD/framework";
mkdir "$TDIR"; sudo chown root:root "$TDIR"; sudo chmod 755 "$TDIR"; sudo touch -d 'Jul 16 2014 9:43:00' "$TDIR";

TDIR="$RTD/framework/accumulators";
mkdir "$TDIR"; sudo chown root:root "$TDIR"; sudo chmod 755 "$TDIR"; sudo touch -d 'Jul 16 2014 9:43:00' "$TDIR";

TFIL="$RTD/framework/accumulators/droppable_accumulator.hpp";
cat /dev/zero | head --bytes 9740 >  "$TFIL";
touch -d 'Oct 21 2010 0:00:00' "$TFIL"; sudo chown root:root "$TFIL"; sudo chmod 644 "$TFIL";
...

这里的技巧是:

  • 请记住在运行脚本之前更改RTD- 我没有一次,并且设法/usr/include/boost/accumulators用零填充的文件覆盖! (这sudo apt-get remove --purge libboost1.42-dev && sudo apt-get install libboost1.42-dev对我来说是必需的)!!! (这就是为什么脚本将在启动时等待用户输入)...假设您已将其更改为/tmp/newtarget.
  • tree不提供完整的时间戳 - 因此时间通常设置为 0
  • tree还将 uids/gids 截断为 7 或 8 个字符 - 因此,如果您的长度超过这些字符,请检查脚本.sh并在适当的地方进行替换。

然后,因为碰巧 OP 示例是root拥有目录,所以.sh脚本包含sudo在适当的位置,因此您不妨将其称为超级用户:

sudo bash test-tree.sh

经过大量set -x打印输出后,脚本应该完成;然后您可以使用diff- 或来检查目录/文件树结构是否正确重建meld

meld <(tree -spugD /tmp/newtarget/) <(tree -spugD /usr/include/boost/accumulators/)

tree除了根目录之外,这给我的输出没有任何区别(对于本例)。

相关内容