階層的な $PATH を介して現在のディレクトリの親にあるバイナリを再帰的に検索する

階層的な $PATH を介して現在のディレクトリの親にあるバイナリを再帰的に検索する

ターミナルを使用しているときに、CWD によってトリガーされる追加のバイナリ/コマンドをいくつか利用できるようにしたいと考えています。

例として、次のディレクトリ構造を示します。

├── P1
|   ├── mybin
|   │   └── cmd1
|   ├── S1
|   │   └── mybin
|   │       └── cmd2
|   ├── S2
└── P2
    └── S3

そしてこのディレクトリ構造では

  • cmd1およびcmd2でご利用いただけますP1/S1
  • またはではのみcmd1が利用可能です。P1P1/S2
  • どちらも利用できP2ませんP2/S3

一般的に、私はこれを任意のディレクトリ構造で動作させたいと思っています。これは、git が git リポジトリ内にいるかどうかを検出する方法に似ています。これは、 に 、 、 を置くこと./mybinと同じ../mybinです。../../mybin$PATH

これを機能させるには、どのように変更すればよいでしょうかPATH? 私は fish シェルを使用していますが、他のシェルのソリューションを自分のシェルに移植することも喜んで行います。

答え1

あなたがただ満足していないのは理解できます

PATH="./mybin:../mybin:../../mybin:../../../mybin:$PATH"

8 個程度のサブディレクトリなどの制限まで。

通常のコマンド検索を汚染したり壊したりする代わりに、短いラッパーを使用して、プレフィックスが付けられたコマンドに対してのみ再帰検索を実行することをお勧めします。

たとえば、などをk foo試行しますが、通常どおり で単純に検索されます。./mybin/foo../mybin/foofoo$PATH

しかし、私は fish を使用していないので、これを fish シェルの言語でどのように記述すればよいのかわかりません。bash / ksh / zsh では、次のようになります。

function k {
    typeset p=. cmd=$1; shift
    while
        typeset e=$p/mybin/$cmd
        if [ -x "$e" ]; then "$e" "$@"; return; fi 
        [ ! "$p" -ef / ]
    do
        p=../$p
    done
    echo >&2 "k: not found: $cmd"; return 1
}

それがうまくいけば、fish に翻訳するのではなく、スタンドアロンの実行可能スクリプトにすることができます。

#! /bin/bash
p=. cmd=$1; shift
while
    e=$p/mybin/$cmd
    if [ -x "$e" ]; then exec "$e" "$@"; fi
    [ ! "$p" -ef / ]
do
    p=../$p
done
echo >&2 "k: not found: $cmd"; exit 1

関連情報