57

i'd like to start zsh similar to

zsh -c 'my_prog option1 option2'

but instead of exiting after running that command, leaving me at the propt of the invoked zsh (not wherever it is being called from). one particular use-case for this is in screenrc files, you could do something like:

screen -t my_prog 0 zsh -c 'my_prog opt1 opt2'

and after running that command you're left with a shell there instead of it closing.

5 Answers 5

36

Not that I would advise doing this.

(sirius)~: zsh -c 'print hello; zsh -i'
hello
(sirius)~: echo $SHLVL
2

There are other tricks you can play with screen and using the $STY variable.

If you want something run from zsh with individual screens, you can check the $STY variable within your .zshrc or .zlogin. It is in the format <PID>.<TTY>.<HOSTNAME>.

if [[ -n $STY ]] then
  if [[ -f ~/.zsh-$STY[(ws:.:)2] ]] then
    . ~/.zsh-$STY[(ws:.:)2]
  fi
fi

If in screen, and if ~/.zsh-<TTY> (from the $STY variable) exists, source that, then continue on your merry way. You can also set an environment variable before calling the interactive shell.

> FOO=bar zsh -i
> env | grep FOO
FOO=bar

> RUNTHISCOMMAND=/path/to/script zsh -i
.zshrc:
if [[ -n $RUNTHISCOMMAND ]] then
   $RUNTHISCOMMAND
fi

Add those checks into your .zshrc/.zlogin.

2
  • 2
    kudos for teaching me about SHLVL Jan 6, 2010 at 5:00
  • i was hoping to avoid the nested shell, but oh well. Jan 6, 2010 at 9:24
17

I found a solution that works without an extra shell here. Add:

if [[ $1 == eval ]]
then
    "$@"
set --
fi

to .zshrc, then call zsh with

zsh -is eval 'your shell command here'

Really great for starting up lots of shells at once.

1
  • It should be noted that this is best placed at the very end of the .zshrc. I had some plugins that had automatically placed their setup code in .zshrc after the eval hook. Typically I'm running infinite processes like npm start in the eval hook. When killing them with CTRL + C I was always surprised that some zsh plugins had stopped working. Of course the reason is that the .zshrc only got evaluated up to the $@.
    – bluenote10
    Mar 6, 2021 at 9:00
11

What about appending ; exec zsh to the command? That way there's only one shell left at the end.

2
  • 8
    You actually don't need the exec if you ; zsh -i, it does that for you already. Jan 6, 2010 at 17:47
  • The weird thing when I source my zsh after the change my terminal goes into like an infinite loop however if I use ; exec zsh {command that I want to run} ;checked to see if there was any broken code further up or any potential code that would cause this to happen but everything above the evaluation was 100s :/
    – 0xeλ7
    Jun 25, 2022 at 23:23
8

I have eval "$RUN" at the end of my .zshrc. I can now run commands without the extra shell, with:

RUN='my_prog opt1 opt2' zsh
2
  • This seems a weird kludge - but it works so well!
    – zaTricky
    Feb 28, 2017 at 5:32
  • This can get problematic if your shell can spawn other shells. So eg. if I use RUN=nvim zsh and then inside the spawned vim I open the embedded terminal suddenly I have vim inside vim.
    – lorefnon
    May 3, 2022 at 17:14
0

I have this in my .zshrc:

alias uce='USE_CUSTOM_ENV=1 zsh'
if [[ "${USE_CUSTOM_ENV}" == "1" ]]; then
        alias a='stuff I need in this context'
        alias x='exit'
        ...

        PROMPT="${PROMPT}%{$terminfo[bold]$fg[red]%}[CUSTOM_ENV] %{$reset_color%}"
        my_prog option1 option2
fi

Upon invoking uce on the command line a new interactive subshell is invoked where my_prog is executed. This approach has the advantage of giving me a custom environment (with aliases, functions, envvars, etc.) for the specific context.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .