変数を使用して find コマンドを実行するときにエラーが発生しました

変数を使用して find コマンドを実行するときにエラーが発生しました

findいくつかのソース ファイルをコピーするコマンドを作成しました。

find ./lib ./tools -type f -regex '.*\.\(cpp\|c\|h\)$' -exec cp --parents \{\} /tmp/potato \; -print

これはうまく機能しますが、オプションで末尾も追加したい-printので、次のようにします。

function deploy_source_code {
    exec_cmd="find ./lib ./tools -type f -regex '.*\.\(cpp\|c\|h\)$' -exec cp --parents \{\} ${args[destdir]} \;"
    if [ "${args[verbose]}" = "true" ]; then
        exec_cmd="${exec_cmd} -print"
    fi  
    ${exec_cmd}
}

しかし、エラーが発生して失敗します:

find: missing argument to `-exec'

なぜ失敗するのか分かりません。アドバイスをいただければ幸いです。よろしくお願いします!

答え1

配列を使用して、それを単純なコマンドの引数として実行します。

deploy_source_code() {
  exec_cmd=(find ./lib ./tools -type f -regex '.*\.\(cpp\|c\|h\)$' 
    -exec cp --parents {} "${args[destdir]}" \;)
  if [ "${args[verbose]}" = "true" ]; then
    exec_cmd+=(-print)
  fi  
  "${exec_cmd[@]}"
}

または、文字列をシェルコードとして評価します。

deploy_source_code() {
  exec_cmd="find ./lib ./tools -type f -regex '.*\.\(cpp\|c\|h\)$' \
    -exec cp --parents {} \"\${args[destdir]}\" \;"
  if [ "${args[verbose]}" = "true" ]; then
    exec_cmd+=" -print"
  fi  
  eval "$exec_cmd"
}

${args[destdir]}上記のコードでは、代入時にが展開されないようにすることが重要です。展開されなければ、その内容が に渡され、evalシェル コードとして評価されてしまいます。安全に使用するのは難しい場合があります。eval特に、すでに連想配列を使用している場合は、配列アプローチを採用することをお勧めします。

あなたのアプローチでは、単純なコマンドの引数を作成するために、文字列に split+glob 演算子を使用していました。 の最後の引数がではなく でfindあったため、これは機能しませんでした(また、 に渡されるリテラル引用符文字にも問題がありました)。 split+glob 演算子は次のように使用できます。\;;find

deploy_source_code() {
  exec_cmd="find ./lib ./tools -type f -regex .*\.\(cpp\|c\|h\)$ \
    -exec cp --parents {} ${args[destdir]} ;"
  if [ "${args[verbose]}" = "true" ]; then
    exec_cmd+=" -print"
  fi
  IFS=" " # split on space
  set -f  # disable glob
  $exec_cmd # invoke the split+glob operator
}

しかし、これはスペース文字が含まれている場合は機能しないことを意味します。これらのスペースを、 likeや改行${args[destdir]}に出現する可能性が低い文字に置き換えることができます。${args[destdir]}:

関連情報