Вынимание 'Доступа запрещен "Строки

Когда я использую find видеть все файлы PDF в /home каталог, я вижу access denied. Для устранения их, я попробовал:

find /home -iname "*.pdf" | grep -v "access denied"

Однако результатом является то же. Как я могу избавиться от этих строк?

9
задан 9 August 2017 в 05:03

3 ответа

То, что Вы попробовали, не работало, потому что эти access denied вывод является ошибками и отправленный на STDERR вместо STDOUT, который передается по каналу к grep.

можно постараться не видеть те ошибки путем перенаправления только STDERR

find /home -iname "*.pdf" 2>/dev/null

Или как , David Foerster прокомментировал , мы можем более кратко близкий STDERR

find /home -iname "*.pdf" 2>&-

Однако, я подозреваю, что Вы на самом деле только хотите искать свой дом, а не другие пользователи, поэтому возможно, Вы действительно хотите

find ~ -iname "*.pdf"

, Если это бросает ошибки в Вашей локальной конфигурации могут быть некоторые неправильные владения, которую необходимо исследовать.

19
ответ дан 23 November 2019 в 04:46

Доступ запрещен, вероятно, печатается на stderr, а не stdout.

Попытка это:

find /home -iname "*.pdf" 2>&1 | grep -v "access denied"
<час>

2>&1 перенаправления вывод от stderr до stdout, так, чтобы grep -v мог сделать его задание. (По умолчанию, | только каналы stdout а не stderr.)

8
ответ дан 23 November 2019 в 04:46

Вы, вероятно, имеете в виду "Разрешение, отклоненное" — который является что find на шоу Ubuntu Вы, когда Вы не можете получить доступ к чему-то из-за полномочий файла — а не "доступ запрещен".

Одно полностью общекомандное, которое делает это правильно (и, в качестве награды, является портативным к другому *, отклоняет, пока сообщение об ошибке является тем же):

(find 3>&1 1>&2 2>&3 3>&- | grep -Fv 'Permission denied') 3>&1 1>&2 2>&3 3>&-

(Обычно Вы хотите передать некоторые аргументы find. Они идут перед первым перенаправлением 3>&1.)

Однако часто Вы будете способный использовать что-то более простое. Например, можно, вероятно, использовать замену процесса. Детали следуют.

Наиболее распространенные методы и их ограничения

Два типичных подхода должны выбросить stderr (как в ответе Zanna) или перенаправить stderr к stdout и отфильтровать stdout (как в ответе Dev Android). Хотя они имеют преимущество того, чтобы быть простым записать и часто являются разумным выбором, эти подходы не идеальны.

Отбрасывание всего отправленного в stderr — такой как путем перенаправления его к пустому устройству с 2>/dev/null или путем закрытия его с 2>&-— рискует недостающими ошибками кроме "Отклоненного разрешения".

"Разрешение, отклоненное", является, вероятно, наиболее распространенной ошибкой, замеченной при выполнении find, но это далеко от единственной возможной ошибки, и если другой действительно происходит, можно хотеть знать об этом. В частности, find отчеты "Никакой такой файл или каталог", если начальная точка не существует. С несколькими начальными точками, find может все еще возвратить некоторые полезные результаты и, казаться, работает. Например, если a и c существуйте, но b не делает, find a b c -name x печать приводит к a, затем "Никакой такой файл или каталог" для b, затем результаты в c.

Объединение stdout и stderr вместе в stdout и передача по каналу его к grep или некоторая другая команда для фильтрации его — как с 2>&1 | grep ... или |& grep ...— рискует неумышленно отфильтровывать файл, имя которого содержит фильтруемое сообщение.

Например, если Вы отфильтруете строки, которые содержат "Разрешение, отклоненное то", затем Вы также отбросите результаты поиска, показывающие, что имена файлов как "Разрешение отклонили messages.txt". Это, вероятно, произошло бы случайно, хотя для файла также будет возможно быть данным специально обработанное имя для срыва поисков.

