我和其他脚本使用了一个可执行文件/usr/bin/foo
,但它的行为有点不正常,因此我制作了一个具有相同文件名的 Bash 包装器,并在/usr/local/bin/foo
其中修复了其错误行为。我PATH
的是/usr/local/bin:/usr/bin
。在包装器脚本中,我必须通过绝对路径运行原始可执行文件,以免进入无限循环:
$ cat /usr/local/bin/foo
#/bin/zsh
/usr/bin/foo | grep -v "^INFO" # reduce output
是否有任何(也许是 Zsh 或 Bash 特定的)简单的方法来执行 next foo
in PATH
,即在执行current 的目录之后的目录foo
中,这样我就不必使用原始可执行文件的绝对路径?PATH
foo
我可以为它创建一个函数/etc/zshenv
,这没什么大不了的。我只是想知道是否有什么标准。我不想使用别名或修复原始可执行文件。
编辑1:= $ cat /usr/local/bin/foo #/bin/zsh path=(${path/#%$0:A:h}) foo | grep -v "^INFO" # 减少输出
这应该清空(但保留) PATH ( ) 中与当前可执行文件 ( ) 的绝对 ( ) 目录 ( )${path/...}
完全匹配 ( ) 的所有字符串。老实说,我从 StackExchange 组装了它,但并不完全理解它。我希望它不会咬我。#%
:A
:h
$0
编辑2:
$ cat /usr/local/bin/foo
#/bin/zsh
path[${path[(i)$0:A:h]}]=() foo | grep -v "^INFO" # reduce output
$path[(i)foo]
foo
查找数组中的索引path
或 1 加数组长度。
答案1
您可以找出脚本所在的目录($0:h
在 zsh 中,"${0%/*}"
在 sh 中)并从中删除该目录PATH
(path=(${path:#$0:h})
在 zsh 中,sh 中更复杂。如果PATH
两次包含相同的目录(例如通过符号链接),则此操作可能会失败。
直接方法的缺点是,这会从路径中删除目录,但同一目录中的其他程序可能是理想的。您可以通过仅使用修改后的路径进行路径查找来解决此问题。
next=$(path=(${path:#$0:h}); print -lr -- =$0:t)
$next
相反,我会PATH
手动进行查找并跳过正在运行的脚本的任何出现。
for d in $path; do
if [[ -x $d/$0:t && ! $d/$0:t -ef $0 ]]; then
exec $d/$0:t
fi
done
答案2
示例:
对我来说type -a egrep
,打印用户定义的别名和实际egrep
命令,在我的 $HOME/bin/ 中添加另一个命令egrep
也会显示它......按顺序;首先是别名,然后是与 PATH 具有相同顺序的其余项目。
$ cd # 回家 $ mkdir -p bin $ PATH=$HOME/bin:$PATH $ 类型 -a egrep egrep 的别名为 `egrep --color=auto' egrep 是 /bin/egrep $ echo -e >bin/egrep '#!/bin/bash\necho TEST' $ chmod 755 bin/egrep $ 类型 -a egrep egrep 的别名为 `egrep --color=auto' egrep 是 /home/$USER/bin/egrep egrep 是 /bin/egrep # 假设你确定它是唯一不在 /home 中且不是别名的 $ 类型 -a egrep | grep -Ev '/home|别名' |切-d''-f3 /bin/egrep $ rm $HOME/bin/egrep
答案3
你可以这样做:
#! /bin/zsh -
# find the other occurrences of a command with the same name in $path that
# are a different file
other_mes=(
${^path/#%/.}/$0:t(N*^e['[[ $REPLY -ef $0 ]]'])
)
if (( ! $#other_mes )) {
print -ru2 Could not find any other $0:t in PATH.
exit 1
}
# run the first found
$other_mes[1] "$@" | grep -v '^INFO'
# return the exit status of the other me, not of grep
exit $pipestatus[1]
${path/#%/.}
$path
将的空元素替换为.
$0:t
: 的尾部(基本名称)$0
[[ a -ef b ]]
a
如果在符号链接解析后发现和b
是同一个文件,则返回 true ,因为它们是同一文件的 2 个路径(如/usr/bin/foo
vs/bin/foo
因为/bin
恰好是/usr/bin
or的符号链接../bin/foo
并且$PWD
是/usr/local
or/usr/foo/../bin/foo
,或者它们是彼此的硬链接或符号链接)。
使用sh
语法(以及大多数[
支持的实现),并假设不以换行符结尾,可能是:-ef
$0
#! /bin/sh -
other_me=$(
me=$(dirname -- "$0")
IFS=:; set -o noglob
for dir in $PATH''; do
other_me=${dir:-.}/$me
if [ -x "$other_me" ] && [ -f "$other_me" ] && [ ! "$other_me" -ef "$me" ]; then
printf '%s\n' "$other_me"
exit
fi
done
printf>&2 '%s\n' "Cound not find any other $me in PATH."
exit 1
) || exit
{
exit_status=$(
{
{
"$other_me" "$@" 4>&-
echo "$?" >&4 4>&-
} 3>&- | grep -v '^INFO' >&3 3>&- 4>&-
} 4>&1
)
} 3>&1
exit "$exit_status"
通过末尾的复杂位来获取 的退出状态$other_me
。