У меня есть несколько папок с \n
характером это их имена.
например:
$ ls
''$'\n''Test'
Это относится к папке с именем теста и пустой строкой перед ее именем.
Поэтому, когда я запускаю несколько таких сценариев, в родительском каталоге:
while IFS= read -r d; do
rmdir $d
done < <(find * -type d)
Это показывает:
rmdir: failed to remove '': No such file or directory
rmdir: failed to remove 'Test': No such file or directory
Потому что он запускается дважды, один раз \n
и другой включенный Test
, потому что имя папки состоит из двух строк.
Так как я могу решить эту проблему так, чтобы скрипт знал \nTest
только одну папку?
command-line
bash
scripts
Тара С Вольпе
источник
источник
-print0
директиву find и-d
опцию read. См stackoverflow.com/a/40189667/7552find * -type d -print0 | while IFS= read -d '' file ; do rmdir $file ; done
команды есть этот выводrmdir: failed to remove 'Test': No such file or directory
.rmdir "$file"
Ответы:
У вас там только одна команда, поэтому достаточно вызвать
find
с-exec
флагом flagrmdir
:Или используйте
-delete
параметр как вfind -type d -delete
, но он не будет работать с непустыми каталогами. Для этого вам также понадобится-empty
флаг. Обратите внимание также,-delete
подразумевает,-depth
что может быть пропущено. Таким образом, другая жизнеспособная альтернатива, которая сохраняет все как один процесс:Если каталог не пустой, используйте
rm -rf {} \;
. Чтобы изолировать только каталоги\n
в имени файла, мы можем объединить цитату ANSI-C в bash$'...'
с-name
опцией:POSIX-ly, мы могли бы справиться с этим следующим образом:
Стоит отметить, что если вашей целью является удаление каталогов, то этого
-delete
достаточно, однако, если вы хотите выполнить команду в каталоге, то-exec
это наиболее уместно.Смотрите также
find
вывода?источник
rm -rf
с осторожностью . ; P Кстати, уfind
вас нет-delete
опции? Он удаляет пустые каталоги и выдает ошибки для непустых, таких какrmdir
- может быть дешевле.-delete
не буду удалять непустые каталоги. Отсюда и бережное использованиеrm -rf
find
команды всухую без какой-либо разрушительной полезной нагрузки (т. Е. Удаляйте-delete
или-exec whatever \;
), чтобы проверить, действительно ли список затронутых файлов верен и не содержит ничего, что не должно быть удалено ...find
. Используйте-exec rmdir {} +
для пакетирования нескольких аргументов в однуrmdir
командную строку. И кстати, « но он не будет работать с непустыми каталогами. » Также относится к этомуrmdir
, так что на самом деле это не отличие от-delete
. Это разница отrm -r
.find -type d -empty -delete
(-delete
подразумевается-depth
).Вы можете использовать оболочки оболочки вместо
find
:Глобус оболочки
*/
соответствует всем папкам в текущем каталоге. Эта конструкция цикла for обеспечивает правильное разбиение слов автоматически.Обратите внимание, что в зависимости от параметров вашей оболочки, это может игнорировать скрытые папки (имя начинается с.). Это поведение можно изменить, чтобы оно соответствовало всем файлам текущего сеанса с помощью команды
shopt -s dotglob
.Также не забывайте всегда указывать свои переменные.
источник
find
делаетshopt -s globstar
и используя**/*/
вместо него glob.Оба ответа, написанные до сих пор, вызывают
rmdir
один раз для каждого каталога, но, какrmdir
можно принять несколько аргументов, я задаюсь вопросом: не существует ли более эффективного способа?Можно просто сделать
и это, безусловно, самый простой и эффективный способ, но он может вызвать ошибку в случае многих каталогов (см. Какова максимальная длина аргументов командной строки в gnome-Terminal? ). Если вы хотите, чтобы этот подход работал рекурсивно, включите параметр
globstar
оболочки сshopt -s globstar
и используйте**/*/
вместо*/
.С GNU
find
(и если мы не хотим просто использовать-delete
), мы могли бы сделатькоторый строит командную строку «почти так же, как
xargs
строит свои командные строки» (man find
). Замены-depth
для ,-maxdepth 1
если вы не хотите работать рекурсивно.В этом ответе SteelDriver объясняет третий и блестящий способ IMO :
При этом используется встроенная оболочка
printf
для создания списка аргументов с нулевым разделителем, затем этот список передается по трубопроводу,xargs
который вызываетrmdir
ровно столько раз, сколько необходимо. Вы можете заставить это работать рекурсивно сshopt -s globstar
и**/*/
вместо*/
как выше.источник
find
является рекурсивным, но цикл OP - нет. Чтобы повторить это поведение, используйтеfind -maxdepth 1 -type d -exec rmdir {} +
. (-depth
в этом случае излишне.) Аккуратный трюк сprintf
подражаниемfind -print0
, я раньше такого не видел.ls
иwhile
петля, я пропустил , что они были перенаправлять от подмены процесса сfind
вместо трубопроводаls
в петлю и просто не показывать его по какой - то причине. Этоfind *
действительно похоронено. Да, это рекурсивно и завершится ошибкой, если в каталоге слишком много записей каталога, включая не-каталоги, потому что он не использует*/
.find .
было бы намного лучше, потому чтоfind
это быстрее,stat
чем расширение bash.