[Toybox] Shell corner cases.
Rob Landley
rob at landley.net
Thu May 1 15:23:52 PDT 2025
On 5/1/25 16:43, Chet Ramey wrote:
> On 5/1/25 3:44 PM, Rob Landley wrote:
>> On 5/1/25 10:29, Chet Ramey wrote:
>>> On 4/30/25 6:23 PM, Rob Landley wrote:
>>>
>>>> Somebody forwarded that to me from an exploit how-to site. It's
>>>> apparently a trick used to subvert scripts that call things via
>>>> absolute path to avoid malicious $PATH.
>>>
>>> I suppose if you can get a script to source an arbitrary file, you
>>> can do
>>> pretty much anything.
>>
>> $ command /usr/bin/whoami
>> landley
>> $ command() { echo nope; }
>> $ command /usr/bin/whoami
>> nope
>>
>> What was the _benefit_ of allowing / in command names?
>
> I can't remember; it was 35 years ago. It's been that way since pre-1.0.
>
>>
>>>> $ x() { echo hello; }; D=x; $D
>>>> hello
>>>
>>> OK? Commands are parsed, then executed.
>>
>> To me, that seemed like analogous behavior working on the same line.
>
> Not at all. The line is parsed into three commands and executed:
>
> 1. The shell function is created by the function definition command.
>
> 2. The variable D is given a value by the simple command.
>
> 3. The variable D is expanded as part of word expansion and the result
> is executed as a simple command.
>
> I don't see how you get much a similarity here, since there's nothing
> changed by the parser like in alias expansion.
The implementation is different but what they do is the same. Modulo the
"wrapping source" thing I mentioned. But I've never seen anybody do
that, I'm just going "maybe that's why it exists".
(I've never seen anybody use "alias" as anything but function definition
with a more convenient syntax, and I've been reading shell scripts since
1992.)
>> Mostly the use of alias I've encountered seems to be things like alias
>> ls='ls -l' allowing additional arguments, although ls() { ls -l
>> "$@"; } seems like it could do it too.
>
> Most of what aliases do can be done with shell functions. The bash man
> page says as much. The really tricky stuff is where you change how the
> shell parses a command.
>
> The _unique_ feature is stuff like:
>>
>> $ alias ls='ls >'
>> $ ls
>> bash: syntax error near unexpected token `newline'
>
> Yes: you can change the shell syntax. You can also introduce syntax errors;
> the POSIX description of `alias' contains some examples.
You can alias "if". I just don't know why you'd WANT to.
>> It works for prefix assignments but not:
>>
>> $ alias blah='echo hello'
>> $ >file blah
>> $ cat blah
>> cat: blah: No such file or directory
>
> What are you expecting this to do? Where do you create a file named `blah'?
> Maybe you meant `cat file', which would display `hello'.
Ah, yes that's what I was expecting. And it did it. Which means it's not
_just_ special casing prefix assignments, it's also special casing
redirects. However:
$ alias blah='echo hello'
$ X=
$ $X blah
bash: blah: command not found
$ func() { echo hello; }
$ $X func
hello
Yeah yeah, blame posix...
>>> Anywhere the shell executes a string (the command_string argument to
>>> `sh -c', `eval', command substitution bodies), it parses the entire
>>> string
>>> as a compound_list and then executes that list.
>>
>> I just did fmemopen(buf, strlen(buf), "r") and fed it to the same line
>> reading loop as everything else. You're saying I should write extra
>> code to behave differently for the special case.
>
> You have agency here, Rob: you don't have to do anything you don't want to.
> I'm telling you what other shells -- including bash -- do and what POSIX
> says (most of it's unspecified).
I can see _what_ it's doing, I'm trying to figure out _why_. And am not
sure I'm any closer than when I started, but again I think this is posix
and history at fault here...
Sigh, this is preprocessor macros, isn't it? Except it wants to skip
prefix assignments and redirections and who knows what else that isn't
detected until the line gets parsed quite a while later.
See, the problem is:
$ a=b if true; then echo a=$a; fi
bash: syntax error near unexpected token `then'
I have to parse keywords to do line continuations and prompt for more
input, but I can't have prefix assignments before a keyword. But alias
can, and alias can RESOLVE to a keyword. It's INVENTING A LAYER, which
happens EARLIER than that yet does MORE than that, and I'm confused by
that. (I try not to have multiple instances of the same logic. This
almost requires it.)
Rob
More information about the Toybox
mailing list