Commit Graph
32 Commits
Author SHA1 Message Date
Florian WaltherandClaude Opus 5.5 82f9c90a39 add custom prompts with PS1 and PS2
PS1 and PS2 support the backslash escapes of bash (\u \h \w \W \$ \t \j
\e \[ \] ...) and expand $VAR, ${...}, $(...) and $((...)) before each
prompt. Values of escapes and expansions are sanitized. Lines before the
last one and non-SGR escape sequences are written before readline's
prompt. Without PS1, the default prompt is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 22:49:19 +02:00
Florian WaltherandClaude Opus 5.5 af5281eed2 report the working directory to the terminal with OSC 7
Before each prompt gosh sends ESC ] 7 ; file://host/path BEL (host and
path percent-encoded), so terminals like GNOME Terminal open new tabs
and windows in the directory of the shell instead of the one gosh was
started in. Nothing is sent if stdout is not a terminal or TERM=dumb.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 19:22:59 +02:00
Florian WaltherandClaude Opus 5.5 1f507f6562 add parameter expansion, arithmetic, set -e/-x/pipefail, trap, eval, exec
- ${#v}, ${v#p} ${v##p} ${v%p} ${v%%p}, ${v/p/r} ${v//p/r} ${v/#p/r}
  ${v/%p/r}, ${v:off:len}, ${v-w} ${v:=w} ${v:+w} ${v:?msg}; nested ${}
- arithmetic expansion $((...)) with the C operators, ** and assignments
- set -e, set -x, set -o pipefail (also as gosh options, passed on to
  subshells); set shows variables, set -o the options
- trap for EXIT and signals; scripts with an EXIT trap run it on
  SIGINT/SIGTERM/SIGHUP too
- eval, exec (also exec > file without a command), $!, wait pid

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 21:15:24 +02:00
Florian WaltherandClaude Opus 5.5 f66cf538c0 add subshells, here-documents and redirections/pipes for control structures
- control structures can have redirections (while read l; do ...; done
  < file), which apply to all commands in them; they run in the shell
- in pipes and in the background they run in a subshell (cmd | while
  read l; do ...; done, for ...; done &, a && b &)
- ( list ) subshells; ( and ) are operators now
- here-documents <<EOF, <<-EOF, <<'EOF' and here-strings <<<word
- redirections of source apply to the commands of the file
- fix non-ASCII characters in quotes being mangled ('für')

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 20:57:15 +02:00
Florian WaltherandClaude Opus 5.5 443367f66f add functions, positional parameters, case and read
- functions: name() { ...; }, function name { ...; }, return, local,
  unset -f; in pipes, & and $(...) they run in a subshell that gets all
  function definitions and the positional parameters
- positional parameters $0, $1 ... ${10}, $#, "$@", "$*", $$; set by
  gosh script args, gosh -c command name args, function calls,
  source file args and set --; shift; for x without "in"
- case word in pattern|pattern) ...;; esac and { list; } groups
- read [-r] [-p prompt] [name ...] with $IFS splitting and $REPLY

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 17:20:59 +02:00
Florian WaltherandClaude Opus 5.5 9fe8b06fba add man page gosh(1) and include it in the deb/rpm packages
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 13:59:09 +02:00
Florian WaltherandClaude Opus 5.5 22ce8c00d4 add assignments name=value and unset
- name=value (one or more) without a command sets variables of the shell
- name=value before a command sets them only in its environment (for
  builtins only while they run)
- an assignment needs an unquoted name and =; the value is not split
  and not expanded as wildcard or brace pattern, ~ is expanded after =
  and :
- the status of an assignment is the one of its last $(...)
- new builtin unset

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 00:17:38 +02:00
Florian Walther fb94e98da5 updated README 2026-10-04 00:16:29 +02:00
Florian WaltherandClaude Opus 5.5 f79fb0b8d5 add control structures: if, for, while, until
- new parser (parser.go) for lists, pipelines, ! and if/elif/else/fi,
  for ... in ... do/done, while/until ... do/done; simple commands are
  kept as text and expanded when they run (in every iteration)
- break [n], continue [n] and the : builtin
- incomplete input (open control structure, trailing &&, |, quote or
  backslash) continues on the next line: prompt "> " in interactive
  shells, scripts and startup files read on
- Ctrl+C aborts the whole command line, including loops
- aliases are expanded at the start of every simple command, also inside
  control structures
