Я вызываю исполняемый файл из сценария оболочки. Сценарий, который я пишу, отличается, но я написал фиктивный исполняемый файл и скрипт, чтобы показать, с чем я сталкиваюсь
Сценарий:
#!/bin/sh -h
MYARGS=""
for arg in "$@"; do
shift
case $arg in
*)
pattern=" "if [[ $arg =~ $pattern ]]; then
MYARGS="$MYARGS \"$arg\""else
MYARGS="$MYARGS $arg"fi
;;
esac
done
echo $MYARGS
./a.out $MYARGS
Программа:
#include "iostream"
int main (int argc, char *argv[])
{
for (int i = 0; i < argc; i++)
{
std::cout << argv[i] << std::endl;
}
}
Теперь я не хочу использовать $ @, поскольку мне нужно отфильтровать некоторые аргументы для передачи в основную программу.
Но, когда я пробую вышеупомянутую часть с разделенной пробелами строкой в качестве аргумента, я получаю следующий вывод:
Command : ./a.out "a b"Output :
./a.out
a b
Command: a.sh "a b"Output :
"a b"./a.out
"a
b"
Проблема в том, что во втором случае аргументы автоматически разделяются, а «a» и «b» выступают в качестве разных аргументов, хотя я сохраняю кавычки «»
Что может быть решением этого?
Когда цитата попадает в переменную bash, это просто символ. Не путай то, что ты тип с тем, что содержит переменная. В этом отношении bash ничем не отличается от C.
const char* v = "a b";
printf("%s\n", v); // => a b
const char* w = "\"a b\"";
printf("%s\n", w); // => "a b"
Bash точно такой же:
$ v="a b"$ echo "$v"a b
$ w="\"a b\""$ echo "$w""a b"
Выше я поместил кавычки вокруг моих расширений переменных, которые вы должны всегда делать. (Ну, почти всегда. Но делайте это, если у вас нет действительно веской причины, и вы можете объяснить свою причину.)
Причина, по которой я цитирую расширение, заключается в том, чтобы не допустить разбиения содержимого строки после раскрытия. Разделение слов разбивает строку на отдельные слова в пробеле (если только для $ IFS не установлено другое значение). Вот и все. Он не просматривает строку для специальных символов, потому что их нет. Потому что, как только кавычка находится в строке, это просто еще один символ. (И то же самое касается всех других специальных символов, таких как $
а также \
,
Вы можете (и люди могут рекомендовать вам) использовать сложные конструкции, используя eval
или Eval-подобные операции (как bash -c
). Это почти всегда кончится горем. Самое простое, лучшее и рекомендуемое решение — использовать массив:
myargs=()
for arg in "$@"; do
shift
case "$arg" in
*) myargs+=("$arg") ;;
esac
done
echo "${myargs[@]}"./a.out "${myargs[@]}"
Обратите внимание, что каждая цитата в приведенном фрагменте имеет важное значение (за исключением тех, в case "$arg"
) и все они имеют одну и ту же цель: избежать разбиения слов при раскрытии переменной (или элементов массива). (Исключение для case
слово заключается в том, что оболочка не разбивает слова в этом контексте. Но вам не нужно помнить это; просто используйте кавычки, как показано.)
Просто используйте xargs
#!/bin/bash
MYARGS=""
for arg in "$@"; do
shift
case $arg in
*)
pattern=" "if [[ $arg =~ $pattern ]]; then
MYARGS="$MYARGS \"$arg\""else
MYARGS="$MYARGS $arg"fi
;;
esac
done
echo $MYARGS | xargs ./a.out