質問を避けるには、 find コマンドを使用します。

質問を避けるには、 find コマンドを使用します。

特定のサブディレクトリとファイルを除いて、ディレクトリ内のすべてのエントリを見つける必要があります。私のスクリプトはこれを関数として呼び出す必要があります。

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_argsand上に追加するたびに、リストに、または、およびname_args3!-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(エスケープ処理)が含まれるため、うまく機能しますが、これは関数が実行する実際のコマンドではありません。

関連情報