我怎样才能找到我在 bash 中隐藏的程序

我怎样才能找到我在 bash 中隐藏的程序

说我有PATH="home/bob/bin:/usr/bin"。我正在编写一个 bash 脚本/home/bob/bin/foo,它将进行一些修改,然后调用/usr/bin/foo.当然,我希望能够在具有不同路径结构的不同系统上使用此脚本。实际上,真正的 foo 可能位于许多不同的地方,所以我想从 PATH 中找到它。我的新 foo 脚本也在我的路径上,所以我不能只调用 foo,这将导致递归调用。

有没有一种简单的方法可以在 bash 脚本中执行此操作? (除了循环 PATH 的元素并手动进行搜索之外?)

答案1

您始终可以通过以下方式获取第二个路径foo

foo=$(type -Pa foo | tail -n+2 | head -n1)

(前提是文件路径不包含换行符)。

请注意,这可能是一个相对路径,在运行后将不再有效cd

然后你可以这样做:

hash -p "$foo" foo

所以 foo当您运行时被调用foo

答案2

我认为没有比枚举PATH.这并不难。

#!/bin/bash
set -f; IFS=:
for d in $PATH; do
  if [[ -f $d/foo && -x $d/foo && ! $d/foo -ef /home/bob/bin/foo ]]; then
    exec "$d/foo" "$@"
    exit 126
  fi
done
echo "$0: foo (real) not found in PATH"
exit 127

我假设 PATH 中没有空条目。空的 PATH 条目是邪恶的,请.显式编写(或者最好根本不包含它)。

如果您只foo从命令行运行而不是从其他程序运行,请将其设为函数而不是脚本。从函数中,运行command foo以隐藏该函数。

答案3

如果 foo 很重要,那么应该在脚本中配置它。我认为这是一个很好的做法,因为您可以将其明确地与脚本挂钩。我不喜欢间接、隐式或隐藏的东西……如果要部署脚本,它们应该非常简单。

否则,如果你坚持要找到它,那么可以通过以下方式找到它:

whereisfoo="$(which foo)"

如果这还不够,那么我担心您所做的事情可能太复杂了。

答案4

我认为这是一种比吉尔斯的答案稍微不那么混乱的方法(尽管我承认这是一个主观判断)。

#!/bin/sh
this_dir=$(dirname "$0") # 或者,将其硬编码为 this_dir=$HOME/bin
redacted_PATH=$(echo ":${PATH}:" | sed -e "s:\:$this_dir\::\::" -e "s/^://" -e 's/:$// ')
if obliged_prog=$(PATH=$redacted_PATH which foo)
然后
            ⋮ # 运行 /usr/bin/foo 之前需要做的事情
        “$(obscured_prog)”论点          # 可能是“$@”,但也可能不是。
            ⋮ # 运行 /usr/bin/foo 后需要做的事情
别的
        echo "$0: foo (real) 在 PATH 中找不到。"
            ⋮ # 任何你想做的代码。

这将构造redacted_PATH$PATH 减去$HOME/bin此私有副本所在的目录foo。  echo ":${PATH}:"在 的开头和结尾添加冒号$PATH,因此它的每个组成部分的前面和后面都会有一个冒号 - 即使是第一个和最后一个。搜索sed次数为

: $this_dir :

(为“清晰”添加空格)并将其替换为

:

即,它$this_dir从 中删除":${PATH}:"。然后它删除开头和结尾的冒号。

然后我们暂时设置PATH$redacted_PATH 并搜索foo使用which。如果成功,我们将获得它的完整路径(例如,/bin/foo/usr/bin/foo),我们用它来运行 的真实(公共/共享/系统)副本foo。由于我们PATH只是暂时更改, /bin/foo因此可以访问用户的环境$PATH,因此,如果/bin/foo运行brillig,它可以找到$HOME/bin/brillig (如果存在)。

$HOME/bin如果多次出现就会出现问题$PATH,但这并不难解决。

相关内容