tcsh: How to find out if shell was started with -c flag? - shell

tcsh, as with other shells, accepts the -c flag to execute a set of commands from the command-line args (instead of from a script) upon running the shell, such as:
tcsh -c 'mkdir /tmp/some-dir; tar -C /tmp/some-dir -xvf a-tarball.tar'
Is there a way to query the interpreter's state to detect that -c flag? Remember that this flag is passed on to tcsh, NOT to the commands that were fed to the interpreter via -c.
Background: I found a few days ago that tcsh -c "COMMANDS..." still invokes additional rc files (in particular, .cshrc) upon starting up. I have some commands in .cshrc that I do NOT want run when tcsh -c is invoked (as opposed to interactive tcsh).

Related

how to escape `&>` in Makefile?

I use a :
python notation.py &> notation.log
Command line.
I try to run it from a Makefile with no success:
$ cat Makefile
run:
python notation.py &> notation.log
$ make
$ ls -la notation.log
-rw-rw-r-- 1 me me 0 juin 8 08:15 notation.log
$
The problem is not escaping. The problem is that is not legal syntax in the shell.
Make always invokes (by default) /bin/sh as the shell to run its recipes. /bin/sh is a POSIX-standard shell. The token &> is not valid POSIX shell syntax. When you are logged in at a shell prompt you are not running the shell /bin/sh, you are running a more powerful shell, probably bash (on Linux) or possibly zsh (on newer MacOS systems). These shells have extra features that are not defined in POSIX and not available in a POSIX-compliant version of /bin/sh.
You have two choices: either use correct POSIX syntax in your recipe:
run:
python notation.py > notation.log 2>&1
Or else tell make to use your shell when it runs recipes:
SHELL := /bin/bash
run:
python notation.py &> notation.log
(of course this assumes that all systems you want to run your makefile in, actually have /bin/bash installed)

Source a tcsh script from bash

I'm trying to execute a tcsh script in a bash environment. My regular environment is tcsh so the following command works for me:
source /usr/scripts/my_setup -t abs
But I need to execute this command from some third party software which runs the commands on bash shell. This script should set an environment variable $TMP.
I already tried all the suggested solutions from the previous threads and they all do not work.
What I tried:
tcsh -c "source /usr/scripts/my_setup -t abs ; exec bash"
tcsh -c "source /usr/scripts/my_setup -t abs ; bash"
The following steps:
echo "tcsh -c 'source /usr/scripts/my_setup -t abs'" > setup
chmod a+x setup
source setup
They all fail. And I understand why (everytime I use tcsh it opens a new shell). But I can't seem to understand how to source a tcsh script from bash.

Which shell does Perl 6's shell() use?

Perl 6's shell sends commands to the "shell" but doesn't say what that is. I consistently get bash on my machine but I don't know if I can rely on that.
$ perl6 -e 'shell( Q/echo $SHELL/ )'
/bin/bash
$ csh
% perl6 -e 'shell( Q/echo $SHELL/ )'
/bin/bash
% zsh
$ perl6 -e 'shell( Q/echo $SHELL/ )'
/bin/bash
That's easy enough on Unix when it's documented, but what about cmd.exe or PowerShell on Windows (or bash if it's installed)? I figure it's the cmd.exe but a documented answer would be nice.
Looking at the source, rakudo just calls /bin/sh -c on non-windows and uses %*ENV<ComSpec> /c on windows.
dash (installed as /bin/sh on many systems), doesn't set $SHELL, nor should it. $SHELL isn't the name of the parent process; it's the name of the shell that should be used when an interactive shell is desired.
To get the name of the parent process, you could use the following on some systems:
echo "$0"
or
# Command line
perl -e'$ppid=getppid(); #ARGV="/proc/$ppid/cmdline"; CORE::say "".<>'
or
# Program file
perl -e'$ppid=getppid(); CORE::say readlink("/proc/$ppid/exe")'
You'll find you'll get /bin/sh in all cases.

Running command as login shell without starting a new shell?

I'm trying to see what the output of a command would be if I were in a login shell, without having to go into a login shell. I've tried several variations of
zsh --login -c "alias"
But none of my aliases get shown; are --login and -c incompatible?
To test the difference between zsh --login -c "alias" and a normal login shell, you can/should add the -x option to see what the shell is up to.
When I run zsh -x --login -c "alias", then it processes /etc/zprofile.
When I run zsh -x --login, then it processes /etc/zprofile and /etc/zshrc.
I don't normally use zsh, so I don't have any personalized profile or start up file for it, but it seems plausible that it might look for (but, in my case, not find) ~/.zprofile and ~/.zshrc too.
I created trivial versions of those files:
$ echo "echo in .zprofile" > ~/.zprofile
$ echo "echo in .zshrc" > ~/.zshrc
and sure enough, they're processed. Further, the -c command with --login processed the .zprofile but did not process the .zshrc file.
Thus, using -c "alias" after the --login suppresses the processing of /etc/zshrc and ~/.zshrc. If you want those executed even so, you need to use something like:
zsh --login -c "[ -f /etc/zshrc ] && . /etc/zshrc; [ -f ~/.zshrc ] && . ~/.zshrc; alias"
Using -x to debug login processing is often informative.
It's nice that modern shells provide a command line option to induce login processing. I still have a program (which I don't use any more) that runs a login shell the old-fashioned way, by adding a - before the shell name in argv[0]. Thus, running -ksh would trigger login processing; the login program would run the login shell with the - at the start.

Difference between pgrep in sh and bash

Here is a test:
$ bash -c "pgrep -f novalidname"
$ sh -c "pgrep -f novalidname"
11202
Why is pgrep giving output when run from sh? (As far as I can see, there are no processes on my computer that is named novalidname)
It's probably a timing issue and pgrep finds itself, as you're issuing it with -f and novalidname is present in the command line. Try with -l to confirm.
The actual explanation:
Regardless of flags, pgrep never returns its own PID.
If you execute bash -c with a simple command, then bash will exec the command rather than creating a redundant subshell to execute it in. Consequently, bash -c "pgrep -f blah" will replace the bash process with a pgrep process. If that pgrep process is the only process whose command line includes blah, then pgrep will not display any PIDs (as per 1).
dash does not perform the above optimization. (zsh and ksh do.) So if on your system, sh is implemented with dash, then sh -c "pgrep -f blah" will result in two processes being executed -- the sh process and the pgrep child -- both of which contain blah in their command lines. pgrep will not report itself, but it will report its parent.
That's one thing (finding itself because of delay) see also:
$ ps ax | grep novalidname
Here it usually shows as well. (on Ubuntu does for me. (under bash)
The other thing is what is /bin/sh bound to?
On most Linux distros /bin/sh is a soft link to default shell which is usually actually bash, but can be any other shell.
The time difference that causes grep/pgrep to show itself may be introduced by finding a soft link location (hm, odd) or some other shell is bound to /bin/sh which executes slightly different than bash, thus causing the delay needed for process to show in pgrep.
Also, bash will firstly try to source ~/.bashrc and load its history, while /bin/sh will do what will do. In .bashrc can be pgrep defined as alias in another way which may also affect the difference.
To see where /bin/sh points to do:
$ readlink -e /bin/sh
Or just run sh to see what will show up. :D

Resources