Почему zsh расширяет глобусы для меня в скрипте bash, используя параллельную GNU? - PullRequest
0 голосов
/ 04 мая 2018

В скрипте bash у меня есть команда, использующая rsync:

#!/usr/bin/bash -e
...
parallel rsync --exclude '*to?be?deleted*' ... 
    --files-from some_file /auto $instance_ip:/somewhere_else/

Согласно документации rsync, их поле --exclude имеет другой стиль сопоставления с образцом .

Когда я запускаю это в терминале bash, все работает нормально.

Однако, выполнение этого на zsh дает мне ошибку, потому что zsh пытается раскрыть эту строку, которую я пытаюсь передать:

zsh:1: no matches found: *to?be?deleted*

Это должно не произойти. Почему zsh даже расширяет мои глобусы в моем скрипте bash ? Есть ли на моем zsh какие-то настройки, которые я могу настроить, чтобы они оба вели себя одинаково? Я не хочу разрабатывать в zsh и развертывать в среде с bash, и мне приходится вести себя по-разному.

Я использую плагины oh-my-zsh:

plugins=(
  git
  colored-man-pages
  zsh-autosuggestions
  zsh-syntax-highlighting
)

В частности, с этим набором команд не получается:

#!/usr/bin/bash -e
find . -name '*filelist' | parallel -j10 rsync --exclude "*to?be?deleted*" testing somewhere_else:/some/where/else

Но с помощью команды rsync она не нарушается.

Ответы [ 3 ]

0 голосов
/ 05 мая 2018

Проблема в утилите GNU Parallel. Даже если кажется, что вы передаете ему программу для запуска с аргументами, на самом деле она объединяет аргументы и передает их в оболочку.

Более того, Parallel либо запускает ту же оболочку, из которой вы запускали parallel, либо выбирает оболочку на основе переменной окружения SHELL (что сомнительно, поскольку эта переменная окружения также используется эмуляторами терминала для определения, какая интерактивная оболочка бежать). В любом случае, именно поэтому он выбирает zsh, а не sh. У вас будет та же проблема с оболочкой, совместимой с sh (bash, dash, ksh,…), но реже: sh оставляет шаблоны в покое, если они ничего не соответствуют, поэтому с sh ваш скрипт будет работать до тех пор, пока в текущем каталоге не найдено файлов, соответствующих *to?be?deleted*.

Решение дано в руководстве, но найти его немного сложно: передайте опцию -q. В руководстве есть очень длинная глава о цитировании, которую вы можете игнорировать 99% времени: просто пропустите -q, если вы не намеревались запустить сценарий оболочки , а не команду . Кроме того, вы должны использовать полный путь к команде, иначе параллель может вызвать встроенную оболочку или даже функцию (если ваша оболочка - bash). Кроме того, установите SHELL на /bin/sh, потому что даже при -q Parallel запускает оболочку и предполагает, что она совместима с sh (я думаю, что zsh достаточно совместим, но я не совсем уверен.). См. Также аналогичный вопрос по Unix Stack Exchange

SHELL=/bin/sh parallel -q -j10 "$(command -v rsync)" --exclude "*to?be?deleted*" testing somewhere_else:/some/where/else

(Да, руководство отговаривает вас от использования -q, но это неправильно. Я уже спорил с автором об этом раньше.)

0 голосов
/ 21 мая 2018

GNU Parallel версия <20140722 использует <code>$SHELL. Более поздние версии пытаются определить, из какой оболочки запускается GNU Parallel, и вместо этого использовать эту оболочку. Подробности об обнаружении можно найти в man parallel_design (Which shell to use). Здесь также объясняется, почему GNU Parallel всегда запускает команды в оболочке (Always running commands in a shell).

Если вы не хотите, чтобы оболочка расширяла специальные символы, вы можете использовать -q. Однако эта команда должна быть простой (см. man bash) без перенаправлений и присвоений переменных. это процитируем командную строку и аргументы, чтобы специальные символы не интерпретируется оболочкой.

0 голосов
/ 05 мая 2018

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

zsh -c "rsync --exclude *to?be?deleted* testing somewhere_else:/some/where/else"

, в котором шаблон не указан. Чтобы предотвратить это, передайте одну строку в качестве аргумента parallel:

... | parallel -j10 'rsync --exclude "*to?be?deleted*" testing somewhere_else:/some/where/else'
...