Фильтрация объединенных потоков имеет другую проблему, которая не может быть смягчена путем фильтрации более выборочно (такой как с grep -vx 'find: .*: Permission denied' на правой стороне канала). Некоторые find действия, включая -print действие, которое неявно, когда Вы не указываете действия, определите, как произвести имена файлов на основе того, является ли stdout терминалом.

  • Если это не терминал, то имена файлов производятся как есть, даже если они содержат странные символы как новые строки и управляющие символы, которые могли бы изменить поведение Вашего терминала. Если это - терминал, то эти символы подавлены и ? печатается вместо этого.
  • Это обычно, что Вы хотите. Если Вы собираетесь обработать имена файлов далее, они должны быть произведены буквально. Однако, если Вы собираетесь отобразить их, имя файла с новой строкой могло бы иначе подражать нескольким именам файлов, и имя файла с последовательностью символов возврата, могло казаться, было другим именем. Другие проблемы также возможны, таковы как имена файлов, содержащие escape-последовательности, которые изменяют цвета в Вашем терминале.
  • Но передавая результаты поиска по каналу посредством другой команды (как grep) причины find больше не видеть терминал. (Более точно это заставляет свой stdout не быть терминалом.) Затем странные символы производятся буквально. Но если вся команда на правой стороне канала делает (a) удаляют строки, которые похожи "На разрешение, отклоненное" сообщения и (b) печать, что оставляют, затем Вы все еще подвергаетесь виду интриг это findтерминальное обнаружение предназначается для предотвращения.
  • Посмотрите раздел UNUSUAL FILENAMES man find для получения дополнительной информации, включая поведение каждого из действий та печать имена файлов. ("Многие действия находки приводят к печати данных, которые находятся под контролем других пользователей..."), См. также разделы 3.3.2.1, 3.3.2.2, и 3.3.2.3 из справочника Findutils GNU.

Вышеупомянутое обсуждение необычных имен файлов принадлежит GNU, находят, который является find реализация в системах GNU/Linux включая Ubuntu.

Оставление в покое стандартного вывода при фильтрации стандартной погрешности

Что Вы действительно хотите, здесь должен оставить stdout неповрежденный при передаче по каналу stderr к grep. К сожалению, нет никакого простого синтаксиса для этого. | каналы stdout и некоторые оболочки (включая bash) поддержка |& для передачи по каналу обоих потоков — или можно перенаправить stderr к stdout сначала с 2>&1 |, который имеет тот же эффект. Но наиболее часто используемые оболочки не обеспечивают синтаксис для передачи по каналу stderr только.

Можно все еще сделать это. Это является просто неловким. Один путь состоит в том, чтобы подкачать stdout с stderr, так, чтобы результаты поиска были на stderr, и ошибки находятся на stdout, затем передают stdout по каналу к grep для фильтрации:

find args 3>&1 1>&2 2>&3 3>&- | grep -Fv 'Permission denied'

Обычно Вы будете передавать аргументы find, такой как начальные точки (места для поиска от, которые обычно являются каталогами), и предикаты (тесты и действия). Они идут вместо args выше.

Это работает путем представления нового дескриптора файла для содержания на один из двух стандартных потоков, которые Вы хотите подкачать, выполняя перенаправления для свопинга их, и закрывая новый дескриптор файла.

  • Дескриптор файла 1 является stdout, и 2 stderr (и неперенаправленным 0 является stdin). Но можно также перенаправить использование других дескрипторов файлов. Это может использоваться, чтобы открыть, или сохранить открытым, файл или устройство.
  • 3>&1 дескриптор файла перенаправлений 3 к stdout, так, чтобы, когда stdout (дескриптор файла 1) впоследствии перенаправляется, исходный stdout мог все еще быть записан в легко.
  • 1>&2 перенаправления stdout к stderr. Так как дескриптор файла 3 является все еще исходным stdout, к нему можно все еще получить доступ.
  • 2>&3 перенаправления stderr к дескриптору файла 3, который является исходным stdout.
  • 3>&- дескриптор файла завершений 3, который больше не необходим.
  • Для получения дополнительной информации посмотрите, Как передать stderr по каналу, и не stdout? и Перенаправление IO - Подкачивающий stdout и (Усовершенствованный) stderr и особенно передают по каналу только stderr через фильтр.

