Расширение переменных в zsh

Сценарий ниже работает в bash, но не в zsh. Я думаю, это потому, что в переменной OPTS я «расширяюсь» (не уверен, что это правильное слово) переменная $EXCLUDE , и этот синтаксис не работает в zsh. Как заменить эту строку, чтобы она работала на zsh?

 SRC="/path_to_source" DST="/path_to_dest" EXCLUDE=".hg" OPTS="-avr --delete --progress --exclude=${EXCLUDE} --delete-excluded" rsync $OPTS $SRC $DST 

  • Глобальный стек
  • Как остановить bash из файлов с проверкой синтаксиса?
  • Что такое расщепление слов? Почему это важно в программировании оболочки?
  • Кластеризация идентичных файлов, игнорирующих пробелы и разрывы строк
  • Установки завершения zsh (autojump) - Как их использовать?
  • Как перечислить все папки в каталоге, не начиная с символа L?
  • Как я могу обнаружить оболочку без входа? (В Zsh)
  • поиск файлов с использованием группового разрешения
  • 3 Solutions collect form web for “Расширение переменных в zsh”

    Проблема здесь в том, что $OPTS не разделяется на несколько аргументов в командной строке rsync . В синтаксисе zsh используйте:

     rsync ${=OPTS} $SRC $DST 

    (альтернативой является симуляция стандартного поведения оболочки во всем мире с опцией -o shwordsplit …)

    С manpage:

    Обычно встречающаяся разница [в zsh ] заключается в том, что переменные, замещенные в командной строке, не разбиваются на слова. См. Описание опции оболочки SH_WORD_SPLIT в разделе «Расширение параметров» в zshexpn(1) . В zsh вы можете либо явно запросить расщепление (например, ${=foo} ), либо использовать массив, если хотите, чтобы переменная расширялась до нескольких слов. См. Раздел «Параметры массива» в zshparam(1) .

    Проблема не исходит от $EXCLUDE , она исходит от $OPTS . Ваш сценарий основан на разбиении слов на $OPTS . Это плохая идея; например, он будет терпеть неудачу, если вы когда-либо измените $EXCLUDE чтобы содержать шаблон, и --exclude=$EXCLUDE подходит для соответствия файлу в текущем каталоге или если вы когда-либо изменяете $EXCLUDE чтобы содержать пробелы.

    $OPTS – это список слов, а не слово. Если вам нужен только ваш скрипт для работы в ksh, bash и zsh, сделайте его массивом:

     SRC="/path_to_source" DST="/path_to_dest" EXCLUDE=".hg" OPTS=(-avr --delete --progress --exclude="$EXCLUDE" --delete-excluded) rsync "${OPTS[@]}" "$SRC" "$DST" 

    Если вы только намерены использовать скрипт в zsh, вы можете упростить последнюю строку:

     rsync $OPTS $SRC $DST 

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

     set -- -avr --delete --progress --exclude="$EXCLUDE" --delete-excluded rsync "$@" "$SRC" "$DST" 

    Если у вас есть сценарий оболочки, который вы хотите легко запускать с помощью zsh, поместите эту строку в начало – она ​​сообщает zsh действовать как ksh, и это не-op для других оболочек.

     emulate ksh >/dev/null 2>/dev/null 

    Чтобы завершить ответ Стефана Гименеса (я еще не могу прокомментировать), одно из решений заключается в том, чтобы сделать ваш скрипт переносимым, если вы используете zsh а затем преобразуете $OPTS в массив, подобный этому

     [ -n "${ZSH_VERSION:-}" ] && set -A OPTS ${=OPTS} 

    Тогда ваша команда rsync будет работать.

    Linux и Unix - лучшая ОС в мире.