[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: x[

From: Martijn Dekker
Subject: Re: x[
Date: Tue, 30 Jul 2019 00:01:17 +0200
User-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:60.0) Gecko/20100101 Thunderbird/60.8.0

Op 29-07-19 om 19:09 schreef Eli Schwartz:
The initial workaround discovered, was to use

$ function _[ () { echo hello; }; <() _[

The use of <() somehow suppresses the glitch in the same way that
quoting it does. If it were just glob expansion, then why should that be so?

As others pointed out, it's the start of an array assignment, and associative array indexes can contain newlines.

So we can de-obfuscate the issue by looking at a simple variable assignment 'x=foo' instead. Consider:

$ function x=foo { echo hello; }; <() x=foo


$ function x=foo { echo hello; }; </dev/null x=foo
(no output)
$ echo $x

In that case, 'x=foo' is interpreted as an assignment. Which is correct, because redirections can occur in any word of a simple command, including before and between assignments and arguments. They are performed and removed before further parsing and executing the command.

<(Process substitution) may look superficially like a fancy form of redirection[*], but it's actually more akin to command substitution: the command inside is run, and the substitution is replaced, not with that command's output, but with a file name from which to read that command's output (or, in the case of >(process substitution), a file name to which to write that command's input).

Because that command is empty in this instance, bash does not bother to substitute a file name, and the <() is substituted by nothing.

So, let's get rid of the function (because it is a distraction) and just see how 'x=foo' is parsed in substitutions and redirections:

$ <() x=foo
bash: x=foo: command not found
$ $() x=foo
bash: x=foo: command not found
$ `` x=foo
bash: x=foo: command not found
$ </dev/null x=foo
(no output)

Here it is also important to understand that a "simple command" consists of either assignments, or command words, or both:

        x=foo y=bar some command here

So, both process substitution and command substitution (both forms) signal to the parser that the preceding assignments in a simple command have ended, and we're now on to command words and thus trying to execute a command called 'x=foo'. This is also true on simple POSIX shells like dash (for command substitution -- they don't have process substitution). The fact that the substitutions are empty, and thus substituted by nothing, does not stop them from influencing the parser.

The same is not true for redirections, which are specified by POSIX to be parsed and removed at the earliest stage, before even distinguishing between assignments and command words.

- M.

[*] Pointless lament: It's unfortunate that process substitution starts with '<' or '>' and not with $ like every other kind of substitution and expansion (except obsolete `command substitutions`). It confuses people into thinking of it in terms of redirection, which is very misleading.

By the way, in modernish, I've re-implemented process substitution in a form usable by all POSIX shells (including simple ones like dash), as a form of command substitution:
$( % your command here )        # like <(your command here)
$( % -o your command here )     # like >(your command here)

modernish -- harness the shell

reply via email to

[Prev in Thread] Current Thread [Next in Thread]