1

My current setup starts with a function that is ostensibly in .bashrc (.bash_it/custom/funcs.bash to be precise)

#!/usr/bin/env bash
function proset() {
  . proset-core "$@";
}

proset-core does some decrypting of secrets and exports those secrets to the session, hence the need for the . instead of just running it as a script/subshell.

If something goes wrong in proset-core, I use return instead of exit since I don't want the SSH connection to be dropped.

if [ "${APP_JSON}" = "null" ] ; then
  echo -e "\n${redtext}App named $NAME not found in ${APPCONF}. Aborting.${resettext}\n";
  return;
fi

This makes sense in the context of the exported proset function, but precludes usage as a script since return isn't valid except from within a function.

Is there a way to detect how it's being called and return one or the other as appropriate?

notbrain
  • 3,366
  • 2
  • 32
  • 42
  • You could investigate [SHLVL](https://www.lifewire.com/why-would-you-use-shivi-variable-2196747) variable. – LMC Mar 08 '18 at 00:34
  • `return || exit` -- if one doesn't work, the other will. – Charles Duffy Mar 09 '18 at 21:05
  • 1
    BTW, `function funcname() { ... }` is bad form -- old-ksh format is `function funcname {`, POSIX-standard format is `funcname() {`; the idiom that uses both the `function` prefix *and* the `()` is compatible with neither. See http://wiki.bash-hackers.org/scripting/obsolete -- if you want to pick one or the other practice to learn, the POSIX-y one is probably better; means you aren't in habits that will make your code break when run in `/bin/sh`, and won't confuse people used to ancient ksh where `function` makes variables local-by-default (which it doesn't do in bash). – Charles Duffy Mar 09 '18 at 21:06

3 Answers3

2

Just try to return, and exit if it fails.

_retval=$?
return 2>/dev/null || exit "$_retval"

The only case where your code will still be continuing after the return was invoked at top-level (outside of a function) is if you were executed rather than sourced, and should that happen, exiting is the Right Thing.

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
  • BTW you can also declare exit as a function while you source a file to prevent exiting... I use that sometime in shell test scripts to load inline functions then capture the results. – Thomas Guyot-Sionnest Sep 16 '22 at 02:51
1

Make the builtin variable $SHLVL part of $@ args as the last arg. Then at test point:

if [ "${@: -1}" -lt $SHLVL ]; then
    # SHLVL arg is less than current SHLVL
    # we are in a subshell
    exit
else
    return
fi 
notbrain
  • 3,366
  • 2
  • 32
  • 42
LMC
  • 10,453
  • 2
  • 27
  • 52
  • Doesn't this require that any other use of proset-core would need to pass $SHLVL all the time? And when "$@" is empty, also detect the number of args and adjust accordingly. Is there a way to check without changing the arg list to proset-core? – notbrain Mar 09 '18 at 20:56
0

Ended up using

calledBy="$(ps -o comm= $PPID)";
if [ "x${calledBy}" = "xsshd" ]; then
  return 1;
else
  exit 1;
fi

since it didn't require passing anything extra. Anything that might cause this to be problematic please comment. Not too worried about being bash-specific or portable.

Credit: get the name of the caller script in bash script

notbrain
  • 3,366
  • 2
  • 32
  • 42
  • The `x$foo` is unnecessary here, btw -- `[ "$calledBy" = sshd ]` is perfectly safe. The only case where that idiom is needed in modern (post-1990) shells is when you're using `-a` or `-o` to combine multiple tests in one instance, and POSIX has that syntax marked as obsolescent (search for `OB` markers in http://pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html). – Charles Duffy Mar 09 '18 at 21:55
  • ...that said, this seems like a lot of overhead for a not-particularly-reliable test (whether you were sourced and whether you're a direct subprocess of sshd are really two different questions!). – Charles Duffy Mar 09 '18 at 21:58
  • ...to provide some concrete examples, you might be `source`d into a shell that is a child of `gnome-terminal` or `/bin/login` rather than sshd, or someone might run `ssh hostname 'exec /path/to/your-script'`, in which case you'll be a direct child of sshd, but executed and not sourced. – Charles Duffy Mar 09 '18 at 22:01