Я написал 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 в вашей строке, чтобы создать аргументы простой команды. Это не сработало, потому что последний аргумент to find
был \;
вместо just ;
(и у вас также возникли бы проблемы с буквальными символами кавычек, переданными в find
). Вы могли бы использовать оператор split+glob как:
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
}
Но это значит, что это не сработает, если ${args[destdir]}
содержит пробелы. Вы всегда можете заменить эти пробелы символом, который с меньшей вероятностью будет встречаться в ${args[destdir]}
like :
или newline.