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]}
: