更好的bash脚本来创建目录结构



我想创建具有以下结构的纯文本文件夹:

Folder
| Subfolder
| | Deeper-subfolder
| Subfolder

我考虑过使用像mkdir这样的基本命令,发现post:Bash脚本创建了一个目录结构,但它仍然需要编写像这样的结构

Folder
Folder/subfolder
Folder/subfolder/deeper-subfolder
Folder/subfolder

因此,我需要更改中使用的正则表达式

sed '/^$/d;s/ ///g' struct.txt | xargs mkdir -p

我可以使用什么bash命令来执行此操作?

使用纯sed:

#!/bin/sed -f
x
G
: loop
s:([^/]*)/*(.*n)([^|]*)|s:231/:
t loop
s/.*n//
s:/*$::
h

为此,我们必须使用保持空间(一个辅助缓冲区)来存储以前的dir路径。然后,我们可以从保留空间中删除目录,并将它们替换到相应的|s中。更详细的解释如下:

这个脚本对每一行都执行。我们要做的第一件事是交换("x")保持空间和模式空间。最初,保留空间是空的,但在第一行之后,保留空间将包含上一个目录路径。通过交换它们,我们加载上一个目录,并将当前的新目录保存到保留空间中。

接下来,我们将新的目录名附加到上一个目录路径上(但两者都将用换行符分隔)。用于此操作的命令为"G"。

现在,我们必须为找到的每一个|字符循环。要做到这一点是棘手的部分,所以请耐心等待。假设我们在当前的模式空间中有以下内容

Folder/subdir
| | deeper-subdir
  1. 首先,([^/]*)匹配第一个斜杠之前的所有内容并捕获它(即将其存储在一个"变量"中,因为它是第一个捕获组,所以命名为1)
  2. 然后我们跳过斜线:/*
  3. 捕获换行符之前的所有内容(包括换行符)并存储到捕获2:(.*n)
  4. 捕获第一个|字符之前的所有内容并存储到捕获3中:([^|]*)
  5. 跳过后面跟着空格字符的|字符:|s

现在,捕获看起来像这样:

  1. 文件夹
  2. 子\r\n
  3. 3.

我们所要做的就是重新生成重新记录捕获的行,并添加另一个斜线,使其成为:

subdir
Folder/| deeper-subdir

在那之后,我们有一个条件分支命令"t",只有在前一个"s"命令成功的情况下,它才会排回"循环"标签。这意味着当字符串准备好(不再有|s)时,我们可以退出循环并继续执行代码。

根据示例,下一次迭代包含捕获:

  1. 分区
  2. \n
  3. 文件夹/

循环后,第一个替换命令删除第一行,其中包含新目录未输入的路径(即,新目录比上一个目录"浅")。

最后一个替换命令删除行末尾的任何斜杠,最后一个命令是一个保留命令("h"),它将当前生成的路径复制到保留空间,因此我们可以在下一行重复所有操作。

希望这有帮助=)

只需更改所提供的sed脚本中的正则表达式是无法做到这一点的。原因是在您引用的具有目录结构的文件的每一行的示例中,都有足够的信息来创建目录。在您的示例中,您需要进行一些数据操作,以跟踪父文件夹。这将更加复杂。。除非迫不得已,否则我们不喜欢引入复杂性

下面的脚本应该可以做到这一点。

其想法是维护目录名的"堆栈",并根据一行的管道数量推送或弹出。

(此脚本假定输入文件格式正确,文件名中不包含任何空行或特殊字符。)

#!/bin/bash
file=$1
# helper function to create a directory from an array
mkDirs(){
IFS=/ dir="$*"
echo "mkdir -p $dir"
}
declare -a stack=()
while read line
do
dirName="${line##*| }"
pipes="${line//[^|]/}"
num_pipes="${#pipes}"
diff=$(( ${#stack[@]} - $num_pipes ))
if [[ "$diff" -ne 0 ]]
then
# create the directory
mkDirs "${stack[@]}"
while (( "$diff" != 0 ))
do
unset stack[${#stack[@]}-1] # pop off stack
diff=$(( ${#stack[@]} - $num_pipes ))
done
fi
stack=("${stack[@]}" "$dirName") # push on stack
done < "$file"
mkDirs "${stack[@]}"

示例:

$ cat struct.txt
Folder
| Subfolder
| | Deeper-subfolder
| Subfolder
| | SubSubFolder
| | | Another
| | | | AnotherChild
| | | YetAnother
Folder2
$ run.sh struct.txt
mkdir -p Folder/Subfolder/Deeper-subfolder
mkdir -p Folder/Subfolder/SubSubFolder/Another/AnotherChild
mkdir -p Folder/Subfolder/SubSubFolder/YetAnother
mkdir -p Folder2

最新更新