Мне было интересно, было ли безопасно использовать rm $(ls)
файлы для удаления файлов (или rm -r $(ls)
для удаления каталогов)? Потому что на всех сайтах люди предлагают другие способы сделать это, даже если эта команда кажется намного проще, чем другие команды.
13
touch 'foo -r .. bar'
;rm $(ls)
; где мой родительский каталог? Кроме того, какие альтернативы вы видите, которые еще сложнее, чем это?rm *
гораздо легче набирать и думать, и безопаснее (но не совсем безопасно; см. ответ Денниса).ls
могут варьироваться в зависимости от реализации и, следовательно, не являются стандартными. В зависимости от того, что вам нужно, рассмотрите альтернативы, такие какfind
иstat
. Вы должны использоватьls
только для потребления человеком, никогда не для использования другими командами или в сценариях.Ответы:
Что это должно сделать?
ls
выводит список файлов в текущем каталоге$(ls)
заменяет выводls
мест, которые в качестве аргумента дляrm
rm $(ls)
предназначен для удаления всех файлов в текущем каталогеЧто не так с этой картиной?
ls
не может правильно обрабатывать специальные символы в имени файла. Пользователи Unix обычно советуют использовать разные подходы . Я также показал это в связанном вопросе о подсчете имен файлов . Например:Также, как правильно упомянуто в ответе Дениса, имя файла с начальными чертами может быть интерпретировано как аргумент
rm
после подстановки, что лишает цели удаления имени файла.Что работает
Вы хотите удалить файлы в текущем каталоге. Так что используйте glob
rm *
:Вы можете использовать
find
команду. Этот инструмент часто рекомендуется использовать не только для текущего каталога - он может рекурсивно обходить все дерево каталогов и работать с файлами с помощью-exec . . .{} \;
В Python нет проблем со специальными символами в именах файлов, поэтому мы могли бы использовать это также (обратите внимание, что это только для файлов, вам нужно будет использовать,
os.rmdir()
иos.path.isdir()
если вы хотите работать с каталогами):Фактически, приведенная выше команда может быть преобразована в функцию или псевдоним
~/.bashrc
для краткости. Например,Perl версия этого будет
источник
"$(ls)"
пример работает, только если в каталоге только один файл. Вы также можете просто использовать табуляцию для расширения имени файла, так как это единственное завершение.ls
тогда :) Я отредактирую это$(ls)
чтобы отключить разделение слов, либо позволяете разделять слова (что приводит к катастрофическим результатам). Единственный чистый способ передать список из нескольких строк без обработки данных как кода - это использовать переменные массива или\0
разделитель, но сама оболочка не может этого сделать. По-прежнемуIFS=$'\n'
наименее опасен, но не может сравнитьсяfind -print0 | xargs -0
. Илиgrep -l --null
. Или вы избегаете всей проблемы с такими вещами, какfind -exec rm {} +
. (Обратите внимание,+
чтобы передать несколько аргументов для каждого вызова rm; ПУТЬ более эффективен).IFS=$'\n'
и в этом случае произойдет сбой, так как у меня есть новая строка в имени файла, так что разделение слов будет рассматривать его как два имени файла вместо одного. Странная причина, однако, заключается в том, что при использовании по умолчаниюIFS
пробела, табуляции, новой строки, оригиналаrm "$(ls)"
также должен произойти сбой, он должен обрабатываться так, как если бы я сказал имя файла, как два отдельных, но это не так. Обычно я используюfind
с-exec
илиfind . . .-print0 | while IFS= read -d'' FILENAME ; do . . . done
структурой , чтобы иметь дело с именами файлов. Или можно использоватьpython
, я добавил пример этого."$(ls)"
всегда расширяется до одного аргумента, потому что кавычки защищают расширение$(ls)
от разделения слов. Так же, как они защищают"$foo"
.Нет, это небезопасно, и обычно используемая альтернатива
rm *
не намного безопаснее.Есть много проблем с
rm $(ls)
. Как другие уже рассмотрели в своих ответах, выводls
будет разделен на символы, присутствующие во внутреннем разделителе полей .В лучшем случае это просто не работает. В худшем случае вы намеревались удалить только файлы (но не каталоги) - или выборочно удалить некоторые файлы
-i
- ноc -rf
в текущем каталоге есть файл с именем . Давай посмотрим что происходит.Предполагалось, что команда
rm -i $(ls)
удалит только файлы и спросит перед удалением каждого из них, но команда, которая в конечном итоге была выполнена, прочиталатак что он сделал что-то еще полностью.
Обратите внимание, что
rm *
только незначительно лучше. Со структурой каталогов, как и раньше, она будет работать так, как задумано, но если у вас есть файл с именем-rf
, вам все равно не повезло.Есть несколько лучших альтернатив. Самые простые из них включают в себя только rm и globbing.
Команда
будет работать точно так, как задумано, где
--
сигнализирует, что все, что после него, не должно интерпретироваться как опция.Это было частью рекомендаций по синтаксису утилит POSIX уже более двух десятилетий. Это широко распространено, но вы не должны ожидать, что оно будет присутствовать везде.
Команда
заставляет глобус расширяться по-другому и поэтому не требует поддержки от вызываемой утилиты.
Для моего примера, приведенного выше, вы можете увидеть команду, которая в конечном итоге будет выполнена путем добавления echo .
Ведущий
./
предотвращает случайную обработку rm любого из имен файлов как параметров.источник
rm
. +1touch 'foo -rf .. bar
. Я не думаю, что злоумышленник может получить более высокий уровень, чем родительский каталог, если мы не сможем создать разделитель пути вls
выводе.rm: refusing to remove '.' or '..' directory: skipping '..'
или что-то подобное при попытке удалить родительский каталог.