November 12, 2013
Blogging with your shell
Greetings. My pseudonym is Ypnose.
Some people already know me (at least I hope so), I try to be
often involved in FOSS projects.
I also write articles on my french blog, since 2011 (it
was discontinued for many reasons). This is my 2nd weblog. I'll
talk about shell or related hacks. I plan to share some of my
tools & configs as well.
Actually, I'm in love with *ksh shells (and not necessarily
because I started serious programming on
Compared to the others shells I tried, they do everything faster and
more easily. Many persons use a shell everyday, only in interactive
mode. They want a fancy prompt with colors, dozens of Unicode
PWD, date(1) or clock. Personally, I chose
my shell according to its "power". For my sake, script usage is
much more important. Before *ksh, I played a lot with
I decided to create my own static website
script, because I was unable to find something which fits my
special needs. We already have similar softwares,
Hakyll. Unfortunately, I
wanted a tool in pure shell (here mksh(1)) + others UNIX utilities,
like find(1) or awk(1).
I have no limits (except my own limits), I can do everything I want
with my lines. That's why wswsh
([w]eb [s]ucks [w]ithout
[sh]ell) is born. It's designed as I wish.
SHELL is underestimated, because it
seems to be archaic, simplistic, dirty or designed for only easy
tasks. I think this is stupid, it's a powerful tool. I do
difficult/advanced tasks with it and I'm happy so far.
I'll try to explain you how wswsh works (reading my comments is useful too).
We are in a directory (which will be your brand new website) named "ITOOGUD", with the following files. It composes the minimal dependencies.
. ├── includes/ │ └── layout ├── wswsh └── wswsh.conf.default
includes contains website parts (layouts, header or
wswsh is the main part of the script and
wswsh.conf.default is the example config file. You have
to rename it to
wswsh.conf It contains the website
options. Read the comments inside for more information.
Now, the show begins...
Make a directory called
src. In this example, we
have a basic structure, with 5 folders and 4 files. As you can see,
some files have an unknown extension
.wshtml. This is
a generic extension (I can distinguish my posts without having a
headache), it symbolizes articles written in HTML fragments
.wtfhtml is OK too). Moreover, try to
.html for your articles (you
will understand why after).
. ├── includes/ │ └── layout ├── src/ │ ├── css/ │ │ └── style.css │ ├── blog/ │ │ └── index.wshtml │ ├── me/ │ │ └── john_doe.wshtml │ └── foo/ │ └── baz/ │ └── trololol.wshtml ├── wswsh └── wswsh.conf
./wswsh "$PWD". First of all, the script
will reproduce exactly the directory structure,
in a new folder
recursively analyzes the sources located to
dest/ ├── css/ ├── blog/ ├── me/ └── foo/ └── baz/
Then, find(1) "scans" those sources and "records" files with
the chosen extension (here
.wshtml). For example,
WSH_INTERP is defined to
the interpreter "reads" the file and its standard output is
redirected to a file
$ ahrf my_article > my_new_article.
This interpreter must be placed in your
Otherwise, the script concatenate the file(s) (+
page_footer functions) to a new one, in
dest. It does something like
$ cat file1 file2 file3 > new_file. Trivial isn't
dest/ ├── css/ │ └── style.css ├── blog/ │ └── index.html ├── me/ │ └── john_doe.html └── foo/ └── baz/ └── trololol.html
Huhh?... How can you copy this
It's not handled by find(1), right?
Yes, that's true, boy. There is a variable
wswsh.conf to copy the stylesheet into
dest/. This variable can be used to apply tags in
layout as well.
. ├── dest/ │ └── css/ │ └── style.css ├── src/ │ └── css/ │ └── style.css ├── wswsh └── wswsh.conf
Sometimes, our pages are not dynamically generated, so we do not
need to deal with these files. It's true for static start pages or
menus. In that case, we just desire to copy them, to the
destination. The program has a section (cf
which does the trick, if it finds
*.html. As it was
mentioned above, you shouldn't use
.html for all posts
. ├── src/ │ ├── start/ │ │ └── index.html │ └── menu/ │ └── 2013/ │ └── index.html ├── wswsh └── wswsh.conf
Despite all the care, some files are trying to escape us. It
was possible to export those
files, stored in a variable called
FIL but I decided to
remove that possibility. Copying external file(s) shouldn't be done
by the main script. You could do it using a trivial script or via
. ├── src/ │ ├── blog/ │ ├── flux.xml │ └── robots.txt ├── wswsh └── wswsh.conf
Testing the website was a bit problematic. I wanted to test the web pages, with a minimal server and I was too lazy to install Nginx / lighttpd (and using them is totally overkill). What a dilemma! I finally decided to grab and compile a tiny C web server called darkhttpd (NOO, it's not PURE shell). Indeed, but it doesn't "violate" my specifications. wswsh is a standalone script and this server isn't part of the script. Since I'm a very detail-oriented person, I like to verify the final result but you don't have to do it.
I won't describe all the possibilities in this article (configs
parsing, various interpreters, hooks), because it would be very
boring. If you read closely my code, I guess it won't be very
difficult to understand what it does. I'll add some
functionalities later (perhaps).
Atom feeds are also
supported (was removed). However, it won't be
"ported" on sh.
The script uses "Modified BSD License".
I hope you were interested by this first article. See ya soon!