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

问题描述 投票:1回答:3

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

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命令来执行此操作?

regex linux bash automation mkdir
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. 将所有内容捕获到换行符(包括)并存储到捕获\2\(.*\n\)
  4. 在第一个之前捕获所有内容角色和存储到捕获\3\([^|]*\)
  5. 跳过|字符后跟空格字符:|\s

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

  1. 子目录\ n
  2. 3.

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

subdir
Folder/| deeper-subdir

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

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

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

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

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

希望这有助于=)


1
投票

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


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
© www.soinside.com 2019 - 2024. All rights reserved.