
I got tired of PHP and Perl, so I tried bash - nerdgeneration
https://github.com/nerdgeneration/www.sh
======
xelxebar
Shell scripting gets a lot of hate, but after spending time to grok the
language (and copious use of shellcheck), I've grown quite fond of it. This
also has the nice side effect of emphasizing use of old unix tools.

I think the "big realization" for me was shifting to think in pipelines
instead of passing state around in variables. That completely removed the pain
of no arrays in POSIX shell for me. Stdin/stdout are your friend.

Certainly, shell scripting isn't the answer for everything, but with
shellcheck (and bats!), I feel like it's a really reasonable default for
systemy things. Heck, the status bar I use in my window manager is essentially
just a 700 line bash script, with asyncronous update and everything. It's even
quite readable and orthogonally organized, if I might boast. Have been
pleasantly surprised over the years every time I go back and read it.

~~~
arendtio
I think one of the biggest problems is the inconsistent runtime environment. I
mean, yes, you can just say fuck POSIX and code for Bash only, but then again,
not even Bash is consistent across its versions. Just to give an example: The
infamous `set -e` behaves quite differently across different shells

[https://www.in-ulm.de/~mascheck/various/set-e/](https://www.in-
ulm.de/~mascheck/various/set-e/)

And those are just POSIX compliant shells. I mean this doesn't matter if you
just want to write a script for yourself but becomes frustrating when you want
to level up you shell skills and write cross-platform scripts ;-)

That said, I have to add that I love shell scripting... I am not exactly sure
why, but I guess it is because it lets you build powerful things with very few
lines of code.

~~~
dahfizz
When isn't this true, though? JavaScript behaves differently based on your
browser and version. C runs differently based on your compiler version and
system libs. This is just the nature of software.

~~~
h1d
You do realize standardization exists to avoid just that?

~~~
neatcoder
What's your point? Shell is also standardized by POSIX.

------
nerdgeneration
So anyway, I've been writing websites for 20 years, and this seemed fun. Some
friend suggested I post it here, so I'm doing that just to shut him up.

~~~
jaequery
What will you do once you get tired of bash?

~~~
mirkules
Port it to Javascript, naturally.

bash.js has a nice ring to it

~~~
DyslexicAtheist
WebAssembly would be pretty cool too. I hear there is now something called
_WebAssembly "usermode"_ which can run directly in ring-0.

WebAssembly + Ring-0 = Security /s

[https://github.com/cervus-v/cervus](https://github.com/cervus-v/cervus)

------
louwrentius
Many years ago I learned myself Bash by writing this:
[https://github.com/louwrentius/PPSS](https://github.com/louwrentius/PPSS)

It's a huge bash script for parallel processing of work. It was great fun and
I'm proud of it as I don't see myself as a programmer of any sort.

But gosh since I learned Powershell and Python, I would never ever ever ever
ever use Bash for anything substantial.

If you ever feel like you grow 'fond' of Bash or Shell scripting, it's time to
seek a doctor. Please learn Python or some equivalent instead.

\-----------------

Edit: reading the code of this web server project:

Let's be absolutely clear: this is a joke project. DO NOT USE THIS FOR #
ANYTHING, ESPECIALLY ON A PUBLIC FACING SERVER.

~~~
rocqua
Ive found it harder than expected to simply port over a bash script to python.
Mostly because the syntax for 'run command c with arguments x y is much worse
than bash. And that is before you want to handle output from the command.

~~~
semi-extrinsic
It would be super nice if there was a package offering "native" shell
experience in python. Say

    
    
      from pyshell import sh, ShellError  
      
      def func(a,b)  
          output, retcode = sh("df -k | awk '{print $5}'")  
          if retcode == 0:  
              return output  
          else:  
              raise ShellError(output,retcode)

~~~
lars512
The sh module is really excellent, and it lets you take the best parts of bash
(the external commands, pipes) and ditch the bad parts (string handling,
general programming). I think it’s what you’re looking for.

[https://amoffat.github.io/sh/](https://amoffat.github.io/sh/)

~~~
tarruda
I wrote [https://github.com/tarruda/python-
ush](https://github.com/tarruda/python-ush) for my own scripts. It was
inspired by "sh", but my version supports native "lazy" pipelines (using
python operator overloading) and other nice features not provided by sh. Also
it works seamless between Unix/windows

I was also planning to extend it to support python3 asyncio, but never got
around it

------
AceJohnny2
I hated Perl until I had to do Bash scripting.

I must apologize to Perl. I see now where it was coming from [1], and what it
saved us from.

May god have pity on your soul for inflicting us with this.

[1] There are lots of quirks in Perl that I now recognize come from shell
scripting. Most obviously, $VAR notation and string quoting.

------
dec0dedab0de
Really you should be starting with bash, thats how you know why these other
languages exist. My rule of thumb used to be if I have more than one "if" in a
shell script then its going to python... But now its any ifs or variables

Edit: now that I read the readme I think the title should have been "show hn:
I made a web framework in bash" this is pretty neat, I still wouldnt use it,
but its cool as hell.

~~~
earenndil
> My rule of thumb used to be if I have more than one "if" in a shell script
> then its going to python... But now its any ifs or variables

Hmm. I have a slightly different view. If logic is _complex_ , then it should
be moved to a different language. But if there are a lot of flat if statements
then shell is fine.

~~~
dmitryminkovsky
Yeah it’s almost inevitable for a bash script to have lots of ifs but they’re
almost always simple, checking some variable is empty or something.

------
waterhouse
Suggestion: You use "set -e". The problem with this is that it's silent about
which line the script died at, so if your script doesn't print a lot, you may
have to do detective work. This is an automatic way of giving you a bit of a
hint:

    
    
      $ cat meh.bash
      #!/bin/bash
      set -e
      die() {
        echo "Failed at line $1: $2"
      }
      trap 'die $LINENO "$BASH_COMMAND"' ERR
      echo a
      test 1 = 3
      echo b
      
      $ ./meh.bash
      a
      Failed at line 8: test 1 = 3
    

Adapted from:
[https://unix.stackexchange.com/a/462157](https://unix.stackexchange.com/a/462157)

~~~
arendtio
If your script dies because of `set -e` the detective work is just the
punishment to condition yourself to write more stable code in the future ;-)

By the way, if you are just using Bash (instead of POSIX /bin/sh) you can do
even better. Some time ago I found a stacktrace function somewhere:

    
    
      set -Eeuo pipefail
      trap stacktrace EXIT
      function stacktrace {
          if [ $? != 0 ]; then
              echo -e "\nThe command '$BASH_COMMAND' triggerd a stacktrace:"
              for i in $(seq 1 $((${#FUNCNAME[@]} - 2))); do j=$(($i+1)); echo -e "\t${BASH_SOURCE[$i]}: ${FUNCNAME[$i]}() called in ${BASH_SOURCE[$j]}:${BASH_LINENO[$i]}"; done
          fi
      }

------
Twirrim
See also:
[https://github.com/avleen/bashttpd](https://github.com/avleen/bashttpd)

~~~
foobarian
Another way to skin the cat:
[https://github.com/cemeyer/httpd.sh](https://github.com/cemeyer/httpd.sh)

Based on ctypes:
[https://github.com/taviso/ctypes.sh/](https://github.com/taviso/ctypes.sh/)

~~~
rgoulter
On the topic of "why would you write that with that", this is worth a mention:
[https://github.com/azac/cobol-on-wheelchair](https://github.com/azac/cobol-
on-wheelchair)

------
Matumio
I think "One does not write a web server in Bash" is like "One does not simply
walk into Mordor." You're practically daring short people with hairy feet to
attempt it.

(Quote: seebs on slashdot)

------
brainpool
I wrote a CMS in Standard ML. My only excuse was that I did not know better.
The only other language I knew was Prolog. Should have done it in bash
instead, would have been easier.

------
tasubotadas
I got tired of crack and meth, so I tried heroin.

------
vortico
Everything being a string _does_ solve potential type issues...

~~~
TazeTSchnitzel
It also creates in-band signalling security hell, even worse than the web
already inherently has.

------
Lowkeyloki
Has this been run through ShellCheck? Once scripts are run through ShellCheck,
I'd almost consider them safe.

No disrespect to ShellCheck, though. It's a fantastic tool.

~~~
proboscis
Shellcheck is indeed great. I needed to make a BASH script to give to my
girlfriend that would install on her OS X a snake game I made. Using
shellcheck made that a lot easier. For example, I didn't know that the [[ ]]
syntax wasn't POSIX compliant. Really great for learning and remembering
little things like that for portability.

------
LeoPanthera
I can't tell you which one, but I know that a very popular website you will
have heard of with a surprisingly high Alexa ranking is almost entirely
powered by a bash script via CGI.

I'm constantly surprised it hasn't exploded yet.

~~~
deepakhj
Craigslist?

~~~
cutler
Perl and MySQL.

------
neokantian
Bash is the love of my life. However, it has serious weaknesses. Its
array/table concept is flawed. You cannot do tables containing tables.
Secondly, out of the box it cannot load or invoke functions in libraries.
Fortunately, ctypes.sh solves this problem, and to some extent, indirectly,
also the table of tables problem.

------
isostatic
Whenever I write websites in bash, I start off fine, but tend to regret it,
and end up refactoring into Perl.

~~~
nerdgeneration
Whenever I write anything in bash, I start off fine, but tend to dig my heels
in as it gets harder and refuse to switch languages.

------
ricardobeat
I write shell scriots all the time for a myriad of tasks, but will tore my arm
off before writing a server in it.

It is very well suited for imperative scripts, but the language breaks down
pretty quickly once complexity and the level of abstraction go up; you start
relying on obscure syntax, behaviour, and piling up more and more patterns
that require full week-long immersion to grasp. Perl is harmless in
comparison.

------
zimbatm
Bash is a misunderstood language. A lot of developers don't take time to learn
it enough and discard it because of that. So I started a twitter handle that
posts semi-regular tips and tricks about it:

[https://twitter.com/thewayofbash](https://twitter.com/thewayofbash)

------
whalesalad
The best thing about projects like this is how well they illustrate the MVP
web framework. A lot of people think things like Django or Rails are magical
massive beasts, and to some extent they are, but vast portions of it can get
boiled down to something like this.

tl;dr if you’re not sure how to roll your own very simple web request/response
framework, this is a great intro.

~~~
tyingq
Bocker is similar for better understanding Linux containers.

[https://github.com/p8952/bocker](https://github.com/p8952/bocker)

------
tlrobinson
I wrote something similar, including a CGI webserver written in shell:
[https://github.com/tlrobinson/martin.sh](https://github.com/tlrobinson/martin.sh)

~~~
wahern
If you used `<<-EOT` you could tab-indent the HTML so it reads better. The
tabs will be automatically removed and the source code will be much more
readable.[1] Of course, it would require tab-indenting all your shell code
(but not the HTML itself), which may be a hard pill to swallow if you're a
spacer. But the fact is that tab indenting was once upon a time the norm in
the land of Unix programming and the tools reflect this.

Windows converts and Python programmers are the ones who turned the tide. I
suspect that when most read older source code from the Unix universe they
don't realize it's almost entirely tab indented because 90% of the source code
will still look clean no matter the tab stop (which is of course the very
point of hard tabs =)

[1] I never understood why Perl's heredoc construct didn't also adopt this
behavior. I always cringe when people use heredoc (even in shell) without
indenting the entire body properly. I mean, that's kinda the point of the
heredoc--so the data becomes part of the code.

------
Pamar
This is of course just personal preference, and I have to admit that it might
be heavily influenced by the shift in responsibilities (i.e. my job involves
less and less scripting at the CLI level nowadays) but I was always partial to
DCL:
[https://en.wikipedia.org/wiki/DIGITAL_Command_Language](https://en.wikipedia.org/wiki/DIGITAL_Command_Language)

------
proboscis
If I'm doing any scripting, I always use BASH. However, I'm trying to actively
push myself to learn another more portable scripting language. I still haven't
been able to decide which out of Python, Perl and Ruby that I really want to
throw myself into -- although recently I have started to become more and more
attracted to Ruby.

~~~
tyldum
If you are thinking about Perl, then take a look at Mojolicious. An amazing
framework to work with that covers so many common use cases with async and
functional programming style. I find that the code becomes very precise and
readable.

------
hyperpallium
Knock bash if you will, but in my experience, it has the best and most helpful
community on SO of any language.

~~~
h1d
Probably because more grown ups know it well.

------
frumph
Ganesh is a fun option as a sinatra-inspired bash web framework for internal
services:

[https://github.com/tropicloud/ganesh](https://github.com/tropicloud/ganesh)

------
k__
also: there is a AWS Lambda Bash runtime.

[https://github.com/gkrizek/bash-lambda-
layer](https://github.com/gkrizek/bash-lambda-layer)

------
_Marak_
Does anyone know what the theoretical limitations of trying to use Bash as a
Web Server are?

How many requests per second could it serve? What about HTTP/2 support?

~~~
nightfly
It would share all the same limitations as any other forking server, plus
extra overhead for any spawned child processes. Basically the same as using
CGI scripts, and probably not much worse any Apached hosted PHP based website,
tbh. Probably wouldn't be worth implementing HTTP/2 since it would increase
the complexity with no real benefit.

------
redm
It’s a neat experiment, totally impractical, but neat. What this has to do
with PHP or Perl I have no idea.

~~~
nerdgeneration
It's just personal. I did Perl in 1997/98 and 2017 to now. I did PHP from 1998
to 2017.

------
LeoNatan25
Not the smartest idea putting "www.sh" in the title, which redirects to a
Chinese site.

~~~
jolmg
China is .cn, .sh is for a British Overseas Territory and the domain is not
registered.

~~~
xfitm3
It could be the ISP's nameserver snarfing NXDOMAINs.

------
StreamBright
Why not OCaml or Rust?

~~~
nerdgeneration
Maybe when I finish the assembler version...

------
revskill
I got tired of bash. Still waiting for `typed bash`.

------
jmontano
Cool Idea, and very easy to migrate between VMs.

------
hyperpallium
When you're tired of PHPing and Perling yourself in the head.

------
nihil75
lol living life in reverse :)

------
telaelit
You monster

~~~
nerdgeneration
Thank you! ;)

------
munificent
That title reads like "I got tired of punching myself in the face and kidney,
so I tried punching myself in the crotch".

I love it.

~~~
svnpenn
That's exactly how I read it. Php and Perl are really from a time gone by.
neither have REPL. php doesn't even have to a proper print command, you have
to add your own newline. Granted they are both quite fast, but with perls
"write only" syntax I would only use either of them for the most basic of
scripts.

~~~
carmate383
Except that PHP does have a REPL, and using PHP_EOL is hardly a big deal. PHP
induces an undeserved gag-reflex for most Ruby / Python / JS devs because they
read some "why php sucks" post on someone's blog ten years ago, but really the
language is quite modern now (not to mention faster).

~~~
jes5199
I honestly tried to come back to PHP after most of a decade in ruby. I
couldn’t find a decent ORM! And after trying to write one, I think I see why.

We ended up rewriting the entire product in Python.

~~~
cutler
Why not Ruby if you'd just spent a decade with it?

~~~
h1d
Sometimes preference doesn't match project choice?

------
honkycat
If you are writing more than 10 lines of bash, write python instead.

Awful language. Waste of time.

~~~
roryrjb
You're using it wrong. The things that bash is good for are not the same
things that Python should be used for. For what bash is good for, it is the
simplest and fastest language one could use.

~~~
okasaki
What is bash good for?

~~~
h1d
For a task like taking backups on servers that involves invoking bunch of
commands, I'd rather not use a scripting language that asks you to open a
process, bind variables on its stdin/stdout and all the boilerplate handling.

How do you do this in a scripting language without complication?

$ ssh remote.server 'mysqldump db | gzip -c' | gunzip -c | mysql db

It's the power of individual commands though I admit bash sucks as a language
but it got invented forever ago, so can't blame it. But we need something
better than bash. Fish is close but not too good.

------
alexanderscott
Look thru the code though... Thought this would do more than serve a static
html file. Not impressed

~~~
nerdgeneration
It doesn't. The route defines the controller. The controller displays the
content, ideally using the view function (there are examples with and without
a view, but always with a controller). The view function takes an associative
array for template replacements.