- control structures in pipelines, with redirections or in the
  background are reported as not supported
- completion: commands after if, then, do etc.
- main_test.go reformatted with gofmt

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 00:05:28 +02:00
Florian WaltherandClaude Opus 5.5 e49fe6fe11 add command substitution $(...)
- $(command) is replaced by the output of command, which runs in a
  subshell (gosh -c), so cd/set in it do not change the shell
- trailing newlines are removed; unquoted the output is split into words
  at blanks and newlines, "$(...)" stays one word; wildcards in the
  output are not expanded
- nested substitutions, quotes and operators inside are handled; the
  list, alias and brace scanners skip $(...) as a whole
- a command that consists only of a substitution has its exit status,
  Ctrl+C in a substitution aborts the command
- $((...)) is reported as not supported

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 23:52:09 +02:00
Florian WaltherandClaude Opus 5.5 041406a340 show the exit status of a failed command in the prompt
- user@host:dir [N] $ after a command failed with exit status N,
  the plain prompt again after a successful command
- the status is colored bold red by default, configurable with the new
  GOSH_COLORS key error

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 23:46:11 +02:00
Florian WaltherandClaude Opus 5.5 b3311cbf94 add brace expansion
- a{b,c}d, nested braces, empty alternatives (file{,.bak})
- sequences {1..5}, {5..1}, {1..10..3}, zero-padded {01..10}, letters
  {a..e}
- happens first on the command text, the results go through ~,
  variable and wildcard expansion
- quoted/escaped braces, ${...} and braces without comma or valid
  sequence are kept; \, protects a comma
- a redirection target must expand to one word (ambiguous redirect),
  a word may expand to at most 100000 words
