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!
___.sh : 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'
It is entirely UNIX based. The current version uses peg-multimarkdown from Fletcher Peney.
It is a nameless, horrible and recursive assemblage of
mkdir etc..., has no option, no
uses almost no variable.
- multimarkdown in the script's
- GNU or Darwin/BSD
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
_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
yyyy-mm-dd.hhmm.this-is-the-title.md. You can create a blog file
empty but for the title using '
___.sh new "This is the title"'. During the
gen phase, appropriately named markdown files
will be transformed into individual post at
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/this.md will be used, but not
notes/bla/bla/that.md). 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
file. For each category, the blurb file will be assembled and shown
on the top-level projects index page (
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
home.md 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:
initis used the first time you check out this project. It will create the
contentdirectory and the necessary sub-folders. It will move the template files and the stylesheet into the
contentdirectory. 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.
cleanwill remove the generated files and folders.
genwill generate all the static pages.
___.sh 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.htmlin 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
___.sh new "A new beginning!" to create a file (named,
2014-07-07.0707.A-new-beginning.md) 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
Generation phase: When
___.sh 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
page. All the posts will also be used to generate a full text
How each pages are assembled:
_header + [post's title] + _nav* + [post] + _blog-footer + _footer
_header + [first line of latest post] + "Blog" + _nav* + [latest post] + _blog-sep + [previous 5 posts] + _blog-footer + _footer
_header + "Archive" + _nav* + [titles and links to all the posts] + _footer
_feed-top + [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
page. For individual notes, the URL will be the filename with '.md'
replaced by '.html'
How each pages are assembled:
_header + "Notes" + _nav* + [list of sub-folders and their notes titles (as links)] + [each note in the folder] + _footer
notes/a-single-note.md -> notes/a-single-note.html:
_header + [note's title] + "Notes" + _nav* + [content] + _footer
_header + [folder name] + "Notes" + _nav* + [all the folder's notes] + _footer
notes/folder/another-note.md -> notes/folder/another-note.html:
_header + [note's title] + folder + "Notes" + _nav* + [another-note.md] + _footer
The projects part was born of the way I arranged mine on my website:
language/projects. Each project folder contains a
project.md. 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
For example, given the following list of projects and languages:
The Projects page would look like that (projects/index.html):
The DisplayableCreator folder would contain a generated index page (projects/java/DisplayableCreator/index.html):
_header + [project's title] + "Projects" + _nav* + [project.md] + _footer
**: the folder's name
.md files will simply be transformed into a
_header + [page's title] + _nav* + [content] + _footer
Except for a "home.md" page if present, which would be incorporated into
_header + [home title] + _nav* + [home.md] + [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
colophon.md page and a
"colophon nohl" class in the
_nav file, the class will become
"colophon highlighted" in
Migration from 1.0
___.sh was generating a blog from a
blog folder. In 2.0
___.sh 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:
- update this project
- copy you blog posts into content/blog
- 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