生成された「開始点」セットから find を呼び出す必要がありますが、一部のパスが無効である可能性があります。
paths() {
#
# mock version of the generator
#
echo /bin
echo kjsdfhk
echo /etc
}
find $(paths) -type f name foo.sh
私の問題は、パスが有効であるかどうかわからず、そうでない場合は静かに無視したいということです。私にとって最も簡単なことは今です。
paths \
| while read path;
do
test -e "$path" || continue
find "$path" -type f -name foo.sh
done
しかし、これは高価です。探すすべての有効なパスに対して、コード全体をループ内で呼び出すことができるので、より効率的な方法を見つけたいと思います。
シンプルで非常にUnixのソリューションは次のとおりです。探すSTDINで「スタートポイント」を読んでください。
paths \
| while read path;
do
test -e "$path" || continue
done \
| find - -type f -name foo.sh
それを除いて...探すこれはサポートされていません! :)
どんなアイデアがありますか?
パスはユーザーが提供するため、スペース(およびその他の興味深い事項)を考慮する必要があります。また、POSIXを目指していますが、/bin/sh
犠牲になる可能性があります。 (ああ、STDERR全体を沈めることも/dev/null
オプションではありません...)
修正する:申し訳ありません。 bashだけが利用できることを言及するのを忘れていました。 POSIXのコメントのため、より混乱する可能性があります。実際、コードはBashスクリプトでソースコードの断片を探しており、そのほとんどは現在次の場所にあります。シェン今後のバージョンでは、いくつかの屈辱感を取り除くことができます。したがって、より多くのbashismを追加することを避けることができれば素晴らしいです。しかし、@stephaneの答え(今投票してください!)のように、どんなにエレガントであっても、「zshisms」を余裕がありません。
答え1
zsh
配列に次のパスがある場合:
files=($(paths))
paths
(これにより、出力は空白、タブ改行、またはヌルに分割されます)または:
files=(${(f)"$(paths)"})
行を分割するには、次のようにします。
find $^files(N) -type f -name foo.sh
またはディレクトリに制限したい場合:
find $^files(/N) -type f -name foo.sh
これで、これらのファイルがない場合は、次のように実行できます。
find -type f -name foo.sh
一部のfind
実装(GNUなど)では、これは現在のディレクトリから検索することを意味します。これを防ぐには、次のようにします。
dirs=($^files(/N))
(($#dirs)) && find $dirs -type f -name foo.sh
または:
setopt cshnullglob
find $^files(/) -type f -name foo.sh
今はzsh
もう必要ありませんfind
。簡単に次のことができます。
files=($^files/**/foo.sh(.N))
!
これにより、ファイルが類似またはブロック-name
されている場合でも操作が容易になります。find
ただし、ファイルがディレクトリへのシンボリックリンクである場合(find
ここではファイルを見つけることはありませんが、実際に望むものかもしれません)、zsh
状況は異なります。
答え2
bashを使用しているので、パスのリストを次の場所に保存します。大量に。配列を繰り返して、既存のパスの配列を作成します。結果の配列が空の場合は特別な場合が必要です。それ以外の場合は、find
エラーが発生したり、現在のディレクトリに移動したりします。
完全に堅牢にするには、パスパラメータがaで始まらないようにする必要があります-
。それ以外の場合は、find
オプションまたはデフォルトパラメータとして解釈されます。
paths=(/some/where around/here -print 'one with
odd spaces')
existing_paths=()
for x in "${paths[@]}"; do
if [ -e "$x" ]; then
if [[ "$x" = -* ]]; then x="./$x";; fi
existing_paths+=("$x")
fi
done
if [[ ${#existing_paths[@]} -ne 0 ]]; then
find "${existing_paths[@]}" -type f -name foo.sh
fi
答え3
Pythonを使用してパスが存在するかどうかをテストし、見つかったNULで区切られたパスをエコーし、それを入力してに渡すことができますxargs
。ただし、Python出力の長さがfindを一度だけ呼び出す必要がある最大引数の長さを超えない限り、次のようになりますfind
。
python -c 'import os, sys; sys.stdout.write("\0".join([x for x in sys.argv[1:] if os.path.exists(x)]) + "\0")' a\ b xyz abc| xargs -0 --no-run-if-empty find
Python部分(-cの一重引用符引数):
- 必要なモジュールをインポートして
os
コマンドsys
に使用 - パラメータを繰り返し
a b
てxyz
使用abc
for x in sys.argv[1:]
- パスが存在する場合のみリストに入れます。
[x ... if os.path.exists(x)]
- NULを使用してリストに参加し、NULを追加してstdoutに記録します。
sys.stdout.write("\0".join[...] + "\0")
空のディレクトリがある場合、touch a\ b xyz
最初の2つの引数が見つかりましたが見つからabc
ず、findが後者のパスに渡されないことがわかります。
答え4
これがあなたにうまくいけば
$(paths) 検索 -f 名前 foo.sh と入力します。
その後、有効なパスのみをエコーするようにパス機能を変更できます。
if [ -d "$path" ]; then echo $path fi
または、パスがファイルである可能性がある場合
if [ -d "$path" ] || [ -e "$path" ]; then echo $path fi
このように、 find は一度だけ実行されます。パス関数を変更できない場合は、findコマンドに渡す前に、すべての有効なパスをフィルタリングする他の関数を常に生成して、間違ったパスが渡されないようにすることができます。