Что-то, что я чувствую, я должен знать наверняка: если я ls <something>
, rm <something>
удаляю точно те же файлы, которые ls
отображались? Есть ли обстоятельства, при которых rm
можно было бы удалить файлы, которые ls
не отображались? (Это в 18.04 Bash)
Редактировать: спасибо всем, кто ответил. Я думаю, что полный ответ представляет собой комбинацию всех ответов, поэтому я принял ответ с наибольшим количеством голосов как «ответ».
Неожиданные вещи, которые я узнал по пути:
ls
не так просто, как вы могли бы подумать, обрабатывая свои аргументы- В простой и беспроблемной установке Ubuntu псевдонимы .bashrc
ls
- Не называйте ваши файлы, начинающиеся с дефиса, так как они могут выглядеть как аргументы команды, а имя один -r запрашивает это!
rm
нет--dry-run
флага ...find -delete
лучше, чемrm
? Вы говорите: «Вот почему» , но мне совершенно непонятно, к чему это относится. Также обратите внимание, что вашfind
вызов рекурсивно удалит все файлы в текущем каталоге, гдеrm
просто удалит файлы в непосредственном каталоге. Также-name *
нет оп. В общем, я весьма озадачен вашим советом ...find
, потому что вы можете запустить его, просмотреть все файлы, а затем выполнить ту же команду с-delete
. Поскольку вы уже видели результатыfind
, не должно быть никакой двусмысленности относительно того, что будет удалено (на самом деле я хотел бы услышать больше подробностей об этом в форме ответа)-delete
" - Но как это лучше, чем запуститьls <filespec>
, а затемrm <filespec>
(что ОП уже знает, как это сделать)?find ... -print
сначала запустите, чтобы подтвердить, какие файлы будут удалены, а затемfind ... -delete
вы все равно удалите файлы, созданные между двумя командами. Если вы используете и то,-print
и другое-delete
, вы не получите подтверждение, а просто отчет о том, что было удалено (и вы можете также использоватьrm -v
).Ответы:
Ну так
ls
иrm
оперируйте аргументами, которые им передаются.Эти аргументы могут быть как простым файлом, так
ls file.ext
иrm file.ext
оперировать тем же файлом, а результат понятен (перечислить файл / удалить файл).Если вместо того, чтобы аргумент является каталогом,
ls directory
перечисляет содержимое каталога , аrm directory
не будет работать как есть (т.е.rm
без флагов не могут удалять каталоги, а если вы делаетеrm -r directory
, это рекурсивно удаляет все файлы подdirectory
и сам каталог ).Но имейте в виду, что аргументы командной строки могут подвергаться расширению оболочки , поэтому не всегда гарантируется, что одинаковые аргументы передаются обеим командам, если они содержат символы подстановки, переменные, выходные данные других команд и т. Д.
В качестве крайнего примера думать
ls $(rand).txt
иrm $(rand).txt
, аргументы «то же» , но результаты совершенно разные!источник
ls
обратите внимание на то,rm *
где есть «скрытые» (точечные) файлы, хотя даже это не совсем справедливое сравнение, поскольку я не писалls *
. Ноrm
само по себе бессмысленно, так что все дело в яблоках и апельсинах. Если я правильно понял, это суть вашего ответа, так что хорошая работа :)ls
противrm -r
: командаls <directory>
не будет показывать скрытые файлы в директории, ноrm -r <directory>
будет удалять даже скрытые файлы.ls
не будет перечислять их (если у них нет псевдонимаls -a
) иrm *
не удалит их (если вы неdotglob
установили).Если вы думаете о чем-то вроде
ls foo*.txt
противrm foo*.txt
, то да, они будут показывать и удалять те же файлы. Оболочка расширяет глобус и передает его соответствующей команде, и команды работают с указанными файлами. Один перечисляет их, один удаляет их.Очевидное различие заключается в том, что если какой-либо из этих файлов окажется каталогом, он
ls
перечислит его содержимое, ноrm
не сможет удалить его. Обычно это не проблема, посколькуrm
удаляет меньше, чем было показаноls
.Большой проблемой здесь является запуск
ls *
илиrm *
каталог, содержащий имена файлов, начинающиеся с тире . Они будут расширяться командные строки двух программ , как если бы вы написали их сами, иls
бы-r
означать «обратный порядок сортировки», в то время какrm
бы-r
означать рекурсивное удаление. Разница имеет значение, если у вас есть подкаталоги как минимум на два уровня. (ls *
покажет содержимое каталогов первого уровня, ноrm -r *
все также пройдет после первого подуровня.)Чтобы избежать этого, пишите разрешающие глобусы с лидирующим знаком,
./
указывающим текущий каталог, и / или ставьте a,--
чтобы сигнализировать об окончании обработки опции перед глобатом (то естьrm ./*
илиrm -- *
).С подобным глобусом
*.txt
это на самом деле не проблема, так как точка является недопустимым символом опции и будет вызывать ошибку (пока кто-то не расширит утилиты, чтобы придумать для нее смысл), но все равно безопаснее поместить ее./
туда.Конечно, вы также можете получить разные результаты для двух команд, если вы изменили параметры глобирования оболочки или создали / переместили / удалили файлы между командами, но я сомневаюсь, что вы имели в виду какой-либо из этих случаев. (Работать с новыми / перемещенными файлами было бы крайне затруднительно.)
источник
Оставляя в стороне поведение оболочки, давайте сосредоточимся только на том, что
rm
иls
можем делать сами. По крайней мере, один случай, когдаls
будет показано, чтоrm
не может быть удалено, включает права доступа к каталогам, а другой - специальные каталоги.
и..
.Разрешения для папок
rm
является операцией над каталогом, потому что, удаляя файл, вы изменяете содержимое каталога (или, другими словами, перечисление записей каталога, поскольку директория - это не что иное, как список имен файлов и inode ). Это означает, что вам нужны разрешения на запись в каталог. Даже если вы являетесь владельцем файла , без прав доступа к каталогу вы не сможете удалить файлы. Обратное также верно :rm
можно удалить файлы , которые могут находиться в собственности других, если вы являетесь владельцем каталога.Таким образом, у вас вполне могут быть права на чтение и выполнение для каталога, что позволит вам, например
ls /bin/echo
, просматривать каталог и просматривать его в очень хорошем состоянии , но вы не сможете,rm /bin/echo
если вы не являетесь владельцем/bin
или не повышаете свои привилегииsudo
.И вы увидите такие случаи повсюду. Вот один из таких случаев: https://superuser.com/a/331124/418028
Специальные каталоги "." а также '..'
Еще один особый случай - это
.
и..
каталоги. Если вы это сделаетеls .
илиls ..
, он с радостью покажет вам содержимое, ноrm
их использование запрещено:источник
Если вы напечатаете
ls *
и затемrm *
, возможно, вы удалите больше файлов, чемls
показано - они могли быть созданы за крошечный промежуток времени между концомls
и началомrm
.источник
/tmp
, когда многие приложения могут создавать временные файлы, так что это всегда возможно в обеих командах с*
. Тем не менее, некоторые приложения также делают файлы анонимными,unlink()
сохраняя их открытыми, поэтому они могут отображаться,ls *
ноrm *
не могут его перехватить.*
что есть разница между тем, чтоls
будет показано, и тем, чтоrm
работает, потому что список содержимого каталога изменился между ними.ls *
фактически может показать имя файла, которое уже пропало.ls *
иrm *
не несут ответственности за расширение глобуса - это делается оболочкой перед передачей команды.Это означает, что вы можете использовать любую команду с расширенным списком файлов, поэтому я бы использовал то, что делает как можно меньше.
Поэтому лучший способ сделать это (или, по крайней мере, другой способ) - пропустить посредника.
echo *
покажет вам, что именно будет передано вашейrm
команде.источник
printf "%s\n" *
получить однозначный взгляд на имена файлов с пробелами. (Или%q
вместо этого иметь дело с символами новой строки и управляющими символами тоже за счет более уродливого вывода.)Как насчет:
По сути, подстановочные знаки, расширяющиеся до элементов, начинающихся с
-
(или вводимых вручную, начиная с,-
но это выглядит как обман), могут интерпретироваться по-разномуls
иrm
.источник
Там являются крайние случаи , когда то , что
ls
показывает не то , чтоrm
снимает. Довольно экстремальный, но, к счастью, благоприятныйls
вариант, если передаваемый вами аргумент является символической ссылкой на каталог: он покажет вам все файлы в каталоге с символическими ссылками , аrm
удалит символическую ссылку, оставив исходный каталог и его содержимое нетронутым:источник
ln -s $HOME some_link; ls some_link
выходыsome_link@
для меня, но яls
псевдонимls -F
. По-видимому,-F
изменяет поведение, чтобы показывать ссылку, а не разыменовывать ее. Не ожидал этого.ls -l
например, целевая ссылка, а не пункт назначения ... должны быть способы проверки самой ссылки.ls
иrm
.ls some_link/
,ls -H some_link
илиls -L some_link
, он будет перечислять связанный каталог, даже если вы добавите-F
или-l
. Наоборот (вроде)-d
говорит , что нужно смотреть на каталог, а не на его содержимое; сравнитьls -l /tmp
иls -ld /tmp
.ls
. Вы в основном показываете, почему перечисление поведения с разными флагами не стоит беспокоиться по этому вопросу ...Если вы только
ls
вместоls -a
, даrm
может удалить скрытые файлы , которые вы не видели сls
без-a
.Пример :
Согласно с :
ls dir_test
: будет отображаться только test2ls -A dir_test
: отобразит test2 + .testrm -r dir_test
: удалит все (.test + test2)Я надеюсь, что это поможет вам.
источник
rm *
не удаляет файлы точек. Если это так,ls *
также покажет их.ls *
не отображать скрытые файлы.ls -a
Перечислим.
,..
,.test
иtest2
. Возможно, вы захотите изменить свой пример для использованияls -A
, который перечисляет все, кроме.
и..
(то есть, только.test
иtest2
).Уже есть много хороших ответов, но я хочу добавить более глубокое понимание.
Задайте себе вопрос: сколько параметров передается
ls
, если вы пишете...? Обратите внимание, что
ls
команда не получает*
параметр as, если есть какие-либо файлы, которые*
можно расширить. Вместо этого оболочка сначала выполняет глобирование перед вызовом команды, поэтомуls
команда фактически получает столько параметров, сколько файлов сопоставлено с глобализацией. Чтобы подавить сглаживание, укажите параметр.Это верно для любой команды:
echo *
противecho '*'
.Есть скрипт, назовите его,
countparams.sh
чтобы проверить эффект. Он сообщает вам, сколько параметров он получил и перечисляет их.Сделайте его исполняемым и запустите
./countparams.sh *
. Учитесь на его выходе!источник
Глоб будет расширяться одинаково оба раза, если содержимое каталога одинаково в эти два разных времени.
Если вы действительно хотите проверить, что будет удалено, используйте
rm -i *.txt
. Он предложит вам отдельно для каждого файла, прежде чем (пытаясь) удалить его.Это гарантированно безопасно для условий гонки:
ls *.txt
/ создан новый файл /rm *.txt
потому что вам предлагается для каждого файла одна и та же программа, которая выполняет удаление.
Это слишком громоздким для нормального использования, и если вы псевдоним ,
rm
чтобыrm -i
вы будете использовать\rm
илиrm -f
довольно часто. Но стоит хотя бы упомянуть, что есть решение для условий гонки. (Это даже переносимо на системы не-GNU: POSIXrm(1)
определяет-i
опцию .)Другим вариантом может быть массив bash:,
to_remove=(*.txt)
затем попросить пользователя подтвердить (возможно, после этогоls -ld -- "${to_remove[@]}"
), затемrm -- "${to_remove[@]}"
. Таким образом, расширение glob выполняется только один раз, и список передается дословноrm
.Еще одна практически используемая опция - GNU
rm -I
( man-страница ), которая запрашивает удаление более 4 элементов. (Но не показывает вам список, только итог.) Я используюalias rm='rm -I'
на своем рабочем столе.Это хорошая гарантия против возврата жира с полузакрытым шаблоном, который слишком подходит. Но использование
ls
first обычно хорошо в вашей собственной директории или в однопользовательской системе, и когда нет фоновых процессов, которые могли бы асинхронно создавать новые файлы там. Для защиты от аппетита, не печатайтеrm -rf /foo/bar/baz
слева направо.rm -rf /
это особый случай, ноrm -rf /usr
это не так! Оставьте-rf
деталь или начните сls
нее и добавляйтеrm -rf
деталь только после ввода пути.источник