Примечание:
* Этот ответ, вероятно, идет глубже, чем того требует вариант использования, и 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> >(...)
), по-видимому, игнорируется (в ksh 93u+
).
grep -v 'Permission denied'
filters out (-v
) all lines (from the find
command's stderr stream) that contain the phrase Permission denied
and outputs the remaining lines to stderr (>&2
).
Этот подход:
надежный: grep
применяется только к сообщениям об ошибках (а не к комбинации путей к файлам и сообщениям об ошибках, которые могут привести к ложным срабатываниям) и сообщениям об ошибках, кроме сообщений о разрешении - отклоненные передаются на stderr.
без побочных эффектов: код выхода find
сохраняется: невозможность доступа хотя бы к одному из обнаруженных элементов файловой системы приводит к коду выхода 1
(хотя это не скажет вам, были ли ошибки другие < / em>, чем произошло (тоже)).
POSIX-совместимые решения:
Решения, полностью совместимые с POSIX, либо имеют ограничения, либо требуют дополнительной работы.
Если выходные данные find
в любом случае должны быть сохранены в файле (или полностью исключены), тогда решение на основе конвейера из Ответ Джонатана Леффлера прост, надежен и соответствует стандарту POSIX:
find . 2>&1 >files_and_folders | grep -v 'Permission denied' >&2
Обратите внимание, что порядок перенаправления имеет значение: 2>&1
должен быть первым.
Предварительный захват вывода stdout в файл позволяет 2>&1
отправлять только сообщения об ошибках через конвейер, с которыми grep
может затем однозначно работать.
Единственным недостатком является то, что общим кодом выхода будет grep
команда, а не find
, что в данном случае означает: если ошибок нет при всех или только ошибках с отказом в разрешении код выхода будет 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) обобщение этого решения с использованием сложных перенаправлений strong>, который работает даже при стандартной печати путей к файлам в stdout:
{ find . 3>&2 2>&1 1>&3 | grep -v 'Permission denied' >&3; } 3>&2 2>&1
Вкратце: пользовательский дескриптор файла 3
используется для временного обмена местами stdout (1
) и stderr (2
), так что сообщения об ошибках одни могут передаваться на grep
через stdout.
Без этих перенаправлений сообщения об ошибках и данных (пути к файлам) , и будут передаваться grep
через стандартный вывод, и grep
не сможет различить сообщение об ошибке Permission denied
и сообщение (гипотетический) файл, в имени которого содержится фраза Permission denied
.
Однако, как и в первом решении, сообщается код выхода grep
, а не find
, но можно применить то же исправление, что и выше.
Примечания к существующим ответам:
Следует отметить несколько моментов относительно ответа Майкла Брюкса, find . ! -readable -prune -o -print
:
Для этого требуется GNU find
; в частности, он не будет работать на macOS. Конечно, если вам нужна команда только для работы с GNU find
, это не будет для вас проблемой.
Некоторые Permission denied
ошибки могут по-прежнему появляться: find ! -readable -prune
сообщает о таких ошибках для дочерних элементов каталогов, для которых текущий пользователь имеет r
разрешение, но не имеет разрешения x
(исполняемый файл). Причина в том, что поскольку сам каталог доступен для чтения, -prune
не выполняется, и попытка спуститься в этот каталог затем вызывает сообщения об ошибках. Тем не менее, в типичном случае отсутствует разрешение r
.
Примечание. Следующий пункт является вопросом философии и / или конкретного варианта использования, и вы можете решить, что он не имеет отношения к вам и что команда хорошо соответствует вашим потребностям, особенно если просто распечатать пути. все, что ты делаешь:
- If you conceptualize the filtering of the permission-denied error messages a separate task that you want to be able to apply to any
find
command, then the opposite approach of proactively preventing permission-denied errors requires introducing "noise" into the find
command, which also introduces complexity and logical pitfalls.
- Например, самый популярный комментарий к ответу Майкла (на момент написания этой статьи) пытается показать, как расширить команду, включив фильтр
-name
следующим образом:
find . ! -readable -prune -o -name '*.txt'
Это однако не работает должным образом, поскольку завершающее действие -print
является обязательным (объяснение можно найти в этот ответ). Такие тонкости могут привести к ошибкам.
Первое решение в ответе Джонатана Леффлера, find . 2>/dev/null > files_and_folders
, как он сам заявляет, слепо заставляет всех em> сообщения об ошибках (и обходной путь громоздкий и не полностью надежный, как он также объясняет). С прагматической точки зрения, однако, это простейшее решение, поскольку вы можете быть довольны предположением, что любые и все ошибки будут связаны с разрешениями.
ответ тумана, sudo find . > files_and_folders
, краток и прагматичен, но не рекомендуется для чего-либо, кроме простой печати имена файлов, по соображениям безопасности: поскольку вы работаете от имени пользователя root, "вы рискуете испортить всю вашу систему из-за ошибки в find или вредоносной версии. , или неправильный вызов, который пишет что-то неожиданно, чего не могло бы произойти, если бы вы запустили это с обычными привилегиями "(из комментария к ответу mist от Tripleee).
Второе решение в ответе viraptor, find . 2>&1 | grep -v 'Permission denied' > some_file
подвержено риску ложных срабатываний (из-за отправки смеси stdout и stderr через pipeline), и, возможно, вместо того, чтобы сообщать об ошибках, non -permission-denied (отказано в разрешении) через stderr, захватывает их вместе с путями вывода в выходной файл.
person
mklement0
schedule
31.10.2016