Как я могу передать полный список аргументов в bash, сохраняя аргументы из нескольких слов вместе? - PullRequest
10 голосов
/ 18 февраля 2009

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

Я объясню мою проблему на примере. Допустим, у меня была функция decho, которая печатала каждый позиционный параметр в отдельной строке:

#!/bin/bash -u
while [ $# -gt 0 ]; do
  echo $1
  shift
done

Хорошо, если я пойду decho a b "c d" Я получу:

[~]$ decho a b "c d"
a
b
c d

Что я и ожидаю. Но с другой стороны, если я получаю список аргументов из переменной, я получаю это:

[~]$ args='a b "c d"'
[~]$ decho $args
a
b
"c
d"

Что не то, что я хочу. Я могу пойти:

[~]$ echo decho $args | bash
a
b
c d

Но это кажется немного неуклюжим. Есть ли лучший способ сделать так, чтобы расширение $args в decho $args разделялось на слова так, как я ожидал?

Ответы [ 5 ]

5 голосов
/ 18 февраля 2009

Вы можете использовать:

eval decho $args
2 голосов
/ 22 апреля 2009

Вы можете переместить eval внутри скрипта:

#!/bin/bash -u
eval set -- $*
for i; 
do 
  echo $i;
done

Теперь вы можете сделать:

$ args='a b "c d"'
$ decho $args
a
b
c d

но вам придется процитировать аргументы, если вы передадите их в CL:

$ decho 'a b "c d"'
a
b
c d
0 голосов
/ 18 октября 2017

В корне ошибочна попытка передать список аргументов, хранящийся в переменной, в команду.

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

decho_argv=(a b 'c d')  # <-- easy!

Затем вместо изменения команды "decho" для размещения аргументов, взятых из простой переменной (что нарушит ее способность обрабатывать обычные аргументы), вы можете сделать:

decho "${decho_argv[@]}"  # USE DOUBLE QUOTES!!!

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

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

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

Например, представьте в следующем примере, если слово "человек" было заменено двумя словами "rm" и "-rf", а последнее слово arg было "*":

Не делайте этого:

> args='arg1 ; man arg4'
> eval set -- $args
No manual entry for arg4
> eval set -- "$args"        # This is no better
No manual entry for arg4
> eval "set -- $args"        # Still hopeless
No manual entry for arg4

> eval "set -- '$args'"  # making it safe also makes it not work at all!
> echo "$1"
arg1 ; man arg4
0 голосов
/ 18 февраля 2009

хммм .. eval decho $args тоже работает:

[~]$ eval decho $args
a
b
c d

И я могу что-то сделать с массивами bash, используя "${array[@]}" (который работает как "$@"), но тогда мне придется написать код для загрузки массива, что было бы больно.

0 голосов
/ 18 февраля 2009

Вы пробовали:

for arg in "$@"
do
        echo "arg $i:$arg:"
        let "i+=1"
done

Должно дать что-то вроде:

arg 1: a
arg 2: c d

в вашем случае.

Прямо по памяти, без гарантии: -)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...