Search code examples
shelltcsh

TCSH script full path


In bash shell I can get a full path of a script even if the script is called by source, link, ./..., etc. These magic bash lines:

 #Next lines just find the path of the file.
 #Works for all scenarios including:
 #when called via multiple soft links.
 #when script called by command "source" aka . (dot) operator.
 #when arg $0 is modified from caller.
 #"./script" "/full/path/to/script" "/some/path/../../another/path/script" "./some/folder/script"
 #SCRIPT_PATH is given in full path, no matter how it is called.
 #Just make sure you locate this at start of the script.
 SCRIPT_PATH="${BASH_SOURCE[0]}";
 if [ -h "${SCRIPT_PATH}" ]; then
   while [ -h "${SCRIPT_PATH}" ]; do SCRIPT_PATH=`readlink "${SCRIPT_PATH}"`; done
 fi
 pushd `dirname ${SCRIPT_PATH}` > /dev/null
 SCRIPT_PATH=`pwd`;
 popd  > /dev/null

How can you get the script path under the same conditions in TCSH shell? What are these 'magic lines'?

P.S. It is not a duplicate of this and similar questions. I'm aware of $0.


Solution

  • I don't use tcsh and do not claim guru status in it, or any other variant of C shell. I also firmly believe that Csh Programming Considered Harmful contains much truth; I use Korn shell or Bash.

    However, I can look at manual pages, and I used the man page for tcsh (tcsh 6.17.00 (Astron) 2009-07-10 (x86_64-apple-darwin) on MacOS 10.7.1 Lion).

    As far as I can see, there is no analogue to the variable ${BASH_SOURCE[0]} in tcsh, so the starting point for the script fragment in the question is missing. Thus, unless I missed something in the manual, or the manual is incomplete, there is no easy way to achieve the same result in tcsh.

    The original script fragment has some problems, too, as noted in comments. If the script is invoked with current directory /home/user1 using the name /usr/local/bin/xyz, but that is a symlink containing ../libexec/someprog/executable, then the code snippet is going to produce the wrong answer (it will likely say /home/user1 because the directory /home/libexec/someprog does not exist).

    Also, wrapping the while loop in an if is pointless; the code should simply contain the while loop.

    SCRIPT_PATH="${BASH_SOURCE[0]}";
    while [ -h "${SCRIPT_PATH}" ]; do SCRIPT_PATH=`readlink "${SCRIPT_PATH}"`; done
    

    You should look up the realpath() function; there may even be a command that uses it already available. It certainly is not hard to write a command that does use realpath(). However, as far as I can tell, none of the standard Linux commands wrap the realpath() function, which is a pity as it would help you solve the problem. (The stat and readlink commands do not help, specifically.)

    At its simplest, you could write a program that uses realpath() like this:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <errno.h>
    
    int main(int argc, char **argv)
    {
        int rc = EXIT_SUCCESS;
        for (int i = 1; i < argc; i++)
        {
            char *rn = realpath(argv[i], 0);
            if (rn != 0)
            {
                printf("%s\n", rn);
                free(rn);
            }
            else
            {
                fprintf(stderr, "%s: failed to resolve the path for %s\n%d: %s\n",
                        argv[0], argv[i], errno, strerror(errno));
                rc = EXIT_FAILURE;
            }
        }
        return(rc);
    }
    

    If that program is called realpath, then the Bash script fragment reduces to:

    SCRIPT_PATH=$(realpath ${BASH_SOURCE[0]})