ЗШ + GREP + REGEX. Почему этот фрагмент действует как rm -r / - PullRequest
0 голосов
/ 30 января 2020

Это небольшой анекдот от того, почему не нужно запускать root.

Я сортировал свой домашний каталог и удалил несколько сжатых файлов, которые я написал, я написал ls . | grep -P 'zip|tar|7z' | xargs rm и подумал: эй Я мог бы также написать это как rm -r $(ls . | grep -P '...') Полагаю.

Вторая часть, которую я не хотел использовать, так как нечего было удалять, это было больше похоже на умственное упражнение, я написал его рядом с последним команда с «делителем» для визуального сравнения.

ls . | grep -P 'zip|tar|7z' | xargs rm **//** rm -r $(ls . | grep -P '...')

Быть **//** «делителем» и ... умственным «заменителем» 'zip|tar..'

Я думал, что это не сработает, но, к моему удивлению, он действовал как rm -r / и пытался удалить все, к счастью, разрешения спасли меня, и ничего не было удалено.

Но мне любопытно, почему это ' я бы так работал, я думаю, что rm **//** как-то переведено в rm /, но я не уверен.

Ответы [ 2 ]

0 голосов
/ 31 января 2020

Одно отличие состоит в том, что решение ls ... | xargs .... также работает, если задействовано действительно много файлов, в то время как ваш rm $( .... ) может выдать список аргументов слишком длинная ошибка. Но если в вашем случае это не проблема, попытка будет еще более простой (при условии, что здесь Zsh; я не понимаю, почему вы отметили это bash, поскольку вы явно ссылаетесь только на Zsh в вашем вопросе)

rm *(zip|tar|7z)*(N)

, что express ваше первоначальное утверждение; Однако я считаю, что вы действительно имели в виду

rm -- *.(zip|tar|7z)(N)

, потому что решение, которое вы разместили, также удалит, например, файл tarpit.txt. Флаг (N) - это слабая попытка разобраться со случаем, когда у вас нет файла, соответствующего шаблону. Без (N) вы получите сообщение об ошибке от Zsh, а rm получит нерасширенный шаблон файла и, поскольку маловероятно, что файл с таким именем существует, выведет второе сообщение об ошибке. Используя (N), Zsh просто ничего не передаст в этом случае (без жалоб), и на самом деле rm будет вызываться без аргументов. Конечно, тогда вы получите rm: отсутствующий операнд на stderr, и если вам это не нравится, вы можете отфильтровать это сообщение.

ОБНОВЛЕНИЯ :

Как указал Кусалананда в своем комментарии, пропуск (N) по умолчанию заставит zsh выводить только сообщение об ошибке, если ни один файл не соответствует шаблону, но не вызывает rm быть призван.

Также добавлен флаг -- к rm, чтобы разрешить удаление, т. Е. Файла с именем -rf.tar.

0 голосов
/ 31 января 2020

В оболочке zsh **//** расширится на все имена в /, а также на все имена в текущем каталоге (рекурсивно).

Из пустого каталога в моей системе:

$ echo **//**
/altroot /bin /boot /bsd /bsd.booted /bsd.rd /bsd.sp /dev /etc /extra /home /mnt /root /sbin /sys /tmp /tmp_mnt /usr /var /vol

Почему? Ну, **/ рекурсивно сопоставляет все каталоги в текущем каталоге. Что еще более важно, он соответствует каталогу current , но поскольку имя текущего каталога недоступно в текущем каталоге, для него нет возвращаемой записи.

Однако , когда вы добавляете / к этому для создания **//, вы получаете одинокий / для текущего каталога. Снова в пустом каталоге:

$ echo **//
/

Затем, если вы добавите еще ** для создания **//**, вы заберете все имена из каталога root вместе со всеми именами из текущего каталог и ниже (имена каталогов из текущего каталога и ниже будут встречаться в списке дважды).

Ваш xargs вызывает

rm **//** rm -r $(ls . |  grep -P '...')

Если вы используете GNU rm , он будет тщательно переставлять командную строку так, чтобы она интерпретировалась так же, как

rm -r **//** rm $(ls . |  grep -P '...')

Теперь это должно быть понятно.


Если вы хотите удалить все обычные файлы в текущем каталоге с суффиксами имен файлов .zip, .tar или .7z используйте

rm ./*.(zip|tar|7z)(.)

в оболочке zsh. Если вы хотите сделать это рекурсивно вниз в подкаталоги, используйте

rm ./**/*.(zip|tar|7z)(.)

Спецификатор glob (.) заставляет шаблон глобирования соответствовать только обычным файлам. Вы можете даже ограничить его файлами более определенного размера, скажем, 10 МБ, с ./**/*.(zip|tar|7z)(.Lm+10).

...