Я хочу отобразить все каталоги, в которых нет файлов с определенным окончанием файла. Поэтому я попытался использовать следующий код:
find . -type d \! -exec test -e '{}/*.ENDING' \; -print
В этом примере я хотел отобразить все каталоги, в которых нет файлов с окончанием .ENDING
, но это не работает.
Где моя ошибка?
Вот решение, состоящее из трех шагов:
temeraire:tmp jenny$ find . -type f -name \*ENDING -exec dirname {} \; |sort -u > /tmp/ending.lst
temeraire:tmp jenny$ find . -type d |sort -u > /tmp/dirs.lst
temeraire:tmp jenny$ comm -3 /tmp/dirs.lst /tmp/ending.lst
Вот так!
#!/usr/bin/env python3
import os
for curdir,dirnames,filenames in os.walk('.'):
if len(tuple(filter(lambda x: x.endswith('.ENDING'), filenames))) == 0:
print(curdir)
Или поочередно (и более питонически):
#!/usr/bin/env python3
import os
for curdir,dirnames,filenames in os.walk('.'):
# Props to Cristian Cliupitu for the better python
if not any(x.endswith('.ENDING') for x in filenames):
print(curdir)
Бонусный контент DLC!
Исправленная (в основном) версия команды find:
find . -type d \! -exec bash -c 'set nullglob; test -f "{}"/*.ENDING' \; -print
Оболочка расширяет *
, но в вашем случае оболочка не используется, только тест команда выполняется найти. Следовательно, файл, существование которого проверяется, буквально называется *.ENDING
.
Вместо этого вы должны использовать что-то вроде этого:
find . -type d \! -execdir sh -c 'test -e {}/*.ENDING' \; -print
Это приведет к ш расширение *.ENDING
когда тест выполняется.
Источник: найти глобусы на UX.SE
Вдохновленный Деннис Нолти и MikeyB's ответы, я придумал это решение:
find . -type d \
\! -exec bash -c 'shopt -s failglob; echo "{}"/*.ENDING >/dev/null' \; \
-print 2>/dev/null
Это работает исходя из того, что
если failglob установлена опция оболочки, и совпадений не найдено, выводится сообщение об ошибке и команда не выполняется.
Кстати вот почему stderr был перенаправлен на /dev/null
.
Я бы сделал это на perl лично
#!/usr/bin/perl
use strict;
use warnings;
use File::Find;
#this sub is called by 'find' on each file it traverses.
sub checkdir {
#skip non directories.
return unless ( -d $File::Find::name );
#glob will return an empty array if no files math - which evaluates as 'false'
if ( not glob ( "$File::Find::name/*.ENDING" ) ) {
print "$File::Find::name does not contain any files that end with '.ENDING'\n";
}
}
#kick off the search on '.' - set a directory path or list of directories to taste.
# - you can specify multiple in a list if you so desire.
find ( \&checkdir, "." );
Должен сработать (работает на моем очень упрощенном тестовом примере).
Вот одна строка о находке.
find ./ -type d ! -regex '.*.ENDING$' -printf "%h\n" | sort -u
редактировать: Ой, тоже не пойдет.
find . -type d '!' -exec sh -c 'ls -1 "{}"|egrep -q "*ENDING$"' ';' -print
q
в egrep для тишины
С участием egrep
вы можете поменять местами нужное регулярное выражение
ls -1 "{}"
выводит имена файлов из команды find