- completion escapes { in file names

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 23:42:25 +02:00
Florian WaltherandClaude Opus 5.5 da281ca4ab fix job control on FreeBSD and macOS: do not use WCONTINUED
Go's syscall.WaitStatus decodes the "continued" status wrongly on BSD:
on FreeBSD it is read as killed by SIGCONT, so after bg the job was
reported as "Exit 147" and removed from the job table while it was
still running (fg: "no such job"); on macOS it is read as stopped.

The shell marks jobs as running itself when it continues them, so wait4
is called without WCONTINUED and only exited/signaled statuses finish a
process.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 23:35:25 +02:00
Florian WaltherandClaude Opus 5.5 187de30351 add aliases
- alias name=value defines aliases, alias lists or shows them in a form
  that can be read back, unalias removes them (unalias -a: all)
- the first word of every command (at the start and after ;, &, &&, ||
  and |) is replaced, the value is expanded again except for aliases
  that are already being expanded (alias ls='ls --color' works)
- a value ending with a blank makes the next word a command name too
- quoted or escaped words (\ll, 'll') skip the alias
- aliases are only expanded in interactive shells and their startup
  files, like in bash
- tab completion includes aliases

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 23:27:55 +02:00
Florian WaltherandClaude Opus 5.5 dae4087a94 add job control
- in an interactive shell every pipeline runs in its own process group
  and gets the terminal while it runs in the foreground
- Ctrl+Z stops the foreground job, command & starts a job in the
  background; finished and stopped jobs are reported before the prompt
- new builtins jobs, fg, bg and wait (wait also works without job
  control, e.g. in scripts, where background jobs read from /dev/null)
- terminal modes are saved and restored when a job stops or continues
- exit and Ctrl+D warn once if there are stopped jobs
- processes are waited for with wait4 (WUNTRACED) instead of exec.Cmd.Wait
- pty based test for job control (Linux)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 23:22:21 +02:00
Florian WaltherandClaude Opus 5.5 4b44cc6e72 add startup files and the source builtin
- login shells (-l or argv[0] starting with -) read /etc/gosh/profile
  and ~/.gosh_profile, interactive shells /etc/gosh/goshrc and ~/.goshrc;
  --noprofile and --norc skip them
- source file / . file runs a file in the current shell, nesting is
  limited to stop files that source themselves
- errors in startup files and scripts are reported with file and line
- ~ and the startup files use $HOME (like sh), the user database is
  only the fallback

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 23:08:23 +02:00
Florian WaltherandClaude Opus 5.5 1182d8d146 add wildcards (*, ?, [...])
- unquoted * ? and [...] (including [!...]) are expanded to the
  matching file names, sorted, per path component
- hidden files only match if the pattern starts with a dot, a trailing /
  only matches directories, a pattern without match is kept as is
- quoted or escaped characters and values of variables are never
  expanded
- redirections to a pattern must match exactly one file
- completion escapes * ? [ and $ in file names

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 20:44:58 +02:00
Florian WaltherandClaude Opus 5.5 c46903e3d2 add pipes and redirections
- tokenizer recognizes unquoted |, <, >, >>, N>, N>>, N>&M, N<&M,
  &> and &>>; only a word of unquoted digits is a file descriptor
- pipelines run concurrently, the status is the one of the last command,
  errors of earlier stages are printed
- redirections are applied left to right (fds 0-2), a redirection
  without a command creates/truncates the file
- pwd and help can be redirected and piped; cd, set, export, exit and
  quit are rejected in pipelines
- syntax errors have exit status 2
- completion: commands after |, ;, && and ||, files after redirections;
  operator characters are escaped in completed names

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 20:39:38 +02:00
Florian WaltherandClaude Opus 5.5 f5c14dff90 add command lists (;, &&, ||) and $?
- split input at unquoted ;, && and || and run the commands like sh;
  variables are expanded per command when it runs
- $? and ${?} expand to the exit status of the last command,
  exit/quit without argument use it
- syntax errors for missing commands around operators (status 2)
- "command not found" message instead of the raw exec error, no more
  "exit status N" message when a command fails

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 20:32:39 +02:00
Florian WaltherandClaude Opus 5.5 b602e17622 add non-interactive mode: -c, script files and commands from stdin
- gosh -c 'command' runs the command and exits, so gosh works as login
  shell for ssh host command, scp and rsync
- gosh script runs a script file, lines starting with # are skipped
- without a terminal, commands are read from stdin (byte by byte, so
  started commands can read the rest of stdin)
- the exit status is the one of the last command (127 not found,
  126 not executable, 128+n killed by signal n)
- -i forces interactive mode, -l/--login is accepted

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 19:45:00 +02:00
Florian WaltherandClaude Opus 5.5 f51680f83c show version with branch and commit in help and -version
- add -version flag (besides --version and -V)
- help output includes the version
- commit and branch are set via ldflags by goreleaser; plain go build
  falls back to the VCS revision embedded by Go

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 19:38:48 +02:00
Florian WaltherandClaude Opus 5.5 03e791cbcd connect stdin of external commands to the terminal
Without Stdin, commands read from /dev/null, so interactive programs
like 'sudo su -', vim or ssh got EOF right away.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 19:10:30 +02:00
Florian WaltherandClaude Opus 5.5 2b8f06ea6d make prompt colors configurable via GOSH_COLORS
- GOSH_COLORS='user=..:root=..:path=..' with ANSI SGR codes,
  empty value disables the color for that part
- only digits and ';' are accepted, invalid entries are ignored
- read before every prompt, so 'set GOSH_COLORS=...' takes effect immediately
- document in help and README, including example color schemes

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 17:47:49 +02:00
Florian WaltherandClaude Opus 5.5 7afcecd053 add colored prompt
- user@host in bold green (bold red for root), directory in bold blue
- colors are disabled with NO_COLOR, TERM=dumb or when stdout is not a terminal
- parts are sanitized before adding the color codes
- only replace the home directory with ~ on a path boundary

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 17:31:09 +02:00
Florian WaltherandClaude Opus 5.5 37d6802815 add goreleaser configuration for binaries and deb/rpm packages
- build static binaries for linux, darwin and freebsd
- create deb and rpm packages that register gosh in /etc/shells
- publish releases to Gitea
- add --version flag, set at build time via ldflags

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 16:58:50 +02:00
Florian Walther d5c3d03a21 fixing bugs, update README,Help; adding .gitignore 2026-10-03 16:51:55 +02:00
Florian Walther 847b6cd5c6 fixing auto-completion 2026-10-03 16:33:40 +02:00
Florian Walther cc18208925 update README-md 2026-09-23 20:38:53 +02:00
Florian Walther ffe4547a86 update reademe 2026-09-23 20:36:52 +02:00
Florian Walther c44da98a1c update README 2026-09-23 20:33:19 +02:00
Florian Walther e1ef97de71 adding README 2026-09-23 20:32:21 +02:00
Florian Walther 6b177e15b3 first commit 2026-09-23 20:30:20 +02:00