3

Представь, у меня есть это

$ ARGS='"a b" c'
$ for arg in "$ARGS"; do echo "$arg"; done
"a b" c
$ for arg in $ARGS; do echo "$arg"; done
"a
b"
c

Результат, который я хочу получить,

$ <???>
a b
c

Как бы я пошел по этому поводу? Благодарю.

2 ответа2

2

Это даст результат, который вы запрашиваете:

eval "for arg in $ARGS; do echo \"\$arg\";done"

Но eval следует использовать только в качестве крайней меры. Причина, по которой на ваш вопрос трудно ответить, заключается в том, что формат вашей переменной ARGS плохо спроектирован.

Последовательность слов, разделенных пробелами, с пробелами внутри слов, защищенных механизмом цитирования, является основным форматом команды оболочки. Поскольку вы должны изучить этот формат, чтобы иметь возможность писать сценарий оболочки, становится заманчивым использовать его для структур данных, управляемых вашим сценарием оболочки, поэтому вы просто берете подобную оболочке конструкцию "a b" c и помещаете ее в переменная оболочки

Обычно это плохая идея. Нет причин для того, чтобы строки в вашем сценарии оболочки выглядели как командные строки оболочки, и единственный способ манипулировать строкой, содержащей разделенные пробелами слова, возможно, заключенные в кавычки, - это либо создать свой собственный анализатор из примитивных строковых операций, либо задать оболочка, чтобы сделать это с Eval.

Но когда вы используете eval, вы не просто получаете удобный разделитель слов и средство удаления кавычек, вы также получаете все остальное синтаксического анализатора оболочки: подстановка команд, подстановка параметров, перенаправление ввода / вывода и другие вещи, которые вы, вероятно, надеваете не хочу

Используйте массив. Этот скрипт на основе массива работает в zsh, ksh и bash:

ARGS=("a b" c)
for arg in "${ARGS[@]}"; do
    echo "$arg"
done

Это намного чище, чем Eval. Если вы программируете для древней системы, в которой нет zsh, ksh или bash, подумайте об изучении awk. Минимальная оболочка POSIX просто не является хорошим языком для сценариев, достаточно сложных, чтобы нуждаться в массивах.

Небольшая проработка части ответа ormaaj: POSIX sh имеет единственную переменную-массив: $@ которая является массивом "позиционных параметров" (аргументов командной строки). Вы можете обращаться (читать, а не записывать) к его отдельным элементам как $1 , $2 , $3 и т.д. Вы можете заменить весь массив командой set . Для вашего примера сценария этой функциональности едва достаточно. Это работает в любой оболочке семьи Борн:

set -- "a b" c
for arg; do
    echo "$arg"
done

Я добавил демонстрацию бонусной функции: for arg без in эквивалентен for arg in "$@" который перебирает массив $@ .

0

Так как вы не заботитесь о кавычках, просто удалите их с помощью sed, прежде чем идти по строке:

for arg in `echo $ARGS | sed -e 's/"//g'`; do
  echo $arg
done

Если ... ваш пример не так, и вы хотите увидеть что-то вроде этого:

a b
c

Вероятно, есть много способов сделать это, но я бы использовал awk (предполагая, что GNU awk позволяет использовать разделители полей длиннее одного символа):

echo $ARGS | \
awk -F'" ' '{ for (field = 1; field <= NF; field++) print $field; }' | \
sed -e 's/^"//' -e 's/"$//'

Последнее значение sed удаляет все начальные кавычки и возможную заключительную кавычку в конце $ ARGS. Конечно, все это развалится, если у вас есть вложенные кавычки.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .