Есть ли какая-нибудь причина для двойного проверки результатов `find -type -f` с помощью оператора` -f` bash?

В этом блоге я нашел сценарий bash (раздел «Snippets»), который содержит следующую структуру для исходных отдельных файлов из .bash_profile :

 if [ -d ~/.bash_profile.d ]; then for file in $( find ~/.bash_profile.d -type f ) do if [ -f "$file" ]; then source "$file" fi done fi 

Имеет ли смысл сначала фильтровать файлы с помощью find -type f а затем снова проверять их с помощью оператора bash -f или это какой-то пэчворк?

Не является ли следующий сценарий одинаковым?

 if [ -d ~/.bash_profile.d ]; then for file in $( find ~/.bash_profile.d -type f ) do source "$file" done fi 

Если нет, в чем разница?

6 Solutions collect form web for “Есть ли какая-нибудь причина для двойного проверки результатов `find -type -f` с помощью оператора` -f` bash?”

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

Во-первых, построение $() вокруг find ошибочно, как показывает @EricRenouf. Правильный способ сделать это – использовать что-то вроде

 while read filename do source $filename done < <(find ....) 

который вызывает find в подоболочке и читает имена файлов в переменной filename в основной оболочке (это find | while read x идеи find | while read x на голове, но, к сожалению, не такая портативная)

Во-вторых, тест каталога -d является избыточным; find не найдет никаких файлов, если каталог не существует, поэтому проверка его существования не имеет смысла.

Однако аргумент -type f для find не тестирует то же самое, что и аргумент -f для test . POSIX имеет следующие условия :

-f путь

Истина, если pathname разрешает существующую запись каталога для обычного файла. False, если pathname не может быть разрешен или если pathname разрешает существующую запись каталога для файла, который не является обычным файлом.

и это говорит о find :

Тип c

Первичный должен оцениваться как истинный, если тип файла c , где c – 'b', 'c', 'd', 'l', 'p', 'f' или 's' для специального файла блока , специальный файл символов, каталог, символическую ссылку, FIFO, обычный файл или сокет, соответственно.

Итак, если у вас есть обычный файл, который «не может быть разрешен», тогда у вас есть файл, для которого test -f будет терпеть неудачу, но find -type f будет успешным. Один из способов сделать это – иметь файл в каталоге, который вы можете прочитать, но доступ к которому вы не можете получить:

 wouter@gangtai:~$ ls -ld foo drw-r--r--. 2 wouter wouter 4096 apr 1 18:38 foo wouter@gangtai:~$ find foo -type f | while read file; do if [ -f $file ]; then echo $file tests -f; else echo $file does not test -f; fi; done foo/bar does not test -f wouter@gangtai:~$ ls -l foo ls: cannot access 'foo/bar': Permission denied total 0 -????????? ? ? ? ? ? bar 

Тип файла (будь то каталог, обычный файл или что-то еще) может быть обнаружен, если у вас есть r , но не x , разрешения в каталоге, в котором хранится файл. Однако, чтобы иметь возможность «разрешить» его (т. Е. Вызвать одну из функций stat() в этом файле), вам нужен бит разрешения x в этом каталоге.

Конечно, независимо от того, является ли выполнение такого теста в сценарии оболочки для вашего .bashrc вообще полезным, это другое дело. Я бы сказал, нет. Однако это не означает, что два теста одинаковы, и есть случаи, когда эта разница важна …

 for file in ~/.bash_profile.d/* 

Это не найдет файлы, начинающиеся с периода (.). Чтобы поймать крайние случаи, лучше сделать находку.

~/.bash_profile.d/* также будет перечислять любые подкаталоги, но не вводить их для получения файлов внутри них.
find с -type f будет исключать сами подкаталоги, а также вводит их и извлекает файлы из них. Кроме того, find будет включать скрытые файлы, которые ~/.bash_profile.d/* не будут.

Редактировать:

Проверка на [ -f "$file" ] избыточна.

Как правило, вы можете избежать многих проблем с помощью опции find -exec или даже с помощью xargs .

Тем не менее, поиск файла будет бесполезен в подоболочке, поэтому вам нужно использовать исходную оболочку.

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

Если вы хотите еще больше упростить, вы также можете удалить начальный тест, как если бы не был каталог с именем .bash_profile.d , в любом случае файлы под ним не могут быть:

 for file in $( find ~/.bash_profile.d -type f 2>/dev/null); do . $file done 

Возможно, вы захотите дважды проверить это, потому что вы обрабатываете вывод find , что означает, что на выходе будет разбито слово. Если find печатает имя, в котором есть пробел, тогда ваш $file на самом деле не пройдет тест -f , поскольку он будет просто частью имени файла.

Например:

 $ touch "~/.bash_profile.d/with space" $ for f in $( find ~/.bash_profile.d -type f 2>/dev/null );do printf -- "--%s--\n" "$f"; done --~/.bash_profile.d/with-- --space-- 

поэтому в этом случае, if [ -f "$f" ] не вернет true, так как $f не указывает на файл

Это еще один пример известной проблемы Do not Parse ls

Нет никакой веской причины для дополнительной проверки -f (кроме того, что упоминал Эрик), но есть логическая причина использовать проверку -x . Это гарантирует, что могут быть получены только исполняемые сценарии. Это позволяет легко отключать исходники без их удаления.

Повторяя мысли Эрика, выражение find ... -print ¦ while read file; do if test -x $file... find ... -print ¦ while read file; do if test -x $file... немного лучше, но, как показывает его ссылка на блог, это задыхается от файлов со встроенными символами новой строки. Мое возражение – это любой, кто достаточно глуп, чтобы вставлять новые строки в имена файлов UNIX, не должен разбираться в скриптах.

  • Можно ли изменить порядок глобуса?
  • Поиск шаблона в именах файлов с номером
  • Почему `find` иногда находит мой файл, иногда не
  • Как повернуть все изображения в каталоге с помощью imagemagick?
  • Bash скрывает скрытые файлы
  • Запретить расширение подстановочных знаков при поиске
  • Почему ls отображает несуществующий файл?
  • Почему моя находка не рекурсивна?
  • find * ищет файл с именем «*» на Debian, но не на RHEL
  • Почему ls. * Показывает разные файлы, чем ls ./.*?
  • Удалите все файлы отмены Vim во всех, кроме одного каталога
  • Linux и Unix - лучшая ОС в мире.