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>
This commit is contained in:
Florian WaltherandClaude Opus 5.5 committed 2026-10-03 23:27:55 +02:00
1 parent dae4087a94
commit 187de30351
4 files changed
+422 -15

No files matched your search

+31 -15
View File
@@ -702,7 +702,7 @@ type shellCompleter struct {
func newShellCompleter() *shellCompleter {
return &shellCompleter{
commands: []string{"cd", "pwd", "echo", "exit", "quit", "set", "export", "source", "jobs", "fg", "bg", "wait", "help"},
commands: []string{"cd", "pwd", "echo", "exit", "quit", "set", "export", "source", "jobs", "fg", "bg", "wait", "alias", "unalias", "help"},
}
}
@@ -726,7 +726,8 @@ func (c *shellCompleter) Do(line []rune, pos int) ([][]rune, int) {
// Complete commands
var candidates [][]rune
seen := make(map[string]bool)
for _, cmd := range append(c.commands, pathExecutables(word)...) {
names := append(append(append([]string(nil), c.commands...), aliasNames()...), pathExecutables(word)...)
for _, cmd := range names {
if strings.HasPrefix(cmd, word) && !seen[cmd] {
seen[cmd] = true
candidates = append(candidates, []rune(escapeWord(cmd[len(word):])+" "))
@@ -951,6 +952,8 @@ flags:
script = func() int { return runScript(os.Stdin, "") }
}
// Aliases are expanded in interactive shells, also in their startup files
interactiveShell = interactiveMode
for _, file := range startupFiles(login && !noProfile, interactiveMode && !noRC) {
sourceStartupFile(file)
}
@@ -1327,6 +1330,9 @@ scan:
// and ||. It returns the error of the last command that was run; errors of
// earlier commands are printed. $? is updated after each command.
func execInput(input string) error {
if interactiveShell {
input = expandAliases(input)
}
items, err := splitList(input)
if err != nil {
lastStatus = exitStatus(err)
@@ -1636,19 +1642,21 @@ func applyRedirects(fds *[3]*os.File, redirects []redirect) ([]*os.File, error)
// the shell cannot be used in a pipeline, since there they would run
// concurrently (sh runs them in a subshell where they have no effect).
var builtins = map[string]struct{ changesState bool }{
"cd": {changesState: true},
"pwd": {},
"exit": {changesState: true},
"quit": {changesState: true},
"set": {changesState: true},
"export": {changesState: true},
"help": {},
"source": {changesState: true},
".": {changesState: true},
"jobs": {},
"fg": {changesState: true},
"bg": {changesState: true},
"wait": {changesState: true},
"cd": {changesState: true},
"pwd": {},
"exit": {changesState: true},
"quit": {changesState: true},
"set": {changesState: true},
"export": {changesState: true},
"help": {},
"source": {changesState: true},
".": {changesState: true},
"jobs": {},
"fg": {changesState: true},
"bg": {changesState: true},
"wait": {changesState: true},
"alias": {},
"unalias": {changesState: true},
}
// runBuiltin executes a built-in command, writing its output to stdout.
@@ -1728,6 +1736,10 @@ func runBuiltin(args []string, stdout io.Writer) error {
}
os.Setenv(parts[0], parts[1])
return nil
case "alias":
return builtinAlias(args, stdout)
case "unalias":
return builtinUnalias(args)
case "jobs":
return builtinJobs(stdout)
case "fg":
@@ -1758,6 +1770,8 @@ Built-in commands:
fg [%n] - Continue job n (default: current job) in the foreground
bg [%n] - Continue stopped job n in the background
wait [%n] - Wait for job n or all background jobs
alias [name[=value] ...] - Define or show aliases (alias ll='ls -l')
unalias name - Remove an alias (unalias -a: all aliases)
help - Show this help
Features:
@@ -1784,6 +1798,8 @@ Features:
2>> file, 2>&1, >&2, &> file (stdout and stderr), &>> file
- Job control: command & runs in the background, Ctrl+Z stops the
foreground job; jobs, fg, bg and wait manage the jobs
- Aliases replace the first word of a command in interactive shells
(define them in ~/.goshrc); \name or 'name' skips the alias
- Non-interactive use: gosh -c 'command', gosh script, command | gosh;
the exit status is the one of the last command
- Startup files: login shells (-l or argv[0] starting with -) read