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

时间:2012-09-28 14:46:09

标签: regex linux bash automation mkdir

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

Folder
| Subfolder
| | Deeper-subfolder
| Subfolder

我考虑使用像mkdir这样的基本命令并发现帖子:Bash script that creates a directory structure,但它仍然需要编写如下结构:

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

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

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

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

3 个答案:

答案 0 :(得分: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. 将所有内容捕获到换行符(包括)并存储到捕获\2\(.*\n\)
  4. 在第一个之前捕获所有内容字符和存储到捕获\3\([^|]*\)
  5. 跳过|字符后跟空格字符:|\s
  6. 现在,捕获看起来像这样:

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

      我们所要做的就是重新生成重复捕获的行并添加另一个斜杠,以便它们变为:

      subdir
      Folder/| deeper-subdir
      

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

      在示例之后,下一次迭代包含捕获:

      1. 子目录
      2. \ n
      3. 文件夹/
      4. 循环之后,第一个替换命令删除第一行,其中包含新目录尚未输入的路径(即新目录比前一个目录“浅”)。

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

        希望这有助于=)

答案 1 :(得分:1)

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

答案 2 :(得分: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