Skip to content : a 42*2 lines, recursive, multimarkdown, sed & bash static html blog 'engine'

Notifications You must be signed in to change notification settings


Repository files navigation


By Nicolas Hoibian.

!!! This is the 2.0 version. Details for migrating from 1.x at the bottom.

Version 2.1: now works on Linux and OSX/Darwin/BSD! : The answer to your questions about static html sites in 42*2 lines of bash (and thousands of lines of C).

"His limbs were in proportion, and I had selected his features as beautiful. Beautiful!--Great God! His yellow skin scarcely covered the work of muscles and arteries beneath; his hair was of a lustrous black, and flowing; his teeth of a pearly whiteness; but these luxuriances only formed a more horrid contrast with his watery eyes, that seemed almost of the same colour as the dun white sockets in which they were set, his shrivelled complexion and straight black lips." - Mary Shelley, 'Frankenstein'

This software generates a static html site from markdown files. It is similar in aim to jekyll and hyde, but with a smaller scope and much less elegance.

It is entirely UNIX based. The current version uses peg-multimarkdown from Fletcher Peney.

It is a nameless, horrible and recursive assemblage of bash, sed, cat, echo, date, mkdir etc..., has no option, no for, and uses almost no variable.


  • multimarkdown in the script's $PATH.
  • mkdir, bash, sed, cat, find, echo, grep, cd,
  • GNU or Darwin/BSD date.

The only script. Every other files are It generates a website from a set of Markdown files. It transform the files into HTML pages in 4 (+1) different ways depending on which folder the files are in. In general, each transformed page will consist of concatenating the _header.html, _nav.html, content and _footer.html together into a single html page. The content is usually the result of a markdown to html conversion, surrounded with some specific transformations, which are slightly different for each folder.

In the blog folder, the files should be named You can create a blog file empty but for the title using ' new "This is the title"'. During the gen phase, appropriately named markdown files will be transformed into individual post at yyyy/mm/dd/this-is-the-title.html. An archive.html page will also be generated, containing a list of all the blog posts, most recent first. A full text RSS feed will also be generated containing all the posts. In the blog/ directory, an index.html will be generated, containing the last post as well as links to the 5 previous posts. The latest blog post and links to the 5 previous ones will also appear on the front page.

