0

I have asked a similar question but after revisiting some of my code I remembered from where the main issue stemmed from, here is the link to the old question.

How to implement built-in commands for my C shell with job control that change the state or environment of the shell process, such as chdir, setenv, exit... when they are specified to run in background by the user. Meaning these commands should not block terminal input when being executed as is the nature of background job processes.

One way to achieve executing built-in commands to not block the terminal input would be to fork() the shell process and execute them there, but this won't change/affect the main shell process instead the child would get its state changed which is not desired behaviour. Although this approach is applicable to non-state main process changing built-in commands.

My approach to this originally was to:

  1. have a separate routine prior to forking
  2. this routine would first dup() stdin, stdout, stderr streams
  3. now dup2() pipe streams
  4. then check if any of the built-in commands that change the state should get executed
  5. if yes, parse user redirections if any and built-in command/function is executed blocking the terminal input...!
  6. at the end no matter if the command was executed or not we restore the saved default (terminal) streams stdin, stdout, stderr with dup2() calls.
  7. function will have to return some kind of integer for status and in case it didn't run a negative integer which will be checked later to determine if we need to fork() to run the command or maybe a control integer/bool ptr as additional parameter to the function.

Resolving the redirections could be done prior and then reuse them in case we need to fork but this is not the concern, anyways this approach leads to terminal input being blocked, is there any workaround? Or is there just a better way of doing things like this?

Newb
  • 181
  • 1
  • 7
  • 2
    `cd path &` doesn't make any sense. I would expect that command to either spawn a new shell that executes the change of directory and exits (having no impact on the shell from which the command was executed), be a no-op as the shell notices that it is pointless and just does nothing, or maybe the shell would emit a warning and say "that command is pointless". If executing such a command in the background modified the current shell, I would be very surprised and consider it a bug. IOW, don't do anything. – William Pursell Jul 23 '23 at 15:54
  • "`fork()` the shell process and execute them there" yes, this is what normal shells do. Background processes are definition running in a subprocess; why would you ever want builtins in a subprocess to change anything in the parent shell? Each subprocess has its own env, cwd, etc. Just fork, set up the redirection, and exec the process(es) specified in the shell command. – erik258 Jul 23 '23 at 15:56
  • Interesting, but for example this line in fish shell creates a background job that still sleeps, echoes the text to screen but also the shell process changes the directory (assuming we are in /home/user dir): `sleep 5 | echo hello | cd .config&`. Are they cheating by actually blocking the terminal for that miniscule amount of time and running the rest in background? – Newb Jul 23 '23 at 16:02
  • 1
    what exactly does it mean in your mind to to pipe `echo`'s stdout into `cd`? – erik258 Jul 23 '23 at 16:04
  • How is that even relevant what does that mean in my mind, point is job gets created for this pipeline that is running in the background while my shell changes the working directory to home/someusername/.config... – Newb Jul 23 '23 at 16:08
  • 1
    Some shells allow the *last* command in a pipeline to execute in the current shell, rather than a sub shell. (Technically, *all* the jobs could run in the current shell, though it would require the shell to essentially duplicate the entire process-handling framework already provided by the OS. I'm not aware of any shell that bothers.) – chepner Jul 23 '23 at 16:11
  • @chepner fish shell seems to spin up a background job even if I put the 'cd' command in between the 2 commands such as: 'sleep 10 | cd .config | sleep 5&'. This still changes the directory and sleeps in background. – Newb Jul 23 '23 at 16:14
  • In fish, `echo hi | cd / | cat &` does seem to change the working directory of the main shell. In zsh or bash, it does not. It's an irrelevant point because `cd` cant be meaningfully used in a pipeline. – erik258 Jul 23 '23 at 16:19
  • 1
    Who knows what `fish` is doing then. (Well, I'm sure many people do, just not me :) ) But keep in mind that `fish` does not attempt to follow the POSIX standard where it thinks it has a better approach, so you can't really extrapolate how a `fish` pipeline works by comparing it to how POSIX pipelines work. (A *pipe* is an operating-system construct; a *pipeline* is a shell syntax that usually, but not necessarily, uses pipes to accomplish a shell-defined goal.) – chepner Jul 23 '23 at 16:23
  • This also works for `setenv` it sets/changes the env var of the main shell process even if it is ran in the pipeline that is specified to run in background, my question is how they deal with that, do they actually block the terminal for the amount of time i takes for the commandto run or is there other way. – Newb Jul 23 '23 at 16:25
  • 1
    (One-process-per-pipeline-component is a design decision made to simplify the shell; any shell can choose a more complicated implementation for pipelines if it is willing to do the state-tracking work. `fish` seems to identify built-in commands and attempt apply their effect to the current shell rather than simply forking-and-forgetting.) – chepner Jul 23 '23 at 16:26
  • @chepner sure fair point, just interested if there is a way to achieve background job changing the shell state and not blocking the terminal input – Newb Jul 23 '23 at 16:26
  • Yes, because in the end, *all* shell state is managed by, well, the shell. If you are writing the shell, you can do whatever you want; you just can't necessarily use separate *processes* to do it. – chepner Jul 23 '23 at 16:27
  • Since you seem to want to re-implement the C-Shell, I had a look at the [csh builtin commands](https://www.ibm.com/docs/en/aix/7.2?topic=shell-c-built-in-commands-list). For a start, which of them would make **sense** to be executed in the background? And even you think that i.e. `dirs` would make sense: You could always create a subshell to run the command, i.e. `dirs &` would then be equivalent to `( dirs ) &`. – user1934428 Jul 24 '23 at 06:33

0 Answers0