A simple shell with simple goals https://git.rawtext.club/sloum/slosh
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
sloum c33810a637 Fixes tilde expansion 5 months ago
.gitignore Rewrites prompt generation to avoid multiple string traversals and adds file globbing as a part of parsing 5 months ago
LICENSE Adds readme and license 5 months ago
Makefile Adds manpage and updates Makefile 5 months ago
README.md Adds manpage and updates Makefile 5 months ago
TODO.md Adds /etc/slosh to bootup for login shells and fixes history memory between sessions 5 months ago
builtins.go Adds /etc/slosh to bootup for login shells and fixes history memory between sessions 5 months ago
commandRunner.go Adds a .sloshrc file that is separate from the login file .slosh. Updates man page. 5 months ago
go.mod Initial commit of mostly working shell 5 months ago
go.sum Initial commit of mostly working shell 5 months ago
main.go Adds /etc/slosh to bootup for login shells and fixes history memory between sessions 5 months ago
rc.go Allows for single line comments beginning at start of line in .slosh 5 months ago
slosh.1 Adds a .sloshrc file that is separate from the login file .slosh. Updates man page. 5 months ago
utils.go Fixes tilde expansion 5 months ago



slosh is a new interactive shell designed for use at ssh [user]@colorfield.space to replace the very limited shell that has been in use there for some time.

Lets get the elephant in the room out of the way: there is no reason most people reading this should want to use this shell. It does not do anything new or inovative (though does combine a few previous shell styles), it is more limited than most shells - by design (you can always run sh or bash scripts from slosh, so there is no need to write a whole programming language into a simple shell), and it lacks many common features.

So why write a new shell at all? Because I like writing and owning my tools. Because it was a good learning experience (it turns out that many things shells implement are more complicated than they seem like they would be). Because I was bored in the evening for a few days and it was something to do. Because my ssh server community was in need of an upgrade from an even more limited shell.

Quick Start

So you've decided to forge ahead (or are on one of my systems and trying to make the best of it). Cool. This section will go over the feature set I have decided on for slosh (or, SLOum's SHell).

For starters, slosh features command completion for anything on the $PATH. Completion is also available for file paths, with a small caveat that will be talked about next. slosh also offers command history via the up/down arrows. In general, emacs bindings are supported for moving around the command input (see the underlying library liner for more info on those key bindings).


You can group text into a string at the shell by surrounding the text with quotes. This treats it as a single value being passed to the given application. Variables get expanded in double quoted strings and do not in single quoted strings.

# echo "I am $SHELL"
I am /usr/local/bin/slosh
# echo 'I am $SHELL'


All filepaths must start with /, ./, ../, or ~. So if you are trying to complete a file in the current directory named myfile.txt you cannot type myf<tab>. You must type ./myf<tab>, or the like. The same goes for running an executable in the current directory named 'myexecutable'. If you just run myexecutable you will be met with a message saying that it was not found on your $PATH. However, typing ./myexecutable works as expected.

This path specificity enables slosh to know that it is working with a filepath, which in turn enables us to ditch the cd/dir command. Instead of using cd you can just type the path and hit enter and you will move there.

# pwd
# ~/Documents
# pwd

Internally, cd and dir are both aliased to this behavior. So you may, at your option, include cd or dir if you like.

Also of note, tab completion always expands the filepath. This takes up more screen real estate but increases clarity (a design goal).

File globbing works as you would expect (using * or **), but file paths that include globs will not be autocompleted.

Additionally there is a builtin called up that takes a number as an argument. It will move you up the number of directories given:

# pwd
# up 3
# pwd


Piping works as you have come to expect:

# ls -la | grep *.go | lolcat


slosh only supports very basic output redirection. There is no separation of stdout and stderr. If you redirect, you will get both. Redirection works with the same syntax you are likely used to (with the former creating/overwriting a file and the later appending to a file):

# ls -la | grep *.go | lolcat > ~/some-file.txt
# echo "set PATH $PATH:/home/myuser/bin" >> ~/.slosh

Command Continuation

You can run multiple commands from the same line of input via the && command. If any command in the line fails, the following ones will not run. The && opperator is particularly useful for allow the let command (see below) to function and provide commands with local environment variables.

# echo "Starting thing1..." && some-program
Starting thing1...
# let GOOS linux && let GOARCH arm && go build -ldflags "-w -s" -o slosh

There is not another way to chain commands (other than pipes) in slosh. If you want two+ commands to run one after the other but do not want their execution to rely on the previous command having exited successfully: put them on separate lines.


slosh has two types of variables: global and local.


A global variable is much like a regular bash or sh style variable, but uses csh syntax (mostly) in its definition:

