2

What does the following do exactly?

newProg=`expr "${newProg}" : ".* -> \(.*\)$"`   
if expr "x${newProg}" : 'x/' >/dev/null; then    
   prog="${newProg}"     
else    
    progdir=`dirname "${prog}"`   
    prog="${progdir}/${newProg}"    
fi   
Michael Homer
  • 74,824
  • 17
  • 212
  • 233
Jim
  • 9,750
  • 15
  • 57
  • 84

1 Answers1

4

The first line uses expr to:

The greedy matching semantics are such that this always captures and outputs the last such match, so there is never a -> in the output.

This would, for example, parse the output of ls -l on a symlink to find the target (given well-behaved filenames, etc, usual caveats).

The second line uses expr again to check whether the new value of newProg begins with a /, i.e., it represents an absolute path.

In the case where it does, prog is just set to that value. Otherwise, prog is set to a computed relative path using dirname on $prog, a variable not defined in this snippet. The effect will presumably be to construct a path relative to that original location.


If you are only targeting a more capable shell or environment than pure POSIX, there is likely to be a more reliable way of doing this than expr. readlink is a very commonly-available command also, which would save on parsing ls.

Michael Homer
  • 74,824
  • 17
  • 212
  • 233
  • +1. the only thing i'd add to that is that parsing the output of `ls` is **always** a bad idea, and using `expr` to parse ls is also inefficient and leads to ugly, difficult to read shell code....especially when every version of `test` aka `[` in existence has `-h` and/or `-L` options to test whether a file is a symlink or not. – cas Jul 16 '17 at 04:14
  • A GNU readlink-based alternative to this could look like `[ -L "$newProg" ] && prog="$(readlink -m "$newprog")"` (1 line rather than 7). And if $progdir is required (i.e. not just a temporary throwaway variable), append `&& progdir="$(dirname "$prog")"` to that line. BTW, the `[ -L ... ] &&` test isn't required because running `readlink -m` on a non-symlink filename just returns that filename (with the full path). – cas Jul 16 '17 at 04:17