In the notes folder, the files can be organized in as many folders as you want, but sub-folders will not be taken into account (notes/bla/ will be used, but not notes/bla/bla/ The notes will be transformed into their html version. There will also be an index.html file which will contain the full text of the notes in the current folder. In the top-level notes folder, the list of notes in it's sub-folders will appear at the top of the page.

In the projects folder, the minimum folder depth should be two (projects/category/project1). In each project folder, the script looks for a project1/project1.blurb and a project1/ file. For each category, the blurb file will be assembled and shown on the top-level projects index page (projects/index.html), and the individual projects .md file will be transformed into an index.html page in the project folder.

In the pages folder, the .md files will be transformed into .html file. If there is a file, it will be used to when creating the site home page (it will appear above the latest blog post). Sub-folders are not supported.


There are four commands: init, new, clean and gen.

  • init is used the first time you check out this project. It will create the content directory and the necessary sub-folders. It will move the template files and the stylesheet into the content directory. Once this is done, you do not need to run it again. If you do, it will overwrite the templates and the stylesheet.

  • new "some title"" creates a new blog post file based on the date and the given title, empty but for the title.

  • clean will remove the generated files and folders.

  • gen will generate all the static pages.

Implementation details

Initial run

Please run init so the content folders (content + /blog /projects /notes /pages)are created and the template files are moved to where they will be used.

Conventions for assembly description:

  • _name: this is one of the template files you have to edit. It should be named _name.html in the content folder.
  • [...]: this is content extracted from a markdown file. It can be the first line of a file (it's title), the result if a markdown to html conversion or the result of some other internal operation.
  • "..." text that appears verbatim in


You can use new "A new beginning!" to create a file (named, for example in the blog folder that will contain the title. It will be named using the date, and most special characters will be removed from the file name (but not the title).

Generation phase: When gen is invoked, all the blog posts will be transformed into html pages, in a YYYY/MM/DD/The-title-of-the-post.html file (yes, the time is removed from the generated post file name). The latest post will also be used to create an index.html in the blog folder. The titles and links to each post will be part of the archive.html page, and the last five titles and links will be added to the end of the index.html page. All the posts will also be used to generate a full text blog/feed.xml.

How each pages are assembled:


+ [post's title] 
+ _nav*
+ [post] 
+ _blog-footer 
+ _footer


+ [first line of latest post] + "Blog" 
+ _nav*
+ [latest post] 
+ _blog-sep 
+ [previous 5 posts] 
+ _blog-footer 
+ _footer


+ "Archive" 
+ _nav*
+ [titles and links to all the posts] 
+ _footer


+ [every posts]


Just write your notes. Upon generation, each note will be transformed into its html version. Each folder will have an index page with the notes in full text and, for the root notes folder, the list of sub-folders and the their notes' titles will appear at the top of the notes/index.html page. For individual notes, the URL will be the filename with '.md' replaced by '.html'

How each pages are assembled:


+ "Notes" 
+ _nav* 
+ [list of sub-folders and their notes titles (as links)] 
+ [each note in the folder] 
+ _footer

notes/ -> notes/a-single-note.html:

+ [note's title] + "Notes" 
+ _nav*
+ [content] 
+ _footer


+ [folder name]  + "Notes" 
+ _nav* 
+ [all the folder's notes] 
+ _footer

notes/folder/ -> notes/folder/another-note.html:

+ [note's title] + folder + "Notes"
+ _nav*
+ [] 
+ _footer


The projects part was born of the way I arranged mine on my website: language/projects. Each project folder contains a project.blurb and a When the site is baked, the blurb are aggregated and arranged below the category name on the Projects page, and each project's markdown file is transformed into an index.html page.

For example, given the following list of projects and languages:


The Projects page would look like that (projects/index.html):

+ "Projects"
+ _nav*

+ java**
+ Displayable**
+ [Displayable.blurb]
+ DisplayableCreator**
+ [DisplayableCreator.blurb]

+ Javascript**
+ nTime**
+ [nTime.blurb]   

+ _footer

The DisplayableCreator folder would contain a generated index page (projects/java/DisplayableCreator/index.html):

+ [project's title] + "Projects" 
+ _nav*
+ [] 
+ _footer

**: the folder's name


The pages .md files will simply be transformed into a .html version:

+ [page's title] 
+ _nav* 
+ [content] 
+ _footer

Except for a "" page if present, which would be incorporated into the root index.html.

+ [home title] 
+ _nav*
+ [] 
+ [latest blog] 
+ _blog-sep 
+ [last 5 posts] 
+ _blog-footer 
+ _footer


Except for the homepage, everywhere the _nav file is used it is transformed so it is possible to highlight the current part of the site the page is in. The default _nav.html page contains links with a class that is composed of a name (blog|notes|project) and " nohl". When generating html pages, the composite class is matched and the "nohl" part is replaced with "highlighted". For notes, blog and projects only 'notes', 'blog' and 'projects' are looked for. In the pages directory, the file name is looked for. So if there is page and a "colophon nohl" class in the _nav file, the class will become "colophon highlighted" in thecolophon.html page.

Migration from 1.0

In 1.0, was generating a blog from a blog folder. In 2.0 generates a website, including a blog, from a content folder that contains a blog folder. Accordingly to switch to 2.0, you will have to:

  1. update this project
  2. run init
  3. copy you blog posts into content/blog
  4. edit the content/_* files to taste. Some names and purposes have changed from 1.0 . Don't forget to add a link to the blog xml feed somewhere.


I hereby release this 'software' under the Creative Commons BY-NA-SA. Have fun.

Copyright Nicolas Hoibian 2014

About : a 42*2 lines, recursive, multimarkdown, sed & bash static html blog 'engine'






No releases published


No packages published