leo-arch / clifm

The shell-like, command line terminal file manager: simple, fast, extensible, and lightweight as hell.
https://github.com/leo-arch/clifm/wiki
GNU General Public License v2.0
1.33k stars 40 forks source link

xonsh shell doesn't fully work inside clifm #223

Closed tkossak closed 1 year ago

tkossak commented 1 year ago

Describe the bug Some xonsh shell commands don't work as expected inside clifm (see below).

To Reproduce Steps to reproduce the behavior:

  1. Start your standard bash shell and run: CLIFM_SHELL=/home/kossak/.local/bin/xonsh clifm (enter the corretct path, where you have xonsh installed)
  2. Then run and observe results:
    T8[1] 14:43 kossak:lman3 ~
    <0> $ a=1; echo @(a)
    1
    T8[1] 14:43 kossak:lman3 ~
    <0> $ echo @(a)
    Traceback (most recent call last):
    File "<string>", line 1, in <module>
    NameError: name 'a' is not defined
    T8[1] 14:43 kossak:lman3 ~
    <1> $ 

Expected behavior The same commands, run directly inside xonsh, work properly:

kossak@lman3 ~ $ a=1; echo @(a)
1
kossak@lman3 ~ $ echo @(a)
1
kossak@lman3 ~ $

Desktop (please complete the following information):

Additional context It seems like inside clifm, each command is run in separate process/memory space, so it doesn't remember variables from previous command.

leo-arch commented 1 year ago

Hi @tkossak. Thanks for reporting.

/etc/shells

You pointed out in Reddit that you had to add xonsh to /etc/shells. True. This check was added as a security layer: whatever value is passed to clifm via CLIFM_SHELL will be used to run shell commands, which might be a severe security risk for your file system, even if you committed a simple typing mistake. User input should always be validated in my programming book. Security is an important factor when it comes to software quality.

Variables

To the point. When running clifm you're not running a full-fledged shell, and this is by design (thus not a bug, but expected behavior). Shell commands are always executed via /path/to/shell -c CMD, that is, spawning a new shell instance, which is why previous commands (in your case a variable assignment) are not recognized; they were executed in a different process (a previous shell instance), and are thereby not visible to the current instance.

Why is this so? Though spawned by a shell, clifm does not run inside a previous/different shell (be it the spawning shell or whatever shell you specified via CLIFM_SHELL), but as a completely independent process (just as all non-builtin programs): it has no access to the memory space of the parent process. The same can be said regarding external/shell commands spawned from within clifm: each of them is an independent process; it is executed as a child process, which, after completion, returns to the parent (which is a different process). The memory space of the child is closed to the parent, and lost after the child finished.

If we wanted to make this different, clifm should have been developed as a shell builtin, that is, an extension/plugin/hack of a specific shell running within this very specific shell, and not as a separate, independent program.

TLDR: The only way (as far as I know) to access the memory space (in this case a variable assignment) of a process (here xonsh) is to be part of this process (say, a shell built-in). But clifm is not (and will never be) a shell builtin, just as shell commands executed from within clifm are not builtin into clifm, but external programs spawned by clifm (as children).

If you want a full shell, you can just spawn it: once in clifm, just enter ; (or :). A full shell will be launched. Do whatever needs to be done and quit. You'll be back into clifm. Or, as you already noted, use a one-liner (in this case all statements are executed by the same shell instance, which is why it works as expected).