Как передать аргументы сценария, содержащие кавычки / пробелы? - PullRequest
23 голосов
/ 19 апреля 2011

Я пытаюсь написать скрипт notify-finish, который можно добавить к любой команде. Когда это будет сделано, он запустит команду, заданную следующими аргументами, а затем отправит электронное письмо пользователю, когда команда будет выполнена. Вот что у меня есть:

PROG=$1
# Run command given by arguments
$@
ECODE=$?
echo -e "Subject: `hostname`: $PROG finished\r\nTo: <$USER>\r\n\r\nExited with $ECODE\r\n" | sendmail $USER

Это работает большую часть времени, но когда аргументы содержат пробелы, кавычка удаляется.

Рабочий пример:

notify-finished rsync -avz source/ user@remote:dest/

Неудачный пример:

notify-finished rsync -avz -e 'ssh -c blowfish' source/ user@remote:dest/

Во втором случае $@ расширяется до rsync -avz -e ssh -c blowfish source user@remote:dest/, пропуская одинарные кавычки. Он не работает ни с двойными кавычками, ни с $*.

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

CMD=(notify-finished rsync -avz -e 'ssh -c blowfish' source/ user@remote:dest/)
${CMD[@]}

Как мне заставить это работать для всех аргументов?

Ответы [ 2 ]

25 голосов
/ 19 апреля 2011

Используйте "$@" с кавычками:

prog="$1"
"$@"
ecode="$?"
echo "$prog exited with $ecode"

Это передаст каждый аргумент в точности так, как он был получен.Если вы не включите кавычки, каждый элемент будет разделен в соответствии с $IFS:

  • "$@", как "$1" "$2" "$3" ..., передавая каждый элемент в качестве отдельного аргумента.
  • "$*" похож на "$1 $2 $3 ...", передавая все элементы, объединенные в один аргумент
  • $* и $@ похож на $1 $2 $3 ..., разбивая каждый элемент на пустое пространство, расширяявсе глобусы и передача каждого результирующего слова в виде отдельного элемента ($IFS).

То же самое верно для массивов, таких как "${array[@]}" и "${array[*]}"

4 голосов
/ 19 апреля 2011

Поместите двойные кавычки вокруг подстановок переменных, чтобы избежать их анализа (обратите внимание, что это относится ко всем переменным: $@, $1 и $PROG).Также: не ставьте $ перед именем переменной при ее назначении;используйте # для комментариев;и в последней строке одинарные кавычки не позволят подставить переменные вообще.

PROG="$1"
shift
# Run program below
"$PROG" "$@"
ECODE=$? # note: this will always be a number, so it doesn't have to be protected with double-quotes
echo -e "Subject: $(hostname): $PROG finished\r\nTo: <$USER>\r\n\r\nExited with $ECODE\r\n' | sendmail "$USER"
...