.\" Man page for gosh. View with: man ./packaging/man/gosh.1 .\" @VERSION@ is replaced by the release version when building packages. .TH GOSH 1 "October 2026" "gosh @VERSION@" "User Commands" .SH NAME gosh \- a simple shell written in Go .SH SYNOPSIS .B gosh .RB [ \-l ] .RB [ \-i ] .RB [ \-\-norc ] .RB [ \-\-noprofile ] .RI [ script .RI [ args " ...]]" .br .B gosh .RB [ \-l ] .RB [ \-\-noprofile ] .B \-c .I command .RI [ name .RI [ args " ...]]" .br .B gosh .B \-version .SH DESCRIPTION .B gosh is a small command interpreter with a syntax close to .BR sh (1). It supports command history, tab completion, variables, positional parameters, command substitution, command lists, control structures, functions, pipes, redirections, wildcards, brace expansion, aliases and job control. .PP Without arguments and with a terminal on standard input, .B gosh starts an interactive shell. With a .I script argument it runs the commands of that file, with .B \-c the given command string, and otherwise it reads commands from standard input. The .I args after the script, or after the .I name of .BR \-c , become the positional parameters .BR $1 , .BR $2 ", ..." .PP .B gosh is a proof of concept and not meant for production use. .SH OPTIONS .TP .B \-c \fIcommand\fP [\fIname\fP [\fIargs\fP ...]] Run .I command and exit. .I name becomes .BR $0 , the .I args become .BR $1 , .BR $2 ", ..." .TP .B \-i Force interactive mode, even if standard input is not a terminal. .TP .BR \-l ", " \-\-login Act as a login shell and read the profile files (see .BR "STARTUP FILES" ). A shell whose .I argv[0] starts with .B \- (as started by .BR login (1), .BR sshd (8) or .BR "su \-" ) is a login shell as well. .TP .B \-\-norc Do not read the goshrc files. .TP .B \-\-noprofile Do not read the profile files. .TP .BR \-version ", " \-\-version ", " \-V Print the version, branch and commit and exit. .TP .BR \-h ", " \-\-help Print a usage summary and exit. .TP .B \- Read commands from standard input. .SH NON-INTERACTIVE USE Scripts, command strings and commands read from a pipe are executed line by line. Empty lines and lines starting with .B # are skipped, so a script may start with .BR "#!/usr/bin/gosh" . A failing command does not abort the script; the exit status of .B gosh is the one of the last command. .PP Because .B gosh supports .BR \-c , .BR ssh (1), .BR scp (1) and .BR rsync (1) work when it is used as login shell. .SH STARTUP FILES Startup files are executed in the running shell, so variables and aliases defined there stay in effect. .TP Login shells read .I /etc/gosh/profile and .IR ~/.gosh_profile . .TP Interactive shells read .I /etc/gosh/goshrc and .IR ~/.goshrc . .PP An interactive login shell reads the profile files first, then the goshrc files. Scripts and .B \-c read no startup files unless .B gosh is a login shell. Missing files are skipped; errors are reported with file name and line number and the remaining lines still run. Files of other shells such as .I /etc/profile or .I ~/.bashrc are not read. .SH SYNTAX .SS Quoting .TP .B \(aq...\(aq Everything is literal. .TP .B \(dq...\(dq Variables and command substitutions are expanded, the result stays one word. .TP .B \e Escapes the next character. .SS Variables .TP .I name\fB=\fPvalue Set a variable. All variables are exported to the environment of started programs. The value is not split into words and not expanded as a pattern; variables, command substitutions and .B ~ (at the start, after .B = and after .BR : ) are expanded. .TP .I name\fB=\fPvalue command Set the variable only for .IR command . .TP .BR $VAR ", " ${VAR} The value of .BR VAR . Using an unset variable is an error and aborts the command. .TP .B ${VAR:\-default} The value of .BR VAR , or .I default if it is unset or empty. Use .B ${VAR:\-} for an empty default. .TP .B $? The exit status of the last command. .SS Positional parameters .TP .B $0 The name of the script, or the .I name given after .BR "gosh \-c" . .TP .BR $1 " ... " $9 ", " ${10} The arguments of the script, of .BR "gosh \-c" , of a function call or of .BR source , or the words set with .BR "set \-\-" . An unset parameter is an error like an unset variable; use .B ${1:\-} for an optional argument. .TP .B $# The number of positional parameters. .TP .B \(dq$@\(dq All positional parameters, each as a separate word. Without parameters it expands to no word at all. .TP .B \(dq$*\(dq All positional parameters as one word, separated by blanks. .TP .B $$ The process ID of the shell. .SS Command substitution .B $(\fIcommand\fP) is replaced by the output of .IR command , which runs in a subshell. Trailing newlines are removed. Unquoted, the output is split into words at blanks and newlines; inside double quotes it stays one word. Wildcards and operators in the output are not interpreted. Backticks and arithmetic expansion are not supported. .SS Tilde and brace expansion .B ~ and .B ~/path at the start of an unquoted word are replaced by the home directory. .PP Brace expansion generates several words from one: .B a{b,c}d becomes .BR "abd acd" , .B {1..5} becomes .BR "1 2 3 4 5" , .B {01..10..4} becomes .B 01 05 09 and .B {a..e} becomes .BR "a b c d e" . Brace expansion happens before all other expansions. .SS Wildcards .B * matches any string, .B ? any single character, .B [abc] and .B [a\-z] one of the given characters and .B [!abc] (or .BR [^abc] ) any character except those. Matches are sorted. Hidden files are only matched if the pattern starts with a dot. A pattern without match is kept unchanged. Quoted wildcards and values of variables are never expanded. .SS Command lists .TP .IB a " ; " b Run .IR a , then .IR b . .TP .IB a " && " b Run .I b only if .I a succeeded. .TP .IB a " || " b Run .I b only if .I a failed. .TP .IB command " &" Run .I command in the background. .SS Pipes and redirections .TP .IB a " | " b Connect standard output of .I a to standard input of .IR b . The exit status is the one of .IR b . .TP .BI < " file" Read standard input from .IR file . .TP .BR > " \fIfile\fP, " >> " \fIfile\fP" Write (or append) standard output to .IR file . .TP .BR 2> " \fIfile\fP, " 2>> " \fIfile\fP" Write (or append) standard error to .IR file . .TP .B 2>&1 Redirect standard error to where standard output goes. .TP .B >&2 Redirect standard output to where standard error goes. .TP .BR &> " \fIfile\fP, " &>> " \fIfile\fP" Write (or append) standard output and standard error to .IR file . .TP .BI << word Here-document: the lines after the command, up to a line that is exactly .IR word , are standard input. If no part of .I word is quoted, variables, command substitutions and backslashes before .BR $ , .BR \(ga , .B \e and newline are expanded in the lines. .BI <<\- word also removes leading tabs from the lines and the delimiter line. .TP .BI <<< " word" Here-string: .I word and a newline are standard input. .PP Redirections are evaluated from left to right. Only file descriptors 0, 1 and 2 are supported. .SS Control structures .nf \fBif\fP \fIlist\fP; \fBthen\fP \fIlist\fP; [\fBelif\fP \fIlist\fP; \fBthen\fP \fIlist\fP;] [\fBelse\fP \fIlist\fP;] \fBfi\fP \fBfor\fP \fIname\fP \fBin\fP \fIwords\fP; \fBdo\fP \fIlist\fP; \fBdone\fP \fBwhile\fP \fIlist\fP; \fBdo\fP \fIlist\fP; \fBdone\fP \fBuntil\fP \fIlist\fP; \fBdo\fP \fIlist\fP; \fBdone\fP \fBcase\fP \fIword\fP \fBin\fP [\fB(\fP]\fIpattern\fP[\fB|\fP\fIpattern\fP]...\fB)\fP \fIlist\fP \fB;;\fP ... \fBesac\fP \fB{\fP \fIlist\fP; \fB}\fP \fB(\fP \fIlist\fP \fB)\fP \fB!\fP \fIcommand\fP .fi .PP Control structures may span several lines; an incomplete command shows the continuation prompt .BR "> " . .B ! negates the exit status of a command. .B for without .B in loops over the positional parameters. .PP .B case runs the list of the first clause with a pattern that matches .IR word . Patterns are wildcards as for file names, but .B * and .B ? also match a .BR / ; quoted characters match literally, and values of variables are not patterns. The .B ;; of the last clause may be omitted. .PP .B { .IR list ; .B } groups commands; they run in the current shell. .B ( .I list .B ) runs the commands in a subshell, a new .B gosh process, so that changes of the directory, variables and functions only apply there. .PP Redirections after a control structure .RB ( "done < file" , .BR "fi > log 2>&1" ) apply to all commands in it, which still run in the current shell. In a pipe and in the background .RB ( & ), a control structure runs in a subshell, like in .BR sh (1). The subshell knows the functions and positional parameters of the shell. .SS Functions .nf \fIname\fP\fB() {\fP \fIlist\fP; \fB}\fP \fBfunction\fP \fIname\fP \fB{\fP \fIlist\fP; \fB}\fP .fi .PP defines a function; the body can be any compound command. When the function is called, its arguments are the positional parameters, which get their old values back afterwards. Functions run in the current shell, so variables they set stay set; use .B local for variables that belong to the function. Redirections of a call apply to all commands of the function. In pipes, in the background and in .B $(...) a function runs in a subshell that knows all functions. Functions take precedence over builtins and programs of the same name. Calls can be nested up to a depth of 1000. .SS Aliases In interactive shells, the first word of a command is replaced by its alias. If the alias value ends with a blank, the next word is checked for an alias as well. .B \e\fIname\fP or .B \(aq\fIname\fP\(aq skips the alias. Aliases are not used in scripts and with .BR \-c . .SH BUILTIN COMMANDS .TP .BR cd " [\fIdir\fP]" Change the directory; without argument to the home directory. .TP .B pwd Print the working directory. .TP .BR echo " [\fIargs\fP]" Print the arguments. .TP .BR exit " [\fIcode\fP], " quit " [\fIcode\fP]" Exit the shell with status .I code (default: .BR $? ). .TP .BI set " VAR" = value Set a variable. .TP .BR "set \-\-" " [\fIargs\fP ...]" Set the positional parameters. .TP .BI export " VAR" = value Export a variable. .TP .BR unset " [\fB\-v\fP] \fIVAR\fP ..., " "unset \-f" " \fIname\fP ..." Remove variables, or functions. .TP .BR source " \fIfile\fP [\fIargs\fP ...], " . " \fIfile\fP [\fIargs\fP ...]" Run the commands of .I file in the current shell, with .I args as positional parameters if given. .TP .B jobs List background and stopped jobs. .TP .BR fg " [\fB%\fP\fIn\fP]" Continue job .I n (default: the current job) in the foreground. .TP .BR bg " [\fB%\fP\fIn\fP]" Continue stopped job .I n in the background. .TP .BR wait " [\fB%\fP\fIn\fP]" Wait for job .I n or for all background jobs. .TP .BR alias " [\fIname\fP[\fB=\fP\fIvalue\fP] ...]" Define or show aliases. .TP .BR unalias " \fIname\fP, " "unalias \-a" Remove an alias, or all aliases. .TP .B : Do nothing, exit status 0. .TP .BR break " [\fIn\fP], " continue " [\fIn\fP]" Leave the innermost (or .IR n -th) loop, or continue with its next iteration. .TP .BR return " [\fIn\fP]" Leave a function or sourced file with status .I n (default: .BR $? ). .TP .BR local " \fIVAR\fP[\fB=\fP\fIvalue\fP] ..." In a function: the variable gets its previous value back when the function returns. Without a value it is unset. .TP .BR shift " [\fIn\fP]" Remove the first .I n (default 1) positional parameters. .TP .BR read " [\fB\-r\fP] [\fB\-p\fP \fIprompt\fP] [\fIVAR\fP ...]" Read a line from standard input and split it into fields at the characters of .B IFS (default blank, tab and newline). Each .I VAR gets one field, the last one the rest of the line; without .I VAR the whole line is stored in .BR REPLY . Without .BR \-r , a backslash escapes the next character and continues the line at its end. .B \-p prints .I prompt if the input is a terminal. The exit status is 1 at the end of the input. .TP .B help Show a summary of builtins and features. .SH JOB CONTROL In interactive shells, each command line runs as a job in its own process group. .B Ctrl+Z stops the foreground job, .B Ctrl+C interrupts it. .BR jobs , .BR fg , .B bg and .B wait manage the jobs; .B %n or .I n refers to job .IR n , .B %\- to the previous job. Finished background jobs are reported before the next prompt. Exiting with stopped jobs warns once. .SH INTERACTIVE USE .TP .B Up/Down Browse the command history. .TP .B Tab Complete commands, aliases and file names. .TP .B Ctrl+C Cancel the current line or command. .TP .B Ctrl+D Exit the shell. .PP Lines starting with a space are not saved in the history. .PP The prompt shows .IR user @ host : dir followed by .BR $ . If the last command failed, its exit status is shown as .BI [ N ] before the .BR $ . .SH ENVIRONMENT .TP .B GOSH_HISTFILE Path of the history file. If set to an empty value, no history is saved. .TP .B XDG_STATE_HOME Base directory of the default history file .IR $XDG_STATE_HOME/gosh/history . .TP .B GOSH_COLORS Prompt colors as colon-separated .IB key = code entries. Keys are .B user (default .BR 1;32 ), .B root .RB ( 1;31 ), .B path .RB ( 1;34 ) and .B error .RB ( 1;31 ); values are ANSI SGR codes, an empty value disables the color. Example: .B GOSH_COLORS=\(aquser=1;33:path=36\(aq .TP .B NO_COLOR If set, the prompt is not colored. Colors are also disabled with .B TERM=dumb or when the output is not a terminal. .TP .B HOME Used for .B ~ and .B cd without argument. .TP .B PATH Directories searched for commands. .TP .B IFS Field separators for .BR read . .SH FILES .TP .I /etc/gosh/profile System-wide profile for login shells. .TP .I ~/.gosh_profile Personal profile for login shells. .TP .I /etc/gosh/goshrc System-wide startup file for interactive shells. .TP .I ~/.goshrc Personal startup file for interactive shells. .TP .I ~/.local/state/gosh/history Default history file (mode 0600). .SH EXIT STATUS The exit status of the last command, or the argument of .BR exit . Typical values: .TP .B 1 General error. .TP .B 2 Syntax error or invalid option. .TP .B 126 Command not executable. .TP .B 127 Command not found. .TP .BI 128+ n Command terminated by signal .I n (130 for Ctrl+C). .SH EXAMPLES .nf gosh \-c \(aqcd /srv && git log | head\(aq for f in *.log; do gzip "$f"; done cp config.yaml{,.bak} make > build.log 2>&1 || echo "failed: $?" LANG=C sort file alias ll=\(aqls \-l\(aq greet() { echo "Hello ${1:\-World}"; } git ls\-files | while read \-r f; do wc \-l "$f"; done while read \-r user rest; do echo "$user"; done < /etc/passwd (cd build && make) > build.log 2>&1 case "$1" in start|stop) echo "$1ing" ;; *) echo "usage: $0 start|stop" ;; esac read \-r \-p \(aqName? \(aq name chsh \-s /usr/bin/gosh .fi .SH SEE ALSO .BR sh (1), .BR bash (1), .BR chsh (1), .BR shells (5) .SH AUTHOR Florian Walther