如何使使用 $0 的脚本在 $PATH 上运行?

如何使使用 $0 的脚本在 $PATH 上运行?

我有一个脚本(~/.../gremlin),我为它创建了一个软链接:

ln -s ~/[...]/gremlin ~/sc/gremlin

~/sc/gremlin是在$PATH.
直接调用脚本就可以了。
通过链接调用它不会。
它使用dirname $0所以什么也得不到。

有没有一种方法可以使此设置工作而无需更改脚本并且无需创建另一个脚本来代替软链接?

$0 的用法如下:

case `uname` in
  CYGWIN*)
    CP=$( echo `dirname $0`/../lib/*.jar . | sed 's/ /;/g')
    ;;
  *)
    CP=$( echo `dirname $0`/../lib/*.jar . | sed 's/ /:/g')
esac

答案1

使用是否dirname $0有问题取决于如何它被使用了。如果没有更多细节,我们无法回答这个问题。

如果(a)的使用dirname $0有问题并且(b)您无法更改脚本,那么解决方案就是~/sc/gremlin用脚本替换软链接:

#!/bin/sh
exec ~/../gremlin "$@"

这样,~/../gremlin就会以正确的方式运行$0

使用exec意味着运行该脚本的进程~/../gremlin将取代正在运行的进程~/sc/gremlin。这比保留两个进程直到~/../gremlin完成更有效。

答案2

如果您想~/...从 派生目录$0,而不是~/sc从脚本内派生,您可以执行以下操作:

如果是zsh脚本:

#! /bin/zsh -
dir=$0:A:h

否则,假设您有一个readlink与 GNU 的命令类似的命令(某些系统有一个realpath您可以使用的命令):

#! /bin/sh -
dir=$(dirname -- "$(readlink -f -- "$0")")

readlink -f$0:A给你典范文件的路径,即解析所有路径组件中的所有符号链接后的绝对路径。

进而:

set -- "$dir"/../lib/*.jar .
case $(uname) in
  CYGWIN*) IFS=';';;
  *)       IFS=:;;
esac
CP="$*"

或者:

case $(uname) in
  CYGWIN*) sep=';';;
  *)       sep=:;;
esac
CP=$(printf "%s$sep" "$dir"/../lib/*.jar).

答案3

正如@john1024指出的,OP问题中的拼写错误可能是问题的重点:

ln -s ~/.../gremlin ~/sc/gremlin

虽然一些应用程序支持三点,但 Unix 文件系统却不支持。你的展开~(波形符),而不是ln,所以

    ln -s ~/../gremlin ~/sc/gremlin

将按预期扩展路径名。如果链接已存在,您可以使用 选项覆盖它-f。但是,如果目标是实际文件,该-f选项将使用符号链接默默地覆盖该文件。您可能想要使用-i至少告诉您已经存在某些内容的选项。

如果你想验证链接(证明它指向一个文件),选项-L很有ls用:

ls -lL ~/sc/gremlin

如果它不是文件,ls将(取决于实现)仅显示l类型(列表的第一个字符),带有权限位的问号),或其他一些表明它不指向真实文件的指示(在这种情况下,OSX 根本拒绝显示任何内容,尽管它会计算符号链接的总大小)。

进一步阅读:

相关内容