Как избавиться от «Не найдено совпадений» при запуске «rm *»

22

Используя zsh, я получаю сообщение «Не найдено совпадений» при выборе шаблона, который не подходит rmи даже при перенаправлении вывода.

# rm * > /dev/zero 2>&1
  zsh: no matches found: *

Как я могу избавиться от этого сообщения?

user123456
источник
Вы пытаетесь удалить все в текущем каталоге? Каков текущий каталог?
cutrightjm
Вы можете использовать setopt extended_glob(или даже просто rm * >/dev/null 2>&1), но на самом деле вы должны сделать обходной путь, чтобы не нуждаться rm *, это совершенно опасно
горький
Вы должны действительно опускаться, /dev/nullа не потом dev/zero. Кроме того, ваше перенаправление stderr отсутствует &; так и должно быть 2>&1.
Ройма
Сообщение об ошибке генерируется zshво время оценки команды, а не во время выполнения самой команды (из-за ошибки команда даже не выполняется). Перенаправление вывода здесь влияет только на вывод команды, а не на саму оболочку.
Adaephon

Ответы:

42

Это поведение контролируется nomatchопцией Zsh . По умолчанию, если командная строка содержит выражение globbing, которое ничего не соответствует, Zsh выведет сообщение об ошибке, которое вы видите, и не выполнит команду вообще. Вы можете отключить это, запустив

setopt +o nomatch

Затем, выражения-глобусы, которые ничего не соответствуют, будут оставлены как есть, и вы получите сообщение об ошибке rm(которое можно отключить -f, хотя это плохая идея, так как это приведет к удалению в других ситуациях, когда вы не можете хочу).

Стивен Китт
источник
4
Поведение также контролируется параметрами nullglobи cshnullglob. Если nullglobустановлено и соответствующий файл не найден, шаблон удаляется из списка аргументов, а не генерирует ошибку. Настройка cshnullglobимеет аналогичный эффект, если все шаблоны в команде не совпадают, и в этом случае будет сообщено об ошибке. Примечание: настройка nullglobили cshnullglobпереопределение nomatch. Можно также установить nullglobдля отдельных моделей с помощью Глоб спецификатора N: rm *(N).
Adaephon
nomatchэто не идеал, это то, что делают Bourne-подобные оболочки. Если шаблон не совпадает, он передается как есть rm(!) , Что rmприведет к ошибке, или, что еще хуже, может удалить неправильный файл для шаблона, *.[ch]например,!
Стефан
9

Что бы вы хотели вместо этого? Не работатьrm вообще (1)? Запустить его с буквальным *аргументом, как в других оболочках типа Борна (2)? Запустить его без каких-либо аргументов (3)?

  1. files=(*(N)); (($#files)) && rm -- $files, Или (rm -- *) 2> /dev/nullэто также скрыло бы подлинные ошибкиrm которые были бы глупыми. Вы можете отменить zshошибку, но восстановить stderr для rmкоманды, хотя с(rm -- * 2>&3 3>&-) 3>&2 2> /dev/null
  2. emulate sh -c 'rm -- *' 2> /dev/null, Затем, как в случае, shкогда zshтеперь эмулируется для этой единственной командной строки, несоответствие *передается как есть rmи rmжалуется, поскольку этот *файл не существует. Мы подавляем rmstderr, как вы это делаете, shчтобы подавить это сообщение об ошибке, но опять же, это глупо, поскольку оно скрывает подлинные ошибки, rmв отличие от ошибки, вызванной неправильным поведением shпередачи литерала *вrm . rm -f '*'не будет жаловаться на несуществующий *файл, так что вы можете сделатьemulate sh -c 'rm -f -- *'
  3. rm -- *(N), rmбудет жаловаться , хотя , когда он не пропустил ни одного аргумента, хотя опять же , не rm -f: rm -f -- *(N).

Обычно, rm -f это команда, которую вы хотите использовать, если хотите, чтобы все файлы были удалены, и получаете сообщение об ошибке только в том случае, если файлы не могут быть удалены или IOW все еще остаются после rmвозвращения. Вы также обычно хотите использовать -fв сценариях, чтобы пользователь не получал подсказки в некоторых ситуациях.

Здесь звонить, rmкогда шар не совпадает, неправильно. sh1 поведение является неправильным. Это безвредно для такой модели *, но для одной такой *.[ch]передачи передача « *.[ch]как есть», когда она не совпадает, может привести к*.[ch] к ошибочному удалению файла:

$ ls
*.[ch]  foo.txt
$ zsh -c 'rm *.[ch]'
zsh:1: no matches found: *.[ch]
$ ls
*.[ch]  foo.txt
$ sh -c 'rm *.[ch]'
$ ls
foo.txt

В противном случае с ошибкой самое разумное , что нужно сделать , и это то , что zshfish, csh, tcsh, bash -o failglobи оригинальный Unix оболочки) делает.

И если вы хотите позаботиться о себе в этом особом случае, zshупростите его с помощью (N)квалификатора glob (для noglob ), как в случае (1) выше. fish(по крайней мере, в последней версии ) делает это еще проще, так как это делает неявный noglob для setкоманды. Итак, эквивалент там будет:

set files *
if count $files > /dev/null
  rm -f -- $files
end

См. Почему nullglob не используется по умолчанию по для более подробной информации.


1 . Строго говоря, это только shсо времен оболочки Bourne (начиная с Unix V7 в 1979 году); более ранние версии sh(которые сделали вызов /etc/globна некотируемых подстановочные знаки , который где Glob название происходит от) сделали ведут себя , как cshи zsh -o cshnullglob, что /etc/globбы прервать команду , если ни один из комков не был ни одного матч (и будет подавлять несовпадающих шарики , если по крайней мере , у одного из них был какой-либо матч). Поведение было нарушено оболочкой Борна.

Стефан Шазелас
источник
Я думаю, что он ожидает получить сообщение об ошибке, rmа не из оболочки. Что-то вроде "rm: не может удалить` * ': нет такого файла или каталога ".
Эммануэль
@ Эммануэль, тогда это 2: emulate sh -c 'rm -- *'чтобы получить (ошибочное ИМО) поведение оболочки Борна.
Стефан Шазелас
@ Stephane_Chazelas, как написано, 2 является правильным ответом на вопрос, который он не задавал :).
Эммануэль
@ Эммануэль, все 3 отвечают на вопрос: как избавиться от ошибки «Нет совпадения». Код ОП подавляет rmошибки. Это то, что вы будете делать в других оболочках, чтобы подавить ошибку, когда нет соответствующего файла, и это также приведет к подавлению подлинных ошибок rm. Мой ответ обрисовывает в общих чертах это и, мы надеемся, показывает, как поведение zsh предпочтительнее.
Стефан Шазелас