ошибка при выполнении команды 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 в вашей строке, чтобы создать аргументы простой команды. Это не сработало, потому что последний аргумент 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.

Связанный контент