3

The short question is: I need to launch an interactive bash in a certain directory, and I can craft the command that launches bash, but I can't modify the system. At the moment, the command that best fits my needs is

bash -c 'cd some-directory; bash'

That is, I am calling bash, to use cd within bash, and then creating a child instance of bash within that to handle my interactive bashing.

I'm aware this isn't the most egregious bash usage in the world, but it feels weird to me. Is there an easier way to do what I'm looking for?


Just for unnecessary context:

This is a part of my tooling that deals with launching a shell within a docker instance (using docker exec) via docker-compose. I could find myself inside any of about 15 docker containers that represent projects - some of them have a "default" directory that I would want to be in, and others wouldn't. The tooling is meant to bridge the gap, and give me a smoother experience switching from one project to another.

Some things that I have tried that I thought might work but didn't include:

  • PWD='~/some/directory' bash - this just gets ignored
  • bash -i -c "cd ~/some/directory - it creates a shell marked as interactive, but doesn't wait for any input like a normal interactive shell.
  • echo "cd ~/some/directory" | bash --rcfile -" was worth a try

Some things that I know would work but don't in my case:

  • Change the working directory then launch my command: I'm in docker, so my host's working directory doesn't matter. I'm intrigued as to how bash knows what the current working directory of a parent shell is.
  • docker-compose does have a -w that will take an absolute path, doesn't know how to handle tildes.
  • cd ~/some/directory ; bash - docker-compose requires an actual executable
  • Put it in an rcfile in the container, or create a "launcher" script: Kinda works, but I want to be able to configure it from the outside, and don't want to edit each of the containers

So is there a way to set the initial directory that I've overlooked, or is this just the way it's done? I know that shell integrations such as Gnome's "Open folder in terminal" must be doing something to tell bash what folder to start in, I can't work out what magic it is using though.

  • 1
    Every Unix process -- bash or other -- is created with its working directory initially inherited from the parent -- which need not be a shell. Any parent including dockerd or whatever GNOME process handles this can set up I/O redirections and/or temporarily set the working directory when creating a child. Any subsequent change in the parent doesn't affect the child, and any subsequent change in the child doesn't affect the parent. – dave_thompson_085 Jan 05 '24 at 02:06
  • @dave_thompson_085 I see - I suspect that's done via some kernel call (or, in the case of docker, a call to whatever shim pretends to be the kernel) which would explain why bash doesn't feel the need to provide an option? Useful info, thanks! – user208769 Jan 09 '24 at 09:40
  • Add: I was reminded by another Q that if you have GNU env (likely if you have bash) it has an option to change the working dir for a program it execs: env -C /wanted/dir bash – dave_thompson_085 Jan 26 '24 at 04:18

1 Answers1

5

Using "exec" to replace the current shell is a slight improvement, i.e.

    bash -c 'cd somedirectory && exec bash -i'

You could put something like

if [ -n "$STARTDIR" ] ; then
    cd "$STARTDIR"
    unset STARTDIR
fi

in your ~/.bashrc, and then use

    STARTDIR="/some/directory" bash

You could put this in a different file and use bash --rcfile ~/changedir

Programs which open folder in terminal will either be asking "terminal" to do the cd, or will be running a sequence of system calls like fork, chdir /some/directory, exec terminal rather than asking the shell to do something.

icarus
  • 17,920
  • Good call - I hadn't thought of exec. Unfortunately as mentioned the rcfile isn't a solution for my use case, as that would be modifying the system that bash is running in - but that's quite a nice way of doing it if someone isn't so restricted! – user208769 Jan 04 '24 at 16:56
  • 1
    @user208769+ bash automatically execs (i.e. replaces itself with) the last (or only) command in -c; check pstree or similar to confirm. – dave_thompson_085 Jan 05 '24 at 02:06
  • 1
    @user208769 Am I correct in understanding that you set up a number of containers using docker compose and then you connect to some of them using docker exec -it name bash? I am not sure exactly how to interpret "This is a part of my tooling that deals with launching a shell within a docker instance (using docker exec) via docker-compose. " – icarus Jan 05 '24 at 03:07
  • @dave_thompson_085 Well there's something I didn't know! Yes, that seems true, useful information, thanks! – user208769 Jan 09 '24 at 09:21
  • @icarus Kinda. The docker containers are used for development work, often I need to run a shell inside the container, and for that I use docker-compose exec service_name /bin/bash (via what is essentially some funky aliases, that's what I'm referring to as "my tooling") - but yes, docker exec -it namespace_service_name_1 some_command is functionally equivalent, including the restriction that the command has to be something that Docker can resolve to an executable file in the $PATH – user208769 Jan 09 '24 at 09:29
  • 1
    @dave_thompson_085 it's only trues if there a single command (without any pipes, redirections or control operators). In other cases, it will fork even for the last command. – aviro Jan 09 '24 at 16:50
  • The point is that docker exec -it -w directory service_name /bin/bash might be the answer you are looking for, once you mix it into your alias soup. – icarus Jan 09 '24 at 20:44