Однако этот метод имеет недостаток, который результаты поиска отправляются в stderr, и ошибки отправляются в stdout. Если Вы выполняете эту команду непосредственно в интерактивной оболочке и передаете по каналу или перенаправляете вывод дальше, то это действительно не имеет значения. Иначе это может быть проблема. Если Вы помещаете ту команду в сценарий, и затем кто-то (возможно, Вы, позже) перенаправляет или передает его вывод по каналу, она не ведет себя как ожидалось.

Решение состоит в том, чтобы подкачать потоки назад после того, как Вы будете сделаны, фильтруя вывод. Применение тех же перенаправлений, показанных выше на правой стороне конвейера, не достигнет этого, потому что | только каналы stdout, так, чтобы сторона конвейера только получила вывод, который был первоначально отправлен в stderr (потому что потоки были подкачаны), а не исходный вывод stdout. Вместо этого можно использовать ( ) для выполнения вышеупомянутой команды в (связанной) подоболочке затем примените перенаправления свопинга к этому:

(find args 3>&1 1>&2 2>&3 3>&- | grep -Fv 'Permission denied') 3>&1 1>&2 2>&3 3>&-

Это - группировка, не конкретно подоболочка, которая делает эту работу. Если Вы предпочитаете, можно использовать { ;}:

{ find args 3>&1 1>&2 2>&3 3>&- | grep -Fv 'Permission denied'; } 3>&1 1>&2 2>&3 3>&-

Менее громоздкий путь: замена процесса

Некоторые оболочки, включая Bash в системах, которые могут поддерживать его (включая системы GNU/Linux как Ubuntu), позволяют Вам выполнить замену процесса, которая позволяет Вам выполнять команду и перенаправление к/от одному из его потоков. Можно перенаправить find stderr команды к a grep управляйте, чтобы отфильтровал его, и перенаправьте это grep stdout команды к stderr.

find args 2> >(grep -Fv 'Permission denied' >&2)

Кредит переходит в к Android Dev для этой идеи.

Хотя bash поддержки обрабатывают замену, sh в Ubuntu dash, который не делает. Это даст Вам "Синтаксическую ошибку: перенаправление, неожиданное", при попытке использовать этот метод, тогда как метод свопинга stdout и stderr будет все еще работать. Кроме того, когда bash выполнения в режиме POSIX, поддержка замены процесса выключена.

Одна ситуация, где bash выполнения в режиме POSIX состоят в том, когда он вызывается как sh1. Поэтому на ОС как Fedora, где bash обеспечивает /bin/sh, или если Вы сделали /bin/sh точка символьной ссылки к bash самостоятельно на Ubuntu, замена процесса все еще не работает в sh сценарий, без предшествующей команды для выключения режима POSIX. Ваш лучший выбор, если Вы хотите использовать этот метод в сценарии, состоит в том, чтобы поместить #!/bin/bash наверху вместо #!/bin/sh, если Вы уже не.

1: В этой ситуации, bash включает режим POSIX автоматически после того, как он выполнит команды в своих сценариях запуска.

Пример

Полезно смочь протестировать эти команды. Чтобы сделать это, я создаю a tmp подкаталог текущего каталога и заполняет его с некоторыми файлами, и каталоги, убирая полномочия от одного из них для инициирования "Разрешения отклонили" ошибку в find.

mkdir tmp; cd tmp; mkdir a b c; touch w a/x 'a/Permission denied messages.txt' b/y c/z; chmod 0 b

