14.1.4 Modifiers

After the optional word designator, you can add a sequence of one or more of the following modifiers, each preceded by a ‘:’. These modifiers also work on the result of filename generation and parameter expansion, except where noted.

a

Turn a file name into an absolute path: prepends the current directory, if necessary; remove ‘.’ path segments; and remove ‘..’ path segments and the segments that immediately precede them.

This transformation is agnostic about what is in the filesystem, i.e. is on the logical, not the physical directory. It takes place in the same manner as when changing directories when neither of the options CHASE_DOTS or CHASE_LINKS is set. For example, ‘/before/here/../after’ is always transformed to ‘/before/after’, regardless of whether ‘/before/here’ exists or what kind of object (dir, file, symlink, etc.) it is.

A

Turn a file name into an absolute path as the ‘a’ modifier does, and then pass the result through the realpath(3) library function to resolve symbolic links.

Note: on systems that do not have a realpath(3) library function, symbolic links are not resolved, so on those systems ‘a’ and ‘A’ are equivalent.

Note: foo:A and realpath(foo) are different on some inputs. For realpath(foo) semantics, see the ‘P‘ modifier.

c

Resolve a command name into an absolute path by searching the command path given by the PATH variable. This does not work for commands containing directory parts. Note also that this does not usually work as a glob qualifier unless a file of the same name is found in the current directory.

e

Remove all but the part of the filename extension following the ‘.’; see the definition of the filename extension in the description of the r modifier below. Note that according to that definition the result will be empty if the string ends with a ‘.’.

h [ digits ]

Remove a trailing pathname component, shortening the path by one directory level: this is the ‘head’ of the pathname. This works like ‘dirname’. If the h is followed immediately (with no spaces or other separator) by any number of decimal digits, and the value of the resulting number is non-zero, that number of leading components is preserved instead of the final component being removed. In an absolute path the leading ‘/’ is the first component, so, for example, if var=/my/path/to/something, then ${var:h3} substitutes /my/path. Consecutive ‘/’s are treated the same as a single ‘/’. In parameter substitution, digits may only be used if the expression is in braces, so for example the short form substitution $var:h2 is treated as ${var:h}2, not as ${var:h2}. No restriction applies to the use of digits in history substitution or globbing qualifiers. If more components are requested than are present, the entire path is substituted (so this does not trigger a ‘failed modifier’ error in history expansion).

l

Convert the words to all lowercase.

p

Print the new command but do not execute it. Only works with history expansion.

P

Turn a file name into an absolute path, like realpath(3). The resulting path will be absolute, will refer to the same directory entry as the input filename, and none of its components will be symbolic links or equal to ‘.’ or ‘..’.

Unlike realpath(3), non-existent trailing components are permitted and preserved.

q

Quote the substituted words, escaping further substitutions. Works with history expansion and parameter expansion, though for parameters it is only useful if the resulting text is to be re-evaluated such as by eval.

Q

Remove one level of quotes from the substituted words.

r

Remove a filename extension leaving the root name. Strings with no filename extension are not altered. A filename extension is a ‘.’ followed by any number of characters (including zero) that are neither ‘.’ nor ‘/’ and that continue to the end of the string. For example, the extension of ‘foo.orig.c’ is ‘.c’, and ‘dir.c/foo’ has no extension.

s/l/r[/]

Substitute r for l as described below. The substitution is done only for the first string that matches l. For arrays and for filename generation, this applies to each word of the expanded text. See below for further notes on substitutions.

The forms ‘gs/l/r’ and ‘s/l/r/:G’ perform global substitution, i.e. substitute every occurrence of r for l. Note that the g or :G must appear in exactly the position shown.

See further notes on this form of substitution below.

&

Repeat the previous s substitution. Like s, may be preceded immediately by a g. In parameter expansion the & must appear inside braces, and in filename generation it must be quoted with a backslash.

t [ digits ]

Remove all leading pathname components, leaving the final component (tail). This works like ‘basename’. Any trailing slashes are first removed. Decimal digits are handled as described above for (h), but in this case that number of trailing components is preserved instead of the default 1; 0 is treated the same as 1.

u

Convert the words to all uppercase.

x

Like q, but break into words at whitespace. Does not work with parameter expansion.

The s/l/r/ substitution works as follows. By default the left-hand side of substitutions are not patterns, but character strings. Any character can be used as the delimiter in place of ‘/’. A backslash quotes the delimiter character. The character ‘&’, in the right-hand-side r, is replaced by the text from the left-hand-side l. The ‘&’ can be quoted with a backslash. A null l uses the previous string either from the previous l or from the contextual scan string s from ‘!?s’. You can omit the rightmost delimiter if a newline immediately follows r; the rightmost ‘?’ in a context scan can similarly be omitted. Note the same record of the last l and r is maintained across all forms of expansion.

Note that if a ‘&’ is used within glob qualifiers an extra backslash is needed as a & is a special character in this case.

Also note that the order of expansions affects the interpretation of l and r. When used in a history expansion, which occurs before any other expansions, l and r are treated as literal strings (except as explained for HIST_SUBST_PATTERN below). When used in parameter expansion, the replacement of r into the parameter’s value is done first, and then any additional process, parameter, command, arithmetic, or brace references are applied, which may evaluate those substitutions and expansions more than once if l appears more than once in the starting value. When used in a glob qualifier, any substitutions or expansions are performed once at the time the qualifier is parsed, even before the ‘:s’ expression itself is divided into l and r sides.

If the option HIST_SUBST_PATTERN is set, l is treated as a pattern of the usual form described in Filename Generation. This can be used in all the places where modifiers are available; note, however, that in globbing qualifiers parameter substitution has already taken place, so parameters in the replacement string should be quoted to ensure they are replaced at the correct time. Note also that complicated patterns used in globbing qualifiers may need the extended glob qualifier notation (#q:s/.../.../) in order for the shell to recognize the expression as a glob qualifier. Further, note that bad patterns in the substitution are not subject to the NO_BAD_PATTERN option so will cause an error.

When HIST_SUBST_PATTERN is set, l may start with a # to indicate that the pattern must match at the start of the string to be substituted, and a % may appear at the start or after an # to indicate that the pattern must match at the end of the string to be substituted. The % or # may be quoted with two backslashes.

For example, the following piece of filename generation code with the EXTENDED_GLOB option:

print -r -- *.c(#q:s/#%(#b)s(*).c/'S${match[1]}.C'/)

takes the expansion of *.c and applies the glob qualifiers in the (#q...) expression, which consists of a substitution modifier anchored to the start and end of each word (#%). This turns on backreferences ((#b)), so that the parenthesised subexpression is available in the replacement string as ${match[1]}. The replacement string is quoted so that the parameter is not substituted before the start of filename generation.

The following f, F, w and W modifiers work only with parameter expansion and filename generation. They are listed here to provide a single point of reference for all modifiers.

f

Repeats the immediately (without a colon) following modifier until the resulting word doesn’t change any more.

F:expr:

Like f, but repeats only n times if the expression expr evaluates to n. Any character can be used instead of the ‘:’; if ‘(’, ‘[’, or ‘{’ is used as the opening delimiter, the closing delimiter should be ’)’, ‘]’, or ‘}’, respectively.

w

Makes the immediately following modifier work on each word in the string.

W:sep:

Like w but words are considered to be the parts of the string that are separated by sep. Any character can be used instead of the ‘:’; opening parentheses are handled specially, see above.