Расширение правой строки в Bash (для сценария оболочки)

Я немного экспериментирую со сценарием оболочки, который должен запускать команды git для нескольких репозиториев на одном уровне. Эта структура проекта может быть плохой идеей, но это уже другая история.

Все работает нормально, пока я не столкнулся с этой проблемой:

DETAIL="test test" && command="commit -m '${DETAIL}'" && echo $(git ${command})
# -> error: pathspec 'test'' did not match any file(s) known to git.

Я также пробовал другие возможности, такие как

DETAIL="test test" && command="commit -m ${DETAIL}" && echo $(git ${command})
DETAIL="test test" && command="commit -m $DETAIL" && echo $(git ${command})

Все дают одинаковый результат (см. выше). Я также просмотрел эти docs о расширении строки, но у меня нет проблемы, что переменные/строки могут быть нулевыми или неопределенными. Последний echo не проблема, вы также можете сохранить результат $(git status) в переменной и повторить этот (мой способ в скрипте).

Я знаю, что есть подобные questions, но похожего сценария пока не нашел, так как имею дело как раз с простыми и ненулевыми строками, но с (тоже?) много цитат.

Интересный вариант:

DETAIL="test test" && command="commit -m '${DETAIL}'" && echo $("git ${command}")
# -> git commit -m 'test test': command not found # WHAT?

Тоже интересно, только:

command="commit -m 'test'" && echo $(git ${command})

работает отлично.


person BairDev    schedule 12.02.2019    source источник


Ответы (1)


Используйте массивы bash с правильным цитированием...

DETAIL="test test" && command=(commit -m "$DETAIL") && git "${command[@]}"

К вашему коду:

  • echo "$(command)" совпадает с command (хорошо, пустые строки в конце удалены)
  • "command blabla" не выполняет файл command с первым аргументом blabla. Он выполнит имя файла, названное точно с пробелом command blabla.
  • Внутри $("git ${command}") вы хотите выполнить имя файла с именем git commit -m 'test test' (точно, это полное имя файла с пробелами после расширения ${command}). Поскольку в вашей системе нет файла с именем git commit -m 'test test', команда bash возвращает не найденную.
person KamilCuk    schedule 12.02.2019
comment
Большое спасибо. Теперь я борюсь с тем, чтобы залить этот массив в локальную функцию и получить его прямо там. Здесь runCommand — моя локальная функция: declare -a commandArray=("commit" "-m" "${DETAIL}"); — следующая строка — run_command $commandArray. Затем внутри функции: local actualCommand=$@ - затем - result=$(git ${actualCommand[@]})? - person BairDev; 12.02.2019
comment
bash не имеет первоклассного массива values. Когда вы говорите, что что-то является массивом, это просто означает, что для name задан атрибут, который позволяет вам использовать индексацию. На самом деле это тонкий слой синтаксического сахара над набором различных переменных. - person chepner; 12.02.2019
comment
Если arr=(1 "2 3" 4), то: f "${arr[@]}" равно f 1 "2 3" 4. Но f ${arr[@]} равно f 1 2 3 4, т.е. дело ". Только "${arr[@]}" будет правильно расширен. Используя $arr, вы получите только первый элемент. Вы можете внутри функции local actualCommand=("$@"). - person KamilCuk; 12.02.2019