Skip to content

Instantly share code, notes, and snippets.

@kflorence
Last active April 26, 2024 20:30
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kflorence/7f18ad97c65337ef77d37159260a331d to your computer and use it in GitHub Desktop.
Save kflorence/7f18ad97c65337ef77d37159260a331d to your computer and use it in GitHub Desktop.
Creates a markdown table of contents from a file tree (omitting the directory itself, "readme.md" files and "images" folders and their contents)
#!/usr/bin/env bash
# This script generates markdown from the output of the `tree` command.
# See: https://linux.die.net/man/1/tree
# See: https://gist.github.com/kflorence/7f18ad97c65337ef77d37159260a331d
set -e
# Tree is configured with:
# - `-f`: use full paths in output (relative to directory given, in this case '.').
# - `--noreport`: exclude the directories and files report as the last line of output.
# - `-I "readme.md"`: exclude any "readme.md" files, redundant with the link to the directory containing that file.
# - `-P "*.md"`: only include Markdown files (files ending with ".md").
# - `--charset ascii`: use ASCII characters instead of unicode (makes parsing easier).
# - `--sort=name`: sort the tree structure by name, alphabetical.
#
# There are then a series of sed commands. These commands:
# - remove any lines ending with `/images` (excludes /images folders).
# - remove any blank lines (cleans up after the above to remove lines that only include line endings).
# - replace any backticks (`) with pipes (|) -- this makes parsing of the output easier.
# - replace " |" with "| |" -- makes the last-child prefix more consistent and easier to parse.
# - replace "| " with " " -- fixes whitespace to conform to Markdown conventions (spaces of two).
# - replace "|--" with "-" -- turns the item prefix into a hyphenated bullet point.
#
# At this point, the remaining lines are formatted to be ending like "- foo/bar/baz.md". The last command:
# - creates three matching groups, one for "foo/bar/baz.md", one for "foo/bar" and one for "baz.md".
# - replaces "- foo/bar/baz.md" with "- [baz.md](foo/bar/baz.md)".
# - replaces "- [baz.md](foo/bar/baz.md)" with "- [baz](foo/bar/baz.md)"
#
# Finally, `tail -n +2` removes the first two lines of the output (a newline and the "." for the root directory).
markdown=$(cd "$1" && tree -f --noreport -I "readme.md" -P "*.md" --charset ascii --sort=name . |
sed \
-e 's:.*/images$::g' \
-e '/^$/d' \
-e 's/`/|/g' \
-e 's/ |/| |/g' \
-e 's/| / /g' \
-e 's/|--/-/g' \
-e 's:- \(\(.*\)/\(.*\)\):- [\3](\1):g' \
-e 's/\.md]/]/g' |
tail -n +2)
# The output is then returned with a trailing newline character.
printf "%s\n" "$markdown"
@kflorence
Copy link
Author

kflorence commented Oct 26, 2021

Example output from tree -tf --noreport -I "readme.md" -P "*.md" --charset ascii .:

.
|-- ./conventions
|   |-- ./conventions/api
|   |   `-- ./conventions/api/rest.md
|   |-- ./conventions/application
|   |   `-- ./conventions/application/usage-context.md
|   |-- ./conventions/auth
|   |   `-- ./conventions/auth/auth0.md
|   |-- ./conventions/git
|   |   `-- ./conventions/git/workflow.md
|   |-- ./conventions/infrastructure
|   |   `-- ./conventions/infrastructure/terraform.md
|   |-- ./conventions/jvm
|   |   `-- ./conventions/jvm/packages.md
|   |-- ./conventions/logback
|   `-- ./conventions/messaging
|       `-- ./conventions/messaging/kafka.md
|-- ./guides
|   |-- ./guides/auth
|   |   `-- ./guides/auth/auth0.md
|   |-- ./guides/github
|   |   `-- ./guides/github/workflows
|   |       |-- ./guides/github/workflows/aws-codebuild-codepipeline.md
|   |       `-- ./guides/github/workflows/images
|   |-- ./guides/lagom
|   |   `-- ./guides/lagom/developer-experience.md
|   |-- ./guides/migration
|   |   `-- ./guides/migration/gitlab-project.md
|   |-- ./guides/monitoring
|   |-- ./guides/scala
|   |   `-- ./guides/scala/upgrades.md
|   `-- ./guides/terraform
|       `-- ./guides/terraform/module-development.md
`-- ./infrastructure
    |-- ./infrastructure/artifactory.md
    |-- ./infrastructure/grafana.md
    |-- ./infrastructure/instana.md
    |-- ./infrastructure/kafdrop.md
    |-- ./infrastructure/kafka.md
    |-- ./infrastructure/kubernetes.md
    |-- ./infrastructure/prometheus.md
    `-- ./infrastructure/sumologic.md

Example output from ./markdown-toc-tree.sh .:

- [conventions](./conventions)
  - [api](./conventions/api)
    - [rest](./conventions/api/rest.md)
  - [application](./conventions/application)
    - [usage-context](./conventions/application/usage-context.md)
  - [auth](./conventions/auth)
    - [auth0](./conventions/auth/auth0.md)
  - [git](./conventions/git)
    - [workflow](./conventions/git/workflow.md)
  - [infrastructure](./conventions/infrastructure)
    - [terraform](./conventions/infrastructure/terraform.md)
  - [jvm](./conventions/jvm)
    - [packages](./conventions/jvm/packages.md)
  - [logback](./conventions/logback)
  - [messaging](./conventions/messaging)
    - [kafka](./conventions/messaging/kafka.md)
- [guides](./guides)
  - [auth](./guides/auth)
    - [auth0](./guides/auth/auth0.md)
  - [github](./guides/github)
    - [workflows](./guides/github/workflows)
      - [aws-codebuild-codepipeline](./guides/github/workflows/aws-codebuild-codepipeline.md)
  - [lagom](./guides/lagom)
    - [developer-experience](./guides/lagom/developer-experience.md)
  - [migration](./guides/migration)
    - [gitlab-project](./guides/migration/gitlab-project.md)
  - [monitoring](./guides/monitoring)
  - [scala](./guides/scala)
    - [upgrades](./guides/scala/upgrades.md)
  - [terraform](./guides/terraform)
    - [module-development](./guides/terraform/module-development.md)
- [infrastructure](./infrastructure)
  - [artifactory](./infrastructure/artifactory.md)
  - [grafana](./infrastructure/grafana.md)
  - [instana](./infrastructure/instana.md)
  - [kafdrop](./infrastructure/kafdrop.md)
  - [kafka](./infrastructure/kafka.md)
  - [kubernetes](./infrastructure/kubernetes.md)
  - [prometheus](./infrastructure/prometheus.md)
  - [sumologic](./infrastructure/sumologic.md)

The command script above is portable enough to work across macOS and linux (tested with Ubuntu).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment