Примечание:
* Этот ответ, вероятно, идет глубже, чем оправдывает сценарий использования, и find 2>/dev/nullможет быть достаточно хорошим во многих ситуациях. Он может по-прежнему представлять интерес для кроссплатформенной перспективы и для обсуждения некоторых передовых методов оболочки в интересах поиска максимально надежного решения, даже если защищенные случаи могут быть в значительной степени гипотетическими.
* Если ваша система настроена на показ локализованных сообщений об ошибках , добавьте префиксы к findприведенным ниже вызовам LC_ALL=C( LC_ALL=C find ...), чтобы обеспечить сообщение на английском языке, чтобы все grep -v 'Permission denied'работало как задумано. Неизменно, однако, все сообщения об ошибках , которые действительно получают отображенные тогда будут на английском языке , а также.
Если ваша оболочка - это bashилиzsh , есть надежное, но достаточно простое решение , использующее только POSIX-совместимые findфункции ; хотя bashсам по себе он не является частью POSIX, большинство современных платформ Unix поставляются с ним, что делает это решение широко переносимым:
find . > files_and_folders 2> >(grep -v 'Permission denied' >&2)
Примечание. Существует небольшая вероятность того, что некоторые grepвыходные данные могут появиться после find завершения, потому что общая команда не ожидает завершения выполнения команды изнутри >(...). В bash, вы можете предотвратить это, добавив | catк команде.
>(...)является (редко используется) выходной процесс подстановки , который позволяет перенаправлять вывод (в данном случае, STDERR выход ( 2>) на стандартный ввод командного внутри >(...).
Кроме того , bashи zsh, kshподдерживает их, а в принципе , но при попытке объединить их с переадресацией из stderr , как это делается здесь ( 2> >(...)), кажется, игнорируется (in ksh 93u+).
grep -v 'Permission denied'фильтры из ( -v) все линии (от findпотока Stderr командования) , которые содержат фразу Permission deniedи выводит оставшиеся строки в стандартный поток ошибок ( >&2).
Этот подход:
robust : grepприменяется только к сообщениям об ошибках (но не к комбинации путей к файлам и сообщений об ошибках, которые могут привести к ложным срабатываниям), а сообщения об ошибках, отличные от запрещенных, передаются в stderr.
Побочный эффект бесплатно : find«сек код выхода сохраняется: невозможность доступа по крайней мере один из элементов файловой системы , с которыми сталкиваются результаты в выходном коде 1(хотя это не о том , какой ошибки других произошло , чем разрешения, запрещённые (тоже)).
POSIX-совместимые решения:
Полностью POSIX-совместимые решения либо имеют ограничения, либо требуют дополнительной работы.
Если findвыход «S должен быть захвачен в файл в любом случае (или подавлена вообще), то трубопровод на основе решения от ответа Джонатана Леффлера является простым, надежным и POSIX-совместимый:
find . 2>&1 >files_and_folders | grep -v 'Permission denied' >&2
Обратите внимание, что порядок перенаправлений имеет значение: 2>&1должен идти первым .
Захват вывода stdout в файл с самого начала позволяет 2>&1отправлять только сообщения об ошибках по конвейеру, который grepзатем может однозначно работать.
Единственным недостатком является то, что общий код выхода будет grepкомандования , а не find«s, что в данном случае означает: если нет ни одной ошибки на всех или только ошибки разрешения, отказано, код выхода будет 1(сигнализации сбоя ), в противном случае ( ошибки, отличные от запрещенных разрешением), 0что противоречит намерению.
Тем не менее, findкод выхода в любом случае редко используется, так как он часто передает мало информации, кроме фундаментального сбоя, такого как прохождение несуществующего пути.
Тем не менее, конкретный случай даже только некоторыепути ввода, недоступные из-за отсутствия разрешений , отражаются в findкоде выхода России (как в GNU, так и в BSD find): если ошибка отказа в разрешении возникает для любого из обработанных файлов, для кода выхода устанавливается значение 1.
Следующая вариация адресована этим:
find . 2>&1 >files_and_folders | { grep -v 'Permission denied' >&2; [ $? -eq 1 ]; }
Теперь код выхода указывает, есть ли какие-либо ошибки, кроме Permission denied возникших: 1если так, то 0иначе.
Другими словами: код завершения теперь отражает истинное намерение команды: об успехе ( 0) сообщается, если вообще не было ошибок или только были отклонены разрешения.
Возможно, это даже лучше, чем просто пропускать findкод выхода, как в решении вверху.
В комментариях gniourf_gniourf предлагается (по-прежнему POSIX-совместимое) обобщение этого решения с использованием сложных перенаправлений , которое работает даже при стандартном поведении печати путей к файлу на стандартный вывод :
{ find . 3>&2 2>&1 1>&3 | grep -v 'Permission denied' >&3; } 3>&2 2>&1
Вкратце: пользовательский дескриптор файла 3используется для временного обмена stdout ( 1) и stderr ( 2), так что только сообщения об ошибках могут передаваться grepчерез stdout.
Без этих перенаправлений и данные (пути к файлам), и сообщения об ошибках передавались бы grepчерез stdout, и grepтогда они не могли бы различить сообщение об ошибке Permission denied и (гипотетический) файл, имя которого содержит фразу Permission denied.
Однако, как и в первом решении, сообщается, что код выхода будет grep's, а не find', но можно применить то же исправление, что и выше.
Примечания к существующим ответам:
Есть несколько моментов , чтобы отметить о ответе Майкла Brux в , find . ! -readable -prune -o -print:
Требуется GNU find ; в частности, это не будет работать на macOS. Конечно, если вам когда-нибудь понадобится команда для работы с GNU find, это не будет проблемой для вас.
Некоторые Permission deniedошибки могут все еще появляться: find ! -readable -pruneсообщает о таких ошибках для дочерних элементов каталогов, для которых текущий пользователь имеет rразрешение, но не имеет x(исполняемого) разрешения. Причина заключается в том, что , поскольку сам каталог является читаемым, -pruneне выполняется, а попытка спуска в этот каталог , то вызывает сообщения об ошибках. Тем не менее, типичным случаем является отсутствие rразрешения.
Примечание. Следующий пункт является вопросом философии и / или конкретного случая использования, и вы можете решить, что он не относится к вам и что команда хорошо соответствует вашим потребностям, особенно если вы просто печатаете пути:
- Если вы концептуализируете фильтрацию сообщений об ошибках с отказом в разрешении как отдельную задачу, которую вы хотите применить к любой
find команде, тогда противоположный подход к профилактическому предотвращению ошибок с запрещенным разрешением требует введения в findкоманду «шума» , что также вводит сложность и логические подводные камни .
- Например, наиболее одобренный комментарий к ответу Михаэля (на момент написания статьи) пытается показать, как расширить команду, добавив
-nameфильтр, следующим образом:
find . ! -readable -prune -o -name '*.txt'
Это, однако, не работает должным образом, поскольку требуется завершающее -printдействие (объяснение можно найти в этом ответе ). Такие тонкости могут вносить ошибки.
Первое решение в ответе Джонатана Леффлера , find . 2>/dev/null > files_and_foldersкак он сам заявляет, вслепую заставляет замолчать все сообщения об ошибках (и обходной путь громоздок и не полностью надежен, как он также объясняет). С практической точки зрения , однако, это самое простое решение , так как вы можете согласиться с тем, что любые ошибки будут связаны с разрешениями.
Ответ Тумана , sudo find . > files_and_folders, является кратким и прагматичным, но опрометчивый для любых других целей, чем просто печать имен файлов , по соображениям безопасности: потому что вы работаете в качестве корневого пользователя « , вы рискуете имея всю систему будучи перепутались ошибкой в находке или вредоносная версия, или неправильный вызов, который пишет что-то неожиданно, что не может произойти, если вы запустили это с обычными привилегиями »(из комментария к ответу тумана от tripleee ).
Второе решение в ответ viraptor в , find . 2>&1 | grep -v 'Permission denied' > some_fileработает риск ложных срабатываний ( в связи с отправкой сочетание стандартный вывод и стандартный поток ошибок по трубопроводу), и, возможно, вместо того, чтобы сообщать не являющихся -permission-ошибки отказа через STDERR, захватывает их вместе с выходными путями в выходном файле.
find . 2>&1 > files_and_folders | grep -v 'Permission denied' >&2:?