1

From the zsh man page:

   -c     Take the first argument as a command to execute, rather than reading commands  from  a  script  or  standard
          input.   If  any  further  arguments are given, the first one is assigned to $0, rather than being used as a
          positional parameter.

   -i     Force shell to be interactive.  It is still possible to specify a script to execute.

   -s     Force shell to read commands from the standard input.  If the -s flag is not  present  and  an  argument  is
          given, the first argument is taken to be the pathname of a script to execute.

As far as I can tell, -i has no effect except when used with -c, to force zsh to source ~/.zshrc. Without -c, zsh appears to be interactive be default.

So:

  • Is there any difference between zsh and zsh -i?
  • Is there any difference between zsh -s and zsh -s -i?
  • Does -i do anything if -c is not present?
jth
  • 185
  • 1
    "It is still possible to specify a script to execute." – muru Nov 12 '19 at 00:19
  • 2
    zsh is only "interactive by default" if its stdin is a tty. You may want to run an interactive zsh when that is not the case. Just try echo val | zsh -i, then at the prompt enter read key; echo $key. Got it? –  Nov 12 '19 at 00:28
  • @mosvy Your example causes all known shells to print the warning: missing file argument. – schily Nov 12 '19 at 14:28
  • @schily which example? –  Nov 12 '19 at 14:48
  • Your example echo val | zsh -i – schily Nov 12 '19 at 14:54
  • @mosvy Thanks, that was a good example. – jth Nov 13 '19 at 08:01
  • 1
    @schily I got no such warning. – jth Nov 13 '19 at 08:01
  • @jth This is another reason why you cannot count zsh as a compliant shell. It is just too different from a real shell :-( – schily Nov 13 '19 at 10:26
  • 2
    When "all known shells" does not encompass the PD Korn, Debian Almquist, FreeBSD Almquist, '93 Korn, Heirloom Bourne, and Z shells, as is the case here (no such warning being emitted by any of them), then exactly how many shells one knows needs to be reëvaluated. – JdeBP Nov 14 '19 at 17:25

1 Answers1

4

The confusion here stems from a misunderstanding of what it means to be an interactive shell.

A Z shell is not interactive just because it happens to be running a prompt-read-execute loop. One can have a shell that is not interactive running a prompt-read-execute loop, reading its commands from a file or from a pipe. cat | zsh yields exactly that.

A Z shell is interactive if it has no command or script to run (i.e. it drops into that prompt-read-execute loop) and its standard input is a terminal. This is a decision made by the shell program at startup. Lots of things are affected by the decision and are consequences of it, such as what startup files to process and the initial values of the $- shell variable and interactive shell option. See the manual for all of the various things that occur "in an interactive shell".

There are some very slight variations among shells on the exact rule used. Some (such as the Z shell here) only test standard input to see whether it is a terminal. The Single UNIX Specification says that both standard input and standard error should be checked. zsh 2>&1 | cat yields an interactive Z shell, but ksh 2>&1 | cat will yield a non-interactive Korn shell.

The Z shell also decides whether it goes into a prompt-read-execute loop, runs a command, or executes a script. That is a separate decision, whose result feeds into the am-I-interactive decision. All three choices can be either interactive or non-interactive, with use of the -i option.

The -i option is simply a way of forcing a shell to think that it is interactive, even if its standard input is not a terminal, or it is given a command or a script to run. It is a bit tricky to demonstrate that with a pipeline such as cat | zsh -i because ZLE causes some odd behaviour (more on which at https://unix.stackexchange.com/a/434839/5132) that muddies the water a bit. But you can see it with ksh -i 2>&1 | cat which yields an interactive Korn shell.

The -s option is similarly present to override the other (what-to-do) decision, based when not overridden upon the presence of a first argument, to execute a script rather than run a prompt-read-execute loop. The -c option affects that other decision, too.

  • zsh wibble tries to execute a script, and is non-interactive because of that.
  • zsh -s wibble does not try to execute a script but forces the what-to-do decision to choose to enter a prompt-read-execute loop, and (when standard input is a terminal) is interactive.
  • zsh -c wibble is non-interactive, because it is running a command.

The combinations fall out logically from here.

  • zsh -si wibble is still (likewise) interactive, the override forcing the am-I-interactive decision the same way that it is being made anyway (because -s is forcing the choice of going into the prompt-read-execute loop).
  • zsh -i wibble tries to execute a script, but the script (if it looks) will think that it is an interactive shell and the interactive EOF behaviour will occur when the Z shell reaches the end of the script.
  • zsh -ci wibble still runs a command, but if that command looks (if it is a builtin or a shell function) it will think that it is an interactive shell.

… with two exceptions:

  • zsh -cs wibble runs a command, in a shell that thinks that it is non-interactive.
  • zsh -csi wibble likewise runs a command, in a shell that thinks that it is interactive.

-c effectively overrides -s. (Microsoft/IBM/JPSoftware command interpreters have a /K option that runs a command then drops into the prompt-read-execute loop. This would be the logical combination of -c and -s, but that was never done in the world of Unix shells.)

JdeBP
  • 68,745
  • "A Z shell is interactive if it has no command or script to run [...] and its standard input is a terminal" This seems incorrect. You can still specify a command or script to run with the -i option. – jth Nov 17 '19 at 19:44
  • It only seems incorrect on that ground, to someone who has not read beyond that sentence to the rest of the answer. – JdeBP Nov 18 '19 at 14:28
  • I'm not sure I agree. It seems to be an incorrect statement that does not add anything to the rest of the answer. – jth Nov 24 '19 at 03:08
  • Overall, I appreciate the detailed response. Unfortunately I do not have the time to verify all of the information in the answer, so I don't feel I can accept the answer as correct; but I will upvote it because it seems useful. – jth Nov 24 '19 at 03:10