1

我想用纯文本创建文件夹,其结构如下:

Folder
| Subfolder
| | Deeper-subfolder
| Subfolder

我考虑过使用类似的基本命令mkdir并发现该帖子:创建目录结构的 Bash 脚本,但它仍然需要编写如下结构:

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

所以我需要更改以下中使用的正则表达式:

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

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

4

3 回答 3

4

使用纯 sed:

#!/bin/sed -f

x
G
: loop
s:\([^/]*\)/*\(.*\n\)\([^|]*\)|\s:\2\3\1/:
t loop

s/.*\n//
s:/*$::
h

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

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

接下来,我们将新目录名称附加到先前的目录路径(但两者都将用换行符分隔)。用于此的命令是“G”。

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

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

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

  1. 文件夹
  2. 子目录\n
  3. 3.

我们所要做的就是重新生成重新排列捕获的行并添加另一个斜线,这样它们就变成了:

subdir
Folder/| deeper-subdir

之后,我们有一个条件分支命令“t”,如果前一个“s”命令成功,它只会返回到“循环”标签。这意味着当字符串准备好(不再有 |s)时,我们可以退出循环并继续执行代码。

按照示例,下一次迭代包含捕获:

  1. 子目录
  2. \n
  3. 文件夹/

在循环之后,第一个替换命令删除第一行,其中包含新目录尚未进入的路径(即,新目录比前一个目录“浅”)。

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

希望这会有所帮助=)

于 2012-09-28T18:19:47.357 回答
1

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

于 2012-09-28T14:59:43.437 回答
0

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

这个想法是维护一个目录名称的“堆栈”,并根据一行有多少管道来推送或弹出。

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

#!/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
于 2012-09-28T15:44:42.130 回答