特定のサブディレクトリとファイルを除いて、ディレクトリ内のすべてのエントリを見つける必要があります。私のスクリプトはこれを関数として呼び出す必要があります。
function findStuff() {
# define exclusions
ignore_dirs=("$1" "*foo*") # exclude base dir
ignore_files=("one.txt" "two.txt" "*three*.txt")
# build patterns for find command
dir_pattern=""
file_pattern=""
for i in "${ignore_dirs[@]}"; do dir_pattern=$dir_pattern" ! -path \"$i\""; done
for i in "${ignore_files[@]}"; do file_pattern=$file_pattern" ! -name \"$i\""; done
# find
find "$1 $dir_pattern $file_pattern"
# now do other stuff with the results...
}
findStuff /some/base/dir
しかし、これによりNo such file or directory
エラーが発生しました。
だから実際にコマンドが何であるかを確認し、コマンドラインecho find "$1 $dir_pattern $file_pattern"
に貼り付けてみましたが、うまくいきました。それからそれをスクリプトに貼り付けて実行しましたが、それもうまくいきました!
だから回避問題のために失敗したと思います。私は何が間違っていましたか?
答え1
find
検索の最上位パスにインポートされた最初の引数(-
orで始まる最初の引数(!
or)まで)を使用します。関数から呼び出されたときに文字列である1つの引数を提供します(変数は拡張されています)。パスが見つかりません。(
find
$1 $dir_pattern $file_pattern
に提供したいパラメータ内にリテラル二重引用符を含めることもできますfind
。二重引用符が行うことは、シェルがグローバルパターンを拡張し、スペースIFS
(または変数に含まれるすべて)に分割されるのを防ぐことです。ただし、たとえば、二重引用符は、ファイル名と比較するために使用されるパターンの一部になります! -name \"thing\"
。find
配列を使用し、個々のパラメータを正しく引用してくださいfind
。
myfind () {
local ignore_paths=( "$1" "*foo*" )
local ignore_names=( "one.txt" "two.txt" "*three*.txt" )
local path_args=()
for string in "${ignore_paths[@]}"; do
path_args+=( ! -path "$string" )
done
local name_args=()
for string in "${ignore_names[@]}"; do
name_args+=( ! -name "$string" )
done
find "$1" "${path_args[@]}" "${name_args[@]}"
}
path_args
and上に追加するたびに、リストに、または、およびname_args
3!
つ-path
の-name
要素を追加します"$string"
。"${path_args[@]}"
とが展開されると"${name_args[@]}"
(二重引用符を参照)、要素は個別に引用されます。
同等の実装が次に適用されます/bin/sh
。
myfind () (
topdir=$1
set --
# paths to ignore
for string in "$topdir" "*foo*"; do
set -- "$@" ! -path "$string"
done
# names to ignore
for string in "one.txt" "two.txt" "*three*.txt"; do
set -- "$@" ! -name "$string"
done
find "$topdir" "$@"
)
sh
シェルには位置引数のリストである1つの配列しか使用できないため、その中にオプションを収集します$@
。find
明らかにbash
、単一の配列を使用するように特定のソリューションを作成することもできますが、バリアントsh
も同様に機能しますbash
。
最後に、テスト出力はecho
関数によって実行されたコマンドを正確に表現しません。
考えてみてください:
cat "my file name"
cat
それはということで実行されますmy file name
。
echo cat "my file name"
文字列を出力しますcat my file name
。これは、シェルがコマンドを実行する前に文字列の周りの引用符を削除するためです。走るそれ命令を出すとcat
探すサムファイルではなく1つです。
コマンドをシェルにコピーして貼り付けると、文字列出力にリテラル二重引用符echo
(エスケープ処理)が含まれるため、うまく機能しますが、これは関数が実行する実際のコマンドではありません。