Some of my favourite features which are built in to the shell, not part of third-party plugin systems, include:

The "command1 =(command2)" syntax, which runs "command2", pipes its output to a new temporary file, runs "command1" with that file's name as an argument, and then removes the temporary file, all in one operation. It's like "<(command2)", which is in Bash and Zsh, but allows "command1" to perform a seek on the file because it's not a pipe.

Redirections like ">file" where there's no command implicitly use cat, so ">file" just pipes STDIN to the file. Same for "<file", which pipes file to STDOUT.

"command &>/dev/null" is shorthand for "command >/dev/null 1>&2".

Floating-point arithmetic built-in (Bash has integer arithmetic only), including C math functions like sin, log, floor.

Implicit insertion of "tee" where you obviously want it; for example, "command >file1 >file2" is the same as "command | tee file1 > file2"

You don't need to quote variable expansions like $1 (except arrays). You still have to do so for command expansions $(command

More expressive pattern syntax, including backreferences, approximate matching (using Damerau-Levenshtein distance), and flags/qualifiers to limit searching to specific kinds of file. E.g. "ls *(-@)" lists all broken symbolic links.

The string =foo is expanded to the path to the "foo" command in $PATH, which allows you to do, for example, "vim =myscript" without needing to remember where "myscript" is exactly.

Lots of parameter expansion flags for various string operators (search/replace, sorting, case translation, splitting and joining, ...).

POSIX extended regex and optional PCRE support for pattern matching.

zle, which does a similar job to readline in bash, but with an enormous number of useful features built-in.

Generalised tilde expansion: ~ is the current user's $HOME, but ~john is the user john's home directory. You can make up your own using "hash -d foo=/path/too/foo"; now "~foo" refers to "/path/to/foo".

Dynamic version of the above: ~[string] uses the function zsh_directory_name to expand "string" into any path; see the manual "zshexpn(1) § Filename Generation § Dynamic named directories".

Easily create more explicit pipes using file descriptors:

# open
exec {fd}>file

command1 >&$fd
command2 >&$fd
#...

# close
exec {fd}>&-

Additional concise and useful syntax for loops, function definitions, etc.:

while (( x < 5 )) { echo $x; let x++ } # more obvious than "
repeat 5 echo hi # does what it says on the tin
myfunc() echo hi # declares a function
for ((x = 0; x++; x < 5)) { echo $i } # C-style for-loop

The equivalent of "try-finally" in some programming languages:

{
# do some stuff which might error
} always {
# do some important cleanup
}

This construct also enables special support for another feature: actual exceptions with throw/catch.

Very flexible prompt expansion: conditionals using %(condition.true.false). Optionally, command expansion "$()" can be enabled in prompts.

All kinds of extra optional modules which can be loaded using "zmodload", for manipulating xattrs, POSIX Capabilities, TCP sockets, an FTP client!?; also, built-in plugin functions which can be loaded with "autoload": a full calendar application, an interactive calculator, colours, regex replace, tetris!

> Zsh was once accused of not being as complete as Emacs, because it lacked a Tetris game. This function was written to refute this vicious slander.

autoload -U tetriscurses
tetriscurses

Ability to set the value of argv[0] received by a command, rather than just the name it was invoked by, e.g. "ARGV0=ls busybox"

Options to emulate the behaviour of other shells: pure POSIX sh, ksh, etc.?

Sorry, that was perhaps a bit more than "some of my favourites". It really does have a lot of stuff.