Author's note: While more snippets have been prepared, I will honor the original restriction somewhat and wait for interest.
EDIT: It's been months,
and I suddenly realized I have a bunch of examples I haven't posted.
I'd hate for them to go unshared, so here they are now.
(new examples start at 16 bytes)
Zsh
Zsh may seem like a new language, given the (relatively) recent popularity of the "Oh My Zsh" framework,
but it in fact dates back to 1990, just one year after Bash released.
Zsh's syntax is inspired by the bourne shell and ksh.
Many people are familiar with Bash scripting, but don't understand how Zsh differs. Zsh brings a surprising amount of powerful constructs.
I'll be highlighting these differences here.
Length 1 Snippet
:
This is equivalent to the command true
. It returns zero (truthy in shell scripts).
Uses for this include short bodyless for
loops: for ((x;y;z)):
Length 2 Snippet
$a
Parameter expansion. If a
is set to some value, substitute that value.
Unlike in Bash and POSIX shells, if $a
is an array, this will expand to all non-empty elements
(or, in the language of shells, "words") of $a
.
Length 3 Snippet
$=s
This is equivalent to the expansion ${=s}
, which induces word splitting.
For parameter expansion forms that involve a prefix (except for flags, see below) or modifiers (see below)
the surrounding braces can be removed if unambiguous.
Unlike in Bash and POSIX shells, word splitting is not done on parameters by default.
To split on $IFS
, this construct is needed, or the option shwordsplit
needs to be set.
Length 4 Snippet
*(.)
When expanding globs, Zsh supports glob qualifiers specified in parentheses after the glob.
Appending (.)
as above will cause this glob to expand to all regular files in the directory.
There are dozens of globbing qualifiers, here are just a few:
/
: Directories
F
: Non-empty directories
@
: Symlinks
U
: Files owned by the effective UID
Yn
: When n
is a number, expand to the first n
matches.
Length 5 Snippet
${~x}
This will expand x
as a glob.
This is useful to match filenames, match case
expressions, and in [[
tests.
Length 6 Snippet
${s:l}
Zsh supports various modifiers to parameter expansion.
The l
modifier will lowercase all words of s
.
The equivalent construct in bash is "${s,,}"
(or if s
is an array: "${s[@],,}"
.
Other useful modifiers include:
a
: Turns paths into absolute paths
A
: Turns paths into absolute paths with symlinks resolved
s/foo/bar
: Does replacement on each element. Use gs/foo/bar
for global replacement.
&
: Repeat the previous substitution.
Length 7 Snippet
${(i)@}
Zsh also supports roughly 30 parameter expansion flags.
The i
flag will sort the parameters case-insensitively.
k
: Substitute the array keys instead of values
P
: Induce indirect parameter expansion: if a='b'
and b='c'
, then ${(P)a}
expands to 'c'
q
: Quote characters special to the shell with backslashes or $'\NNN'
. q-
and q+
will use different methods for quoting.
u
: Remove duplicate words in the expansion.
z
: Split into words according to shell parsing grammar: if c='"a b" c'
, then ${(z)c}
will split into "a b"
c
.
Length 8 Snippet
xy${^a}z
With this expression, if a
is some array (e.g.: a=(hello world)
),
a
is converted to a brace expansion (e.g.: xyhelloz
xyworldz
Length 9 Snippet
<<<${str}
Like in bash, this is a here-string.
Unlike in bash, if no command is provided, the string is printed to stdout.
This can often be used as a replacement for echo
,
except that the expansion of ${str}
occurs in a subshell.
Length 10 Snippet
$a[(r)a?*]
Array subscripts also have flags! r
is "reverse subscripting":
This will give the first word in a
whose value matches a?*
. (Likewise, R
gives the last match.)
Other flags include i
and I
which return the indices or keys of the match,
k
and K
which match the keys, or w
or f
which split scalar a
on words or lines, respectively.
Length 11 Snippet
b=(${@:*a})
This is another form of parameter expansion, it will expand to all words of "$@"
that exist in the array a
.
Similarly, ${@:|a}
will expand to the words of $@
which do not exist in a
.
Length 12 Snippet
${${(f)s}:h}
One of the most powerful features of Zsh is that parameter expansions can be indefinitely nested.
So this will take s
, split it on newlines, and then strip each line's the last path component. (/usr/bin/zsh
⇒ /usr/bin
)
Length 13 Snippet
$argv[i,i+10]
The numbered parameters $@
can also be found under the named array argv
.
For some purposes, this can be more convenient or more consistent if also working with other arrays.
There are two ways to get a substring or non-associative array.
The ${name:offset:length}
method works the same way in Bash,
but the $name[start,end]
method is different:
The subscripts use arithmetic expansion, like you'd find in $[ ]
or $(( ))
.
Length 15 Snippet
print -P %D{%F}
Like Bash's PS1
sequences, Zsh has its own prompt sequences.
%D
expands to the current date, with an optional {
string}
after it.
That string will be passed to strftime
to be expanded.
Variables can also be prompt-expanded with the %
expansion flag: ${(%)foo}
Length 16 Snippet
<<<$[[#16]8#755]
Arithmetic expansion supports any base from 2-36 (inclusive).
n#...
will interpret the number at that base, while [#n]
will return the number in that base.
The number will be printed as base#number
(this example: 16#351
) with the exception of certain options and bases:
setopt nocbases
: No special cases
setopt cbases
: Base 16 numbers will be printed as 0x[num]
setopt cbases octalzeroes
: Base 8 numbers will also be printed as 0[num]
.
With setopt octalzeroes
, numbers with leading zeroes in arithmetic expansions will be interpreted as octal,
without needing the 8#
prefix.
Length 19 Snippet
setopt extendedglob
This deserves a post on its own...
This option adds a lot of new globbing options.
It's like changing from EREs to PCREs, but with globs.
I've started submitting zsh -oextendedglob
as a language for some challenges.
Length 29 Snippet
for x y (${a:^^b})c+=$[$#x+y]
Okay, there's a lot here. This will:
${a:^^b}
: Zip the arrays together, looping the shorter of the two arrays.
for x y (...)
: Pull words out two at a time, assigning them to x
and y
b+=($[$#x+y])
: Add the length of x
to the value of y
, and append that to c
.
Because only one operation is done for each iteration of the loop, no {
}
or do
done
is needed.