Расширение zsh работает по-другому в неинтерактивных сценариях?

Предположим, что Вы зарегистрированы как abc и запущенный netbean, затем abc у пользователя должно быть разрешение для чтения и записи. Это можно установить как

chmod -R 775 /var/www/project

и

chown -R www-data:abc /var/www/project
3
28.04.2015, 17:25
2 ответа

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

В интерактивном режиме похоже, что у вас установлен параметр null_glob . Согласно документации zsh этот параметр не установлен по умолчанию. Что произойдет, если этот параметр не установлен, зависит от того, установлен ли другой параметр, nomatch , или нет. Если nomatch не задан ( nonomatch ), вы получите следующее:

% mkdir dir
% touch dir/file.a
% ls file.a
ls: cannot access file.a: No such file or directory
% echo */*.{a,b} .
dir/file.a */*.b .

Расширение происходит в 2 этапа. Сначала * / *. {A, b} расширяется до 2 слов: * / *. A и * / *. B . Затем каждое слово раскрывается в виде шаблона глобуса. Первый расширяется до dir / file.a , а второй расширяется до самого себя, потому что он ничему не соответствует.Все это означает, что если вы используете mv , а не echo , mv должен попытаться переместить 2 файла: dir / file.a (нормально) и * / *. B (такого файла нет). Это то, что происходит по умолчанию в большинстве оболочек, таких как sh и ksg и bash .

По умолчанию параметры zsh таковы, что null_glob не задан, а nomatch установлен. Сценарии запускаются с настройками параметров по умолчанию (если вы не измените их в ~ / .zshenv или / etc / zshenv , что делать не следует). Это означает, что в сценариях вы получите следующее:

% mkdir dir
% touch dir/file.a
% ls file.a
ls: cannot access file.a: No such file or directory
% cat script.sh
#!/usr/bin/zsh
echo */*.{a,b} .
% ./script.sh
./script.sh:2: no matches found: */*.b

Поскольку * / *. B ничего не соответствует, вы получите ошибку из-за nomatch .

Если вы вставите setopt nonomatch в сценарий перед командой echo / mv ], вы вернетесь к неправильному поведению, описанному выше: это пытается переместить несуществующий файл.

Если вы вставите setopt null_glob в сценарий перед командой echo / mv , вы получите поведение, которое вы получили в своей интерактивной оболочке, а именно: это работает.

7
27.01.2020, 21:10

При интерактивном запуске zsh считывается ваш ~/.zshrc (а также система /etc/zshrc, но если ваш администратор не непослушный, то это не его вина). Скорее всего, там вы установите несколько /etc/zshrc опций, которые изменяют способ расширения команд zsh, в частности extended_glob (который должен быть по умолчанию, если zsh не выбрал обратную совместимость с ранними 1990-ми годами, когда такой опции не существовало). Эти опции не будут установлены при выполнении скрипта.

В вашем случае происходит команда mv */*.{a,b} . сначала разбирается в список слов mv, */*.a, */*.b, . (если не отключить расширение скобы). Затем каждое слово, содержащее символ подстановки, рассматривается как шаблон. По умолчанию, в zsh, если шаблон глобуса не совпадает ни с одним файлом, команда не выполняется и zsh сигнализирует об ошибке. Очевидно, что в вашем .zshrc включена опция null_glob, в результате чего несовпадающий шаблон расширяется до пустого списка слов (т.е. он удаляется). При выполнении скрипта второй шаблон */*.b не совпадает ни с одним файлом, что приводит к ошибке, которую вы видите. При интерактивном выполнении команды этот шаблон удаляется.

Опцию null_glob можно явно включить в вашем скрипте с помощью setopt null_glob. Вы также можете включить его для конкретного шаблона с помощью N glob qualifier:

mv */*.{a,b}(N) .

Вместо того, чтобы использовать здесь расширение для скобок, вы должны использовать оператор или , который доступен в zsh (в отличие от простого sh), потому что это именно то, что вы имеете в виду - не два шаблона, а файлы, которые совпадают с любым из шаблонов.

mv */*.(a|b) .

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

Если ни один файл не совпадает вообще, эта команда приведет к ошибке. Вы не можете просто заставить ее замолчать с помощью (N), потому что это приведет к недействительной команде mv . будет выполнена. Вместо этого сначала проверьте, есть ли совпадения, и выполните mv только в том случае, если совпадения есть.

files=(*.(a|b)(N))
if ((#files)); then mv -- $files[@] .; fi
2
27.01.2020, 21:10

Теги

Похожие вопросы