Один из каталогов, который доступен, включает файл с "Разрешением, отклоненным" на его имя. Выполнение find без перенаправлений или каналов показывает этот файл, но также и показывает, что фактическое "Разрешение отклонило" ошибку для другого каталога, который не доступен:

ek@Io:~/tmp$ find
.
./a
./a/Permission denied messages.txt
./a/x
./c
./c/z
./w
./b
find: ‘./b’: Permission denied

Передача по каналу и stdout и stderr к grep и отфильтровывание строк, которые содержат "Разрешение, отклоненное", заставляет сообщение об ошибке уйти, но также и скрывает результат поиска для файла с той фразой на ее имя:

ek@Io:~/tmp$ find |& grep -Fv 'Permission denied'
.
./a
./a/x
./c
./c/z
./w
./b

find 2>&1 | grep -Fv 'Permission denied' эквивалентно и производит тот же вывод.

Методы, показанные выше для того, чтобы отфильтровать "Разрешение, отклоненное" только из сообщений об ошибках — а не от результатов поиска — успешны. Например, вот метод, где stdout и stderr подкачиваются:

ek@Io:~/tmp$ (find 3>&1 1>&2 2>&3 3>&- | grep -Fv 'Permission denied') 3>&1 1>&2 2>&3 3>&-
.
./a
./a/Permission denied messages.txt
./a/x
./c
./c/z
./w
./b

find args 2> >(grep -Fv 'Permission denied' >&2) производит тот же вывод.

Можно инициировать другое сообщение об ошибке, чтобы гарантировать, что строки, отправленные в stderr, которые не содержат текст "Разрешение, отклоненное", все еще позволяются через. Например, здесь я работал find с текущим каталогом (.) как одна начальная точка, но несуществующий каталог foo как другой:

ek@Io:~/tmp$ (find . foo 3>&1 1>&2 2>&3 3>&- | grep -Fv 'Permission denied') 3>&1 1>&2 2>&3 3>&-
.
./a
./a/Permission denied messages.txt
./a/x
./c
./c/z
./w
./b
find: ‘foo’: No such file or directory

Проверка этого findСтандартным выводом является Все еще Терминал

Мы можем также видеть, какие команды вызывают специальные символы, такие как новые строки, чтобы быть отображенными буквально. (Это может быть сделано отдельно от демонстрации выше, и это не должно быть в tmp каталог.)

Сделайте файл с новой строкой на ее имя:

touch $'abc\ndef'

Обычно мы используем каталоги в качестве начальных точек для find, но файлы работают также:

$ find abc*
abc?def

Передача по каналу stdout к другой команде заставляет новую строку быть произведенной буквально, создавая ложное впечатление от двух отдельных результатов поиска abc и def. Мы можем протестировать это с cat:

$ find abc* | cat
abc
def

Перенаправление просто stderr не вызывает эту проблему:

$ find abc* 2>/dev/null
abc?def

Ни делает закрытие его:

$ find abc* 2>&-
abc?def

Передача по каналу к grep действительно вызывает проблему:

$ find abc* |& grep -Fv 'Permission denied'
abc
def

(Замена |& с 2>&1 | эквивалентно и производит тот же вывод.)

Свопинг stdout и stderr и передача по каналу stdout не вызывают проблему —findstdout становится stderr, который не передается по каналу:

$ find abc* 3>&1 1>&2 2>&3 3>&- | grep -Fv 'Permission denied'
abc?def

Группировка той команды и свопинг потоков назад не вызывают проблему:

$ (find abc* 3>&1 1>&2 2>&3 3>&- | grep -Fv 'Permission denied') 3>&1 1>&2 2>&3 3>&-
abc?def

( { ;} версия производит тот же вывод.)

Используя замену процесса для фильтрации stderr не вызывает проблему также:

$ find abc* 2> >(grep -Fv 'Permission denied' >&2)
abc?def
4
ответ дан 23 November 2019 в 04:46

Другие вопросы по тегам:

Похожие вопросы: