我们都知道我们可以使用它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
并获得相同的结果;这里的想法是,我可以更改文本文件中的文件名、目录名、大小、权限和时间戳 - 并且有那在输出结构中重建。对于文件,我首先想到的是,只要它们被touch
ed(即大小为 0 字节)就好了 - 但最好也重建大小 - 通过填充 0x00 或随机字节,直到达到请求的大小。
它的主要用途实际上是发布问题:)
- 其中一些依赖于目录结构,例如我安装的程序;但程序本身与问题无关;然后,我可以简单地询问有关“匿名”目录树的问题,而不是针对可能碰巧安装了该程序的回答者,他们自己可以在自己的计算机上快速重建该目录树,只需将树文本描述粘贴到帖子中即可。
那么 - 有没有一种简单的方法可以实现这一目标?
答案1
我从未见过这样的工具。您可以使用多种脚本语言(包括 Bash)编写脚本,以解析输出tree
并在磁盘上重建与其匹配的相应目录。查看文本文件需要使用while
orfor
循环并使用mkdir
ormkdiir -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
不提供完整的时间戳 - 因此时间通常设置为 0tree
还将 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
除了根目录之外,这给我的输出没有任何区别(对于本例)。