Есть ли недостатки в использовании rm $(ls) для удаления файлов?
Мне было интересно, если использовать rm $(ls)
удалить файлы (или rm -r $(ls)
удалить каталоги также) было безопасно? Потому что на всех сайтах люди предлагают другие способы сделать это, даже если эта команда кажется намного проще, чем другие команды.
2 ответа
Что это должно сделать?
ls
выводит список файлов в текущем каталоге$(ls)
заменяет выводls
помещает это в качестве аргумента дляrm
- по существу
rm $(ls)
предназначен для удаления всех файлов в текущем каталоге
Что не так с этой картиной?
ls
не может правильно обрабатывать специальные символы в имени файла. Пользователи Unix обычно советуют использовать разные подходы. Я также показал это в связанном вопросе о подсчете имен файлов. Например:
$ touch file$'\n'name
$ ls
file?name
$ rm $(ls)
rm: cannot remove 'file': No such file or directory
rm: cannot remove 'name': No such file or directory
$
Кроме того, как правильно указано в ответе Дениса, имя файла с начальными черточками может быть интерпретировано как аргумент rm
после подстановки, которая побеждает цель удаления имени файла.
Что работает
Вы хотите удалить файлы в текущем каталоге. Так что используйте шар rm *
:
$ ls
file?name
$ rm $(ls)
rm: cannot remove 'file': No such file or directory
rm: cannot remove 'name': No such file or directory
$ rm *
$ ls
$
Ты можешь использовать find
команда. Этот инструмент часто рекомендуется использовать не только для текущего каталога - он может рекурсивно обходить все дерево каталогов и работать с файлами через -exec . . .{} \;
$ touch "file name"
$ find . -maxdepth 1 -mindepth 1
./file name
$ find . -maxdepth 1 -mindepth 1 -exec rm {} \;
$ ls
$
В Python нет проблем со специальными символами в именах файлов, поэтому мы могли бы использовать это также (обратите внимание, что это только для файлов, вам нужно будет использовать os.rmdir()
а также os.path.isdir()
если вы хотите работать с каталогами):
python -c 'import os; [ os.remove(i) for i in os.listdir(".") if os.path.isfile(i) ]'
Фактически, приведенная выше команда может быть превращена в функцию или псевдоним в ~/.bashrc
для краткости. Например,
rm_stuff()
{
# Clears all files in the current working directory
python -c 'import os; [ os.remove(i) for i in os.listdir(".") if os.path.isfile(i) ]'
}
Perl версия этого будет
perl -e 'use Cwd;my $d=cwd();opendir(DIR,$d); while ( my $f = readdir(DIR)){ unlink $f;}; closedir(DIR)'
Нет, это небезопасно, и обычно используется альтернатива rm *
не намного безопаснее.
Есть много проблем с rm $(ls)
, Поскольку другие уже рассмотрели в своих ответах, вывод ls
будет разделен на символы, присутствующие во внутреннем разделителе полей.
В лучшем случае это просто не работает. В худшем случае вы намеревались удалить только файлы (но не каталоги) или выборочно удалить некоторые файлы с помощью -i
- но есть файл с именем c -rf
в текущем каталоге. Давай посмотрим что происходит.
$ mkdir a
$ touch b
$ touch 'c -rf'
$ rm -i $(ls)
$ ls
c -rf
Команда rm -i $(ls)
должен был удалить только файлы и спросить перед удалением каждого из них, но команда, которая в конечном итоге была выполнена, прочитала
rm -i a b c -rf
так что он сделал что-то еще полностью.
Обратите внимание, что rm *
только незначительно лучше. Со структурой каталогов, как и раньше, она будет вести себя так, как задумано, но если у вас есть файл с именем -rf
Тебе все еще не повезло.
$ mkdir a
$ touch b
$ touch ./-rf
$ rm -i *
$ ls
-rf
Есть несколько лучших альтернатив. Самые простые из них включают в себя только rm и globbing.
Команда
rm -- *
будет работать именно так, как и предполагалось, где
--
сигнализирует, что все, что после него, не следует интерпретировать как опцию.Это было частью рекомендаций по синтаксису утилит POSIX уже более двух десятилетий. Это широко распространено, но вы не должны ожидать, что оно будет присутствовать везде.
Команда
rm ./*
заставляет глобус расширяться по-другому и поэтому не требует поддержки от вызываемой утилиты.
Для моего примера, приведенного выше, вы можете увидеть команду, которая в конечном итоге будет выполнена, добавив echo.
$ echo rm ./* rm ./a ./b ./-rf
Ведущий
./
предотвращает случайную обработку rm любого из имен файлов как параметров.