
デフォルトではsearchコマンドに似たものを取得しようとしていますが、ディレクトリのリストが$PATH
異なり、検索中のファイルが実行可能ではありません。
ディレクトリリストは固定されており(PATHと同じ形式の変数に圧縮できます)、サブディレクトリにドロップダウンしたくありません。 bashにcomplete
オプションがあることを覚えていますが、そのセクションを最後まで読んでいましたが、見つかりませんでした。私は近いですか?
たぶん、次のようなものがあります(ファイルがあるとします~/lib
)。
> filepath -p ".:/etc:$HOME/lib:$HOME/bin" foo
/home/alexis/lib/foo
which
つまり、orのようなものを探していますが、which -a
実行可能ファイルに限定されてはいけません。実行可能ファイルだけを検索してはいけませんが、$PATH
問題を解決できます;-)。
答え1
find
すでに複数の検索パスをサポートしています。
find . /etc ~/lib ~/bin -maxdepth 1 -name '*foo*'
または使用fd
findよりも速く、機能が豊富で、より美しいです。
fd --max-depth=1 foo . /etc ~/lib ~/bin
別の簡単な方法ですが、空白や改行のあるファイルでは機能しない可能性があります。
SearchPaths=(/etc ~/lib ~/bin)
shopt -s nullglob
eval printf "%s " "${SearchPaths[@]/%/*foo*}"
Bash配列を使って直接ファイル拡張を実行するより簡単な方法を見たようですが、今は覚えていません。
答え2
bash関数はGNUのラッパーとして使用できますfind
。
filepath () {
local fp_path=${FP_PATH:-".:/etc:$HOME/lib:$HOME/bin"} fpath fquit=-quit
local usage="usage: filepath [-a] [-p path[:path...]] expr"
OPTIND=1
while getopts :ap: opt; do
case $opt in
a) fquit=
;;
p) fp_path=$OPTARG
;;
*) echo "$usage" >&2
return 1
esac
done
shift $((OPTIND-1))
if [ -z "$1" ]; then
echo "$usage" >&2
return 1
fi
IFS=: read -r -a fpath <<<"$fp_path"
find "${fpath[@]}" -maxdepth 1 \( -type f -o -type l \) -name "$1" -print $fquit 2>/dev/null
}
デフォルトの検索パスは関数の最初の行で定義され、:
区切り文字として使用されます。環境変数FP_PATH
またはオプションでオーバーライドできます-p
。オプションを使用しない限り、
find
最初の結果を印刷して終了します。-a
検索は通常のファイルとシンボリックリンクに制限され、必要に応じてオプションを調整します。
例:
$ mkdir -p ~/bin /tmp/etc
$ touch ~/bin/foo /tmp/foo /tmp/etc/foo
$ filepath
usage: filepath [-a] [-p path[:path...]] expr
$ filepath -a -p /tmp:/tmp/etc 'fo*'
/tmp/foo
/tmp/etc/foo
$ filepath -p /tmp:/tmp/etc 'fo*'
/tmp/foo
$ FP_PATH=/tmp filepath foo
/tmp/foo
$ filepath foo
/home/freddy/bin/foo
答え3
ディレクトリリストを配列(bash
)に保存する場合は、次のコードを使用できます。
# Maybe in ~/.bashrc
filefindlist=(. /etc "$HOME/lib" "$HOME/bin" src/*)
filefind() {
local ff
for ff in "${filefindlist[@]}"
do
if [ -d "$ff" ] && [ -f "$ff/$1" ]
then
printf '%s\n' "$ff/$1"
return 0
fi
done
return 1
}
使用法
filefind program.c
filefindlist
配列を定義すると、すべての変数とシェルグローバル変数(ワイルドカード)が評価されます。したがって、src/one
後で配列を作成するだけで拡張されますsrc/two
。ただし、次に配列を定義するときは、 と が含まれます。src/*
src/one
src/one
src/two
質問で提案された内容を正確に実装するには、次のアプローチを使用できます。
filefind() {
local fl="$FILEFINDLIST" fp ff
[ "$1" = '-p' ] && fl="$2" && shift 2 # Override default search list
readarray -d: -t fp <<<"$fl" # Convert to array
for ff in "${fp[@]}"
do
if [ -d "$ff" ] && [ -f "$ff/$1" ]
then
printf '%s\n' "$ff/$1"
return 0 # Only print first match
fi
done
return 1
}
使用法
FILEFINDLIST='.:$HOME/lib:$HOME/bin'
filefind -p ".:/etc:$HOME/lib:$HOME/bin" program.c
filefind program.c
答え4
そしてzsh
:
filepath() print -rC1 -- ${(s[:])^1}/$^@[2,-1](N)
それから:
$ filepath .:/etc:$HOME/lib:$HOME/bin ls issue python
/etc/issue
/home/chazelas/lib/python
/home/chazelas/bin/ls