If my goal is to write a script for POSIX compatible shells, scripts that I would begin with #!/bin/sh, how permissible is this [[
syntax.
Not at all. Many modern Linux-based systems use dash
as /bin/sh
by default, which is fully POSIX-compliant and no more, and so [[
will not work. This includes every recent Debian and Ubuntu release, and their derivatives, as well as many other distributions. Historically these systems commonly used Bash there instead, and deliberately switched to improve performance.
Many other systems, including most of the BSDs and most commercial Unices, don't support [[
either and never have: their sh
is POSIX-only, or its extensions don't include the [[
syntax. OpenBSD's sh
does support a version of [[
, which is slightly different than Bash's; I don't know of any others that do, although they may exist. Otherwise, it's only systems that use Bash as /bin/sh
(or less often zsh
, or even less often some others) where [[
will work in something declared to be a sh
script.
On the other hand, the large majority of systems have Bash installed in practice, and just making your script explicitly be run with bash
will suffice for all of them. Bash's sh
-emulation mode has always been broken anyway.
Since you're relying on Bash features, I can't see any reason at all you'd want to declare it as a sh
script: just say #!/bin/bash
and be done, using [[
as much as you want — or even better, to the total exclusion of [
. If you instead want maximum portability, use [
or test
and POSIX sh
1, and write carefully.
1Note that some of the commercial Unices have, or have had, non-POSIX sh
as /bin/sh
; to work uniformly on those you'll need to run the scripts with the full path to the system's POSIX sh
.
The rationale given in the POSIX specification is:
The "-exec ... {} +"
syntax adopted was a result of IEEE PASC Interpretation 1003.2 #210. It should be noted that this is an incompatible change to the ISO/IEC 9899:1999 standard. For example, the following command prints all files with a '-'
after their name if they are regular files, and a '+'
otherwise:
find / -type f -exec echo {} - ';' -o -exec echo {} + ';'
The change invalidates usage like this. Even though the previous standard stated that this usage would work, in practice many did not support it and the standard developers felt it better to now state that this was not allowable.
PASC Interpretation 1003.2 #210 goes into more detail about the history of -exec … {} +
. It existed on several Unix systems before it was adopted by POSIX; the defect report traces it back to SVR4 (where it was largely undocumented). The defect report justifies the incompatible change as having little impact in practice:
Note that the "+" is only treated as special if it immediately
follows "{}". This minimises the chances of causing problems with
existing uses of "+" as an argument with "-exec".
Although adding support for -exec … {} +
would break some conforming applications such as the example above, there are fewer of these than if -exec … {} … +
was allowed.
Another reason, perhaps, to restrict {}
to be the last argument is ease of implementation. If {}
was allowed anywhere in the argument list to -exec
, the find
program would have to build the command line by copying the static arguments, then the variable part, then another static part. This would make it harder to construct the argument list and to account for the size limit. The difficulty is minimal, but implementers like to cut corners. Supporting multiple substitutable instances of {}
(if -exec {} foo +
is to work, it can be logically expected that -exec {} foo {} +
would as well) would be significantly harder.
Best Answer
POSIX defines “absolute pathname” as follows:
and “relative pathname” as follows:
That’s all there is to it for relative and absolute paths.
Canonical paths aren’t defined in POSIX, but the term usually refers to comparable paths, i.e. if you take two paths to a file system object, and convert them to canonical form, the result should be identical if and only if the two file system objects are identical. This involves removing “..” as you mention, but it also means resolving symbolic links; so a canonical path could be defined as
In POSIX terms, a canonical pathname is effectively a resolved pathname (as long as you accept that canonical pathnames can only be determined for file system objects which exist).
Note that this only works because hard-linked directories aren’t allowed...
So to answer your questions:
/../
;/../
, nor can it contain/./
,//
(except arguably in first position), or symbolic links;foo
is a relative path.(Pedantically, they are all pathnames, not just paths.)