Search code examples
bashshellevalcshtcsh

find out which shell tcsh/bash/etc. is running when eval is used on script


I have a shell script that exports variables to be used in tool setup for a multiuser environment. As different projects (history of 100+ projects) use different setups, my script sets variables for different shell kinds.

Example:

#!/bin/sh

#some XY_VAR setting happening here

case "$1" in

'-c')
    echo "setenv XY $XY_VAR;"
    ;;

'-b')
    echo "export XY=$XY_VAR;"
    ;;

esac

when used in a project's script, it is evaled like this

eval `set_my_vars -c` #when using (t)c-shell
eval `set_my_vars -b` #when using bash

My question is can I make the script detect the shell it is evaled from and input that to the case statement?

ps -hp $$

doesn't work when the script is evaled, this was my first idea (with awk of course). I have found multiple ways where people wanted to detect in which shell they are running in, but all I have found fail when using eval.

Can anybody help? Maybe I am just to stupid to find the solution on my own.

Thanks and best regards rws


Solution

  • $$ refers to the current process; which in your case is the shell that gets spawned by the backticks. So what you need to do is get the pid of the process that spawned the subshell: the parent process. An example might be:

    comm=$(ps -ho comm $(ps -ho ppid $$))
    echo "echo \"$comm\""
    

    This first runs ps -ho ppid $$ to get the parent pid, and then runs another ps -ho comm to get the command name from the parent pid.

    And then using:

    eval `./sourceme`
    

    Will print the expected value:

    [~]% eval `./sourceme`
    zsh
    
    $ sh
    $ eval `./sourceme`
    sh
    
    $ csh
    % eval `./sourceme`
    csh
    
    % bash
    [~]$ eval `./sourceme`
    bash
    
    [~]$ osh
    osh$ eval `./sourceme`
    osh
    

    The fish shell requires slightly different syntax though:

    osh$ fish
    Welcome to fish, the friendly interactive shell
    Type help for instructions on how to use fish
    martin@e585 ~> eval `./sourceme`
    fish: Unknown command: `./sourceme`
    martin@e585 ~> eval (./sourceme)
    fish
    

    I only tested this on Linux; since your ps example gives an error on my system ("unsupported SysV option") it looks like you're probably not using Linux(or a Linux with a different ps?) so you may need to frob with the commands a bit, but this should hopefully point you in the right direction.

    Also, if you run this through another script you may need to get the parent of the parent.


    If you are using Linux then another option would be using the /proc filesystem:

    ppid=$(cat "/proc/$$/status" | grep ^PPid: | awk '{print $2}')
    comm=$(cat "/proc/$ppid/status" | grep ^Name: | awk '{print $2}')
    echo "echo \"$comm\""
    

    But this will only work on Linux. ps is a bit messy and difficult to use portable, but it's certainly more portable than Linux's procfs.