Skip to content

Instantly share code, notes, and snippets.

@vallahor
Last active January 13, 2024 15:20
Show Gist options
  • Save vallahor/d69ae793e23ab23e6b2e47a686a9cd80 to your computer and use it in GitHub Desktop.
Save vallahor/d69ae793e23ab23e6b2e47a686a9cd80 to your computer and use it in GitHub Desktop.

usage

python makedirs.py -f input.txt -o output.txt -indent 4

From a given txt file of directories and/or files structured by indentation generate a sh script that can create that directory tree. Be carefull with indentation.

Example:

input.txt

css/
    styles.css
    version/
index.html
javascript/
    index.js
    timer.js
    modules/
        work.js
    stuff.js
src/
    css/
        style.css
    js/
        main.js
        module/
            src.js
README.md

test/
    one/
        a/ b/ c/
                    file_c.txt
                file_b.txt
    two/
        a/
            b/
                c/
                    file_c.txt
                file_b.txt

    three/ a/
            b/ c/
                    file_c.txt
                file_b.txt

    four/ a/ b/
                c/ d/
                        e/

output.sh

mkdir -p {css,javascript,src,test}
touch {index.html,README.md}
touch css/styles.css
mkdir -p css/version/
touch javascript/{index.js,timer.js,stuff.js}
mkdir -p javascript/modules/
touch javascript/modules/work.js
mkdir -p src/{css,js}
touch src/css/style.css
touch src/js/main.js
mkdir -p src/js/module/
touch src/js/module/src.js
mkdir -p test/{one,two,three,four}
touch test/one/a/b/file_b.txt
mkdir -p test/one/a/b/c/
touch test/one/a/b/c/file_c.txt
touch test/two/a/b/file_b.txt
mkdir -p test/two/a/b/c/
touch test/two/a/b/c/file_c.txt
touch test/three/a/b/file_b.txt
mkdir -p test/three/a/b/c/
touch test/three/a/b/c/file_c.txt
mkdir -p test/four/a/b/c/d/e/
import argparse
INDENT_SIZE = 4
class Directory:
def __init__(self, name):
self.name = name
self.directories = []
self.files = []
self.created = False
def parse_dir(
lines: list[str], dir_name: str, position: int = 0, indent: int = 0
) -> (Directory, int):
dir = Directory(dir_name)
index = 0
while position + index < len(lines):
line = lines[position + index]
name = line.lstrip()
current_indent = len(line) - len(name)
if len(line) == 0:
index += 1
continue
if current_indent < indent:
break
if name[-1] == "/":
next_position = position + index + 1
cur_dir, idx = parse_dir(lines, name, next_position, current_indent + 1)
dir.directories.append(cur_dir)
index += idx
else:
dir.files.append(name)
index += 1
return dir, index
def gen_dir(lines: list[str]) -> Directory:
result = []
for line in lines:
line = line.replace("\n", "").rstrip()
if line.count("/") > 1:
dirs = []
name = line.lstrip()
indent = len(line) - len(name)
for index, dir in enumerate(name.split("/")):
if dir == "":
continue
space_size = indent + INDENT_SIZE * index
spaces = " " * space_size
dirs.append(f"{spaces}{dir.lstrip()}/")
result.extend(dirs)
continue
result.append(line)
root_dir, _ = parse_dir(result, "root")
return root_dir
def make_line(cmd: str, path: str, fields: list[str]) -> str:
sep, lhs, rhs = "", "", ""
if len(fields) > 1:
sep, lhs, rhs = ",", "{", "}"
names = sep.join(fields)
return f"{cmd} {path}{lhs}{names}{rhs}\n"
def gen_sh(dir: Directory, path: str = "") -> str:
mkdir = touch = txt = result = ""
if len(dir.directories) == 1:
directory = dir.directories[0]
result = gen_sh(directory, f"{path}{directory.name}")
else:
dir_names = []
if len(dir.directories) > 1:
for directory in dir.directories:
directory.created = True
dir_names.append(directory.name[:-1])
result += gen_sh(directory, f"{path}{directory.name}")
if not dir.created or len(dir_names) > 0:
mkdir = make_line("mkdir -p", path, dir_names)
if len(dir.files) > 0:
files_name = [file for file in dir.files]
touch = make_line("touch", path, files_name)
txt += f"{mkdir}{touch}{result}"
return txt
parser = argparse.ArgumentParser()
parser.add_argument("-f", "--file", type=str, nargs="?", help="file containing directory tree", default="input.txt")
parser.add_argument("-o", "--output", type=str, nargs="?", help="output filename", default="output.sh")
parser.add_argument("-i", "--indent", type=int, nargs="?", help="directory/file indent size", default=4)
def main():
args = parser.parse_args()
INDENT_SIZE = args.indent
with open(args.file, "r") as f:
lines = f.readlines()
root_dir = gen_dir(lines)
txt = gen_sh(root_dir)
with open(args.output, "w") as f:
f.write(txt)
print(txt)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment