Предположим, что Вы зарегистрированы как abc
и запущенный netbean
, затем abc
у пользователя должно быть разрешение для чтения и записи. Это можно установить как
chmod -R 775 /var/www/project
и
chown -R www-data:abc /var/www/project
Оба неверны с настройками по умолчанию 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
, вы получите поведение, которое вы получили в своей интерактивной оболочке, а именно: это работает.
При интерактивном запуске 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