# set myvar1 "I am a variable in the $SHELL shell"
# echo $myvar1
I am a variable in the /usr/local/bin/slosh shell
# set myvar2 I am a $SHELL variable
# echo $myvar2
I am a /usr/local/bin/slosh variable
# set myvar2 'I am a $SHELL'
# echo $myvar3
I am a $SHELL

The set builtin takes the variable name as its first argument and any subsequent arguments are concatenated into a double quoted string (they will have variable references expanded). You can, of course, use single quotes to not trigger variable expansion.

You can remove the reference to a global variable with the unset command:

# set myvar 'Hello, world'
# echo $myvar
Hello, world
# unset myvar
# echo $myvar


Local variables have the same syntax as global variables, except they use let instead of set. Where you use them is different though. Instead of affecting the shell environment a let variable is passed into the execution environment of subsequent applications called as a part of the same shell execution. For example:

# let GOOS linux && let GOARCH arm && go build -o ./slosh

In the above example GOOS is set to linux and passed to the next command's execution environment (without adding it to the global environment that the shell itself draws from). GOARCH is then set to arm and both are passed into the go build command, which will use those variables. This behavior also works with pipes (|).

Be aware that when you create the local variable it gets passed forward, but never backward. So if you add a local variable in the middle of a series of commands it will not be available to commands that came before it. The local scope gets cleared when the whole command entry line is finished.

Local variables are not available to the shell itself, only to commands run by the shell:

# let myvar 12345 && echo $myvar

...nothing gets echoed in the above because $myvar does not exist in the scope of the shell, only in the scope of the echo program (and the code for echo does not call a variable named myvar).


You can set an alias the same way you set a variable (but with the alias builtin):

alias ll ls -lah

The first argument if the name of the new alias and the arguments that follow are the value of the alias. An alias will not look up another alias. So if you set ls to ls -la and ll to ls --color=auto the -la does not get added to the ll alias.

You can remove an alias with unalias:

unalias ll

Slosh File

slosh will look for a file named .slosh in your home directory. If it is present, it will be read when slosh is launched. This is a good place to set aliases and global variables. There is nothing special about the slosh file in terms of execution. The shell reads each line and treats them as if they were typed in at the shell at runtime. This is different than things like a .bashrc or various script files for shells where they are run as a script and have their own environment. If you are just using it for variables and aliases you should have no trouble with that difference. You could also use the file to launch programs at runtime.

Comments can be added to a .slosh file. Comments are always the whole line and always start with #. There are no multiline comments or comments than come after content on a line.

alias c clear

# Prompt options
#    %c  -  Current dir
#    %d  -  Short dir listing
#    %D  -  Full dir listing
#    %h  -  Host name
#    %u  -  Current user
set SLOSH_PROMPT "%u@%h - %c # "

If you make changes to your slosh file while running slosh and want to reload the file into the current runtime, you can do so with lsf (load slosh file). This will clear all aliases before loading any new ones, so be aware of that. At present lsf cannot be used to load arbitrary files with slosh oriented commands in them, though that is being looked into for a future release.

Custom Prompt

slosh supports prompt customization via the global variable SLOSH_PROMPT. As such, you could put something like the following in your ~/.slosh file:

set SLOSH_PROMPT "%u@%h [%c] -> "

Escape codes have no effect within this variable and may have unexpected results. This is due to a limitation in the underlying line editing library being used by slosh. You may have noticed in the above example that there are a few weird %-based instructions. The following are currently avaialable:

  • %c - current base directory (example: bin)
  • %d - a short path, consisting of the last three path segments (example: ...Music/Slowdive/Souvlaki)
  • %D - the full path (example: /home/myuser/Music/Slowdive/Souvlaki)
  • %h - the current host (example: my-linux-system)
  • %u - the current user's username (example: myusername)


slosh is not a programming language the way bash and many other shell/command languages are. There are no if statements, no loops, etc. The general ethos behind slosh has been: if you want to program you can either write a bash script and execute it with bash or you can use a programming language (Lua, Python, C, or anything else you like). slosh is meant to be a very minimal shell that provides a basic feature set to allow you to navigate a system successfully, but not much more.

As mentioned above, redirection of stderr, stdout, and stdin is not possible in a granular way.

slosh does not support job control (ctrl-z on most systems then jobs and fg) and likely will not in the future. A simple multiplexer like dvtm makes this less necessary.

At present it is not possible to run a job in the background via the & command. However, this is planned for a future version.


git clone https://git.rawtext.club/sloum/slosh && cd slosh
go build -ldflags "-w -s" -o slosh

Alternatively you can use the Makefile...

git clone https://git.rawtext.club/sloum/slosh && cd slosh

I recommend running upx -9 ./slosh if you have upx and want a smaller binary. But it will work fine either way, so not a big worry.

If you'd prefer to just run it once for fun:

git clone https://git.rawtext.club/sloum/slosh && cd slosh && go run *.go


slosh is released under the floodgap free software license, a copy of which is included in the repo.