Quantcast
Channel: How to obtain the absolute path of a file via Shell (BASH/ZSH/SH)? - Stack Overflow
Viewing all articles
Browse latest Browse all 46

Answer by Mecki for bash/fish command to print absolute path to a file

$
0
0

The answer of Alexander Klimetschek is okay if your script may insist on a bash or bash compatible shell being present. It won't work with a shell that is only POSIX conforming.

Also when the final file is a file in root, the output will be //file, which is not technically incorrect (double / are treated like single ones by the system) but it looks strange.

Here's a version that works with every POSIX conforming shell, all external tools it is using are also required by the POSIX standard, and it explicitly handles the root-file case:

#!/bin/shabspath ( ) {    if [ ! -e "$1" ]; then        return 1    fi    file=""    dir="$1"    if [ ! -d "$dir" ]; then        file=$(basename "$dir")        dir=$(dirname "$dir")    fi    case "$dir" in        /*) ;;        *) dir="$(pwd)/$dir"    esac    result=$(cd "$dir" && pwd)    if [ -n "$file" ]; then        case "$result" in            */) ;;             *) result="$result/"        esac        result="$result$file"    fi    printf "%s\n" "$result"}abspath "$1"

Put that into a file and make it executable and you have a CLI tool to quickly get the absolute path of files and directories. Or just copy the function and use it in your own POSIX conforming scripts. It turns relative paths into absolute ones and returns absolute ones as is.

Interesting modifications:

If you replace the line result=$(cd "$dir" && pwd) with result=$(cd "$dir" && pwd -P), then all symbolic links in the path to the final file are resolved as well.

If you are not interested into the first modification, you can optimize the absolute case by returning early:

abspath ( ) {    if [ ! -e "$1" ]; then        return 1    fi    case "$1" in        /*)            printf "%s\n" "$1"            return 0    esac    file=""    dir="$1"    if [ ! -d "$dir" ]; then        file=$(basename "$dir")        dir=$(dirname "$dir")    fi    result=$(cd "$dir" && pwd)    if [ -n "$file" ]; then        case "$result" in            */) ;;            *) result="$result/"        esac        result="$result$file"    fi    printf "%s\n" "$result"}

And since the question will arise: Why printf instead of echo?

echo is intended primary to print messages for the user to stdout. A lot of echo behavior that script writers rely on is in fact unspecified. Not even the famous -n is standardized or the usage of \t for tab. The POSIX standard says:

A string to be written to standard output. If the first operand is -n, or if any of the operands contain a character, the results are implementation-defined.
- https://pubs.opengroup.org/onlinepubs/9699919799/utilities/echo.html

Thus whenever you want to write something to stdout and it's not for the purpose of printing a message to the user, the recommendation is to use printf as the behavior of printf is exactly defined. My function uses stdout to pass out a result, this is not a message for the user and thus only using printf guarantees perfect portability.


Viewing all articles
Browse latest Browse all 46

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>