Show HN: Bish – Shell scripting with a modern feel
github.com
github.com
Recently I discovered a post [1] which touches on this:
> The whole point of short code is saving human bandwidth, which is the single thing in a computing environment that doesn't obey Moore's law and doesn't double once in 18 months. Now, which kind of bandwidth is the most valuable? I'll tell you which. It's the interactive command bandwidth.
It makes the argument that syntax is actually really important in building an interactive language - '[]' is better than '()', ' ' is better than ','. And it's true, bash (and, as it happens, tcl) ruthlessly pursue this - strings don't require quotes, function calls just require spaces (rather than brackets and commas) and there's generally very little punctuation for the most common operations.
I bring this up because it's interesting to see bish has gone in the other direction (curly braces, semicolons, brackets, quoted strings) in the name of a 'modern feel'. It makes me wonder if there's a way to bring the power of python (etc) into the shell in a syntax-friendly way.
[1] http://yosefk.com/blog/i-cant-believe-im-praising-tcl.html
That being said, the choice to include those syntax features in bish was made entirely to make writing a parser easier, not for any deep philosophical reason.
That's called optimizing bish developer bandwidth, rather than optimizing bish user bandwidth. Neither requires philosophy :)
Even though bash has some "modern" features, they're typically a bit weird and hard to remember: bash has arrays, for example, but the syntax is bizarre; you can write functions, but you can't declare the parameters, only access them as $1, $2, etc.; and so on. Occasionally I have to look up some expression syntax (like which bracket syntax to use for arithmetics, or whether "if" should have one or two brackets, and whether it's [[ a && b ]] or [[ a ]] && [[ b ]]) just because it's so damn different. It's painfully obvious that bash wasn't planned; so much of its evolution can be felt in the layers of hacks.
And with Ruby it's much easier to refactor to do things like logging (eg., when spawning a sub-command, only show its output if it fails), or provide cleanup (express your script with the command pattern, with commands that know how to commit and undo themselves), or use existing libraries.
Ruby's syntax — the ability to omit parantheses, the support for running shell commands with backticks — makes it particularly suited. For example:
if [ -e ./somefile ]; then
./somecommand ./somefile
(cd ./somedir && make)
installdir=`getsomeconfig`
cp build/mybinary $installdir/bin
fi
In Ruby: if File.exist? "somefile"
`./somecommand ./somefile`
Dir.chdir 'somedir' do
`make`
end
installdir = `getsomeconfig`
cp "build/mybinary", "#{installdir}/bin"
end
The last line requires that you initially do: require 'fileutils'; include FileUtils
Now you have a bunch of utilities (cd, cp, mv, mkdir, mkdir_p, etc.) as global Ruby methods.I like bash scripting, but the moment to use another language for a script for me is "will this require an array?"
Editor: http://batsh.org/
Source: https://github.com/BYVoid/Batsh/
from sh import date, ls, egrep, git
print date(), ls('~/project')
print egrep(ls('~/project'), '-o', '\.py$')
print git.add(egrep(ls('~/project'), '-o', '\.py$'))
[1] http://amoffat.github.io/sh/I don't think this improves on Perl. Being compiled to Bash might be interesting, if your deployment systems don't have Perl. It used to be unthinkable that any UNIX/Linux system wouldn't have Perl...but, several distros no longer install Perl by default (which is annoying as hell, to me, as Python isn't at all an acceptable substitute for one-liners and shell+ tasks). But, in that case, it would need to compile down to POSIX shell, because Ubuntu doesn't install bash by default, it uses ash (a small POSIX shell). So, bash has the exact same flaw as Perl for that use case.
Anyway, I don't generally think this adds things that I wish for when working with shell scripting, and having to compile it (even a quick compilation like this is likely to be) takes away one of the biggest benefits of scripting languages.
This seems like a really bad idea, since it apparently throws out good things like pipes, input/output redirection, wildcard expansion, and interactivity, but doesn't offer anything over the standard scripting languages.
Do you have a citation for this? I just checked my boxes and servers and they all have bash and are using it directly as the default shell. I never had to install bash myself on these machines.
Actually I just checked by /bin/sh and it's pointed to /bin/bash on my laptop (14.10) but on my desktop it is /bin/dash (also 14.10). Now I have some investigating to do. I suspect I did something that changed that but I don't remember doing it.
It's included in the standard Ubuntu repositories (http://packages.ubuntu.com/trusty/shells/rc) and it looks like it's in homebrew as well. I'd recommend giving it a try. The original Plan 9 paper describing rc is a good place to start and a good read, although you should be aware that Rakitzis' version made some minor changes to the syntax (a more usual if...else instead of Duff's 'if not') and dropped some Plan 9 specific pieces.
It feels like bish is trying to make using bash as a programming language tolerable.
Back in the Day, it was BSD Unix, which used tcsh as the interactive shell and Bourne shell as the scripting shell, as tcsh had tab completion but has a scripting syntax which is harmful to sysadmins and other living things, and Bourne shell had a sane scripting language but no interactive functionality beyond cooked mode.
We developed Korn shell, Bourne-Again shell (bash), and, eventually, zsh to move beyond that idiotic experience. These days, our non-interactive scripting languages are Python, Perl, Ruby, and Ruby with a different mix of libraries, all of which have better FFI other support libraries than any shell does.
My point is, unless bish has Python-class libraries, I don't see the point of taking on the annoyance of having a scripting shell different from my interactive shell.
There is however the portability factor. I've used fish as my only interactive shell for at least 5 years yet I rarely write a script complex enough to justify requiring users to have fish installed. Even when I write only for myself this sits at the back of my head and biases me to #!/bin/bash... From this perspective, "bish compiles to bash" made me immediately take note as a wise move.
Bash hurts my ego.
for (f in files) {
print(f);
}
}# cwd, ls, and cd are all builtin functions.
dir = cwd();
files = ls();
print("Files in current directory $dir:");
printall(files);
cd("/");
files = ls();
print("Files in root directory:");
printall(files);
Whats wrong with this, much shorter Bash sequence:
echo Files in current directory `pwd`:
ls
cd /
echo Files in root directory:
ls
[1] https://github.com/yramagicman/dotfiles/blob/master/bin/upda...
I keep intending to learn Perl really well, which I think could absorb much of Bash, and also Awk and Sed, and then there would be only one thing I needed to know for this kind of work, and I might use it enough to remember the various weird syntactic bits from one month to the next. But I never quite get over the hump.
Double-parentheses (( )) are only for arithmetic, e.g. "((count++))" or "echo $((1+1))"
The dollar sign precedes parentheses--i.e. $()--when you're substituting the output of a command, e.g. "echo Today is $(date)". It's easy to remember, because it's just like using the dollar sign for substituting the value of a variable, i.e. "date=$(date); echo $date".
You might want to look into the fish shell. Its scripting is much less idiosyncratic. You don't have to quote any variables, arrays, or command substitutions. e.g.:
set foods apple banana 'cucumber casserole'
for f in $foods
echo $f
end
prints: apple
banana
cucumber casserole
...not: apple
banana
cucumber
casserole
...as would be the case if you forgot to quote "$foods" and "$f" in Bash.[1] https://github.com/yramagicman/dotfiles [2] https://github.com/yramagicman/zsh-aliases [3] https://github.com/mathiasbynens/dotfiles/blob/master/.funct...
history | percol --prompt-bottom --result-bottom-up
I'm using fish, so the whole thing looks like this: function _percol_key_bindings
function __percol_ctrl_r
set tempfile (mktemp)
history | percol --prompt-bottom --result-bottom-up >$tempfile
and commandline (cat $tempfile)
commandline -f repaint
rm -f $tempfile
end
# Bind Ctrl+R to percol history function for now
bind \cr '__percol_ctrl_r'
end
[1]https://github.com/mooz/percol/If you want to replace bash (in an environment where Perl, Python, and Ruby all exist in a space for more advanced scripting) you have to do a hell of a lot to improve on the existing standards.
Then again, a fun weekend project playing with compilers is a valid use of one's time, even if the product doesn't change the world forever :)
$ docker run -ti imiell/sd_bish /bin/bash
bash-4.3# bish
USAGE: bish <INPUT>
Compiles Bish file <INPUT> to bash.
Magic here:https://github.com/ianmiell/shutit-distro/blob/master/bish/b...
Note I needed to hack the code a little.