Как эффективно использовать команду find? пожалуйста, помогите мне?

Код, который вы разместили [[ ! -z $param ]] && echo "I am not zero", будет печатать I am not zero, если параметр не установлен/не определен или пуст (в bash, ksh и zsh ).

Для также печатать, если параметр содержит только пробелы (удалить пробелы ), POSIXly (для более широкого диапазона оболочек):

 [   -z "${param#"${param%%[! ]*}"}"   ] && echo "empty"

Пояснение:

  • ${param# … }удаляет начальный текст.
  • Этот ведущий текст дан:${param%%[! ]*}
  • Который расширяется до всех пробелов перед любым не -пробелом символом, то есть всеми ведущими пробелами.

Конечным результатом всего расширения является удаление всех ведущих пробелов.

Этот расширенный результат проверяется, если его длина равна 0.

  • Если результат пустой, то либо переменная была пустой, либо
  • удаление начальных пробелов сделало его пустым.

Следовательно, если проверка верна, переменная либо уже была пустой, либо содержала только пробелы внутри.


Эту концепцию легко распространить на другие типы символов. Чтобы также включить вкладки, поместите явную вкладку внутри выражения в квадратных скобках :

.
 [ -z "${param#"${param%%[!     ]*}"}" ] && echo "empty"

или используйте переменную с удаленными символами, которые вам нужны:

 var=$' \t'                                    # in ksh, bash, zsh
 [ -z "${param#"${param%%[!$var]*}"}" ] && echo "empty"

или вы можете использовать некоторое «выражение класса символов» POSIX (пробел означает пробел и табуляцию):

 [ -z "${param#"${param%%[![:blank:]]*}"}" ] && echo "empty"
-2
06.03.2021, 23:29
2 ответа

Q1. Что означает -print0, зачем это нужно?

Лучше всего начать с руководства. В терминале вы можете набрать man findи получить хорошее описание. Как правило, вы также можете просто погуглить «найти человека» и найти те же / похожие страницы руководств в Интернете.

В руководстве по поиску говорится о-print0:

print the full file name on the standard output, followed by a null character (instead of the newline character that -print uses). This allows file names that contain newlines or other types of white space to be correctly interpreted by programs that process the find output.

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

Q2.Почему /bin/ ? почему бы просто не rm -f ?

Из вашего вопроса непонятно, почему это было сделано.

Похоже, для этого нет веских причин. Иногда это делается для того, чтобы позволить вам запустить комментарий, когда переменная окружения PATH установлена ​​неправильно. Это может быть обычным явлением при запуске команд в cron.

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

 /bin/find ~ -name delete_me -type f -print0 | /usr/xargs -0 /bin/rm -f

Единственная другая (весьма маловероятная )причина может заключаться в том, что в вашей системе каким-то образом есть две разные rmкоманды, и вам нужно указать, какая именно. Но это действительно очень маловероятно.

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

Он уже делает это.

В4. Как изменить его так, чтобы он не находил в определенном каталоге?

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

# Just editing your version...
find "$HOME" -name exclude_this_dir -prune -o -name delete_me -type f -print0 | xargs -0 /bin/rm -f

# More succinctly
find "$HOME" -name exclude_this_dir -prune -o -name delete_me -type f -exec rm -f {} +
1
18.03.2021, 22:26
  1. Нестандартный -предикат -print0означает «печатать путь к найденному файлу с завершающим нулевым символом в конце вместо символа новой строки». Это сделано для того, чтобы иметь возможность обрабатывать имена файлов, содержащие символы новой строки (, что разрешено в системах Unix; Однако символы nul не могут быть частью имени файла Unix ). Команда, читающая вывод команды find, которая использует -print0, должна знать, что записи завершаются нулем -. Это опция -0для xargs, которая позволяет читать записи с нулевым завершением -.

    Не требуется. Ни один из

    find "$HOME" -name delete_me -type f -delete
    

    ни более стандартный

    find "$HOME" -name delete_me -type f -exec rm {} +
    

    использует -print0. Обе команды делают то же самое, что и ваша команда, и их следует использовать вместо xargs. Утилита xargsможет оказаться полезной при чтении аргументов из файла или какой-либо другой команды. При использовании findбезопаснее использовать встроенное средство -exec. Там есть несколько вещей, которые некоторые реализации xargsмогут делать, но -execне могут, например запуск параллельных пакетов утилит. Однако в данном упражнении он не используется.

    Также предпочтительнее использовать "$HOME"вместо ~в сценариях оболочки, поскольку $HOMEведет себя как переменная, а ~— нет.

    Также обратите внимание, что опция -fдля rm, вероятно, не нужна. Он используется, чтобы избежать сбоя утилиты rm(с диагностическим сообщением и не -нулевым статусом выхода ), если указанные пути отсутствуют или если rmвызывается без пути для удаления. Он также переопределяет все более ранние-i(параметры интерактивного режима ). Но здесь нет опции -iв командной строке rm,и данные пути гарантированно существуют, так как findиспользуется для их поиска (, исключая условия гонки, когда файлы фактически удаляются во время выполнения findкаким-либо другим процессом между тем, когда они были найдены findи удаляется rm, выполненным из find).

  2. Нет причин использовать rmс полным путем, за исключением случаев, когда нельзя гарантировать, что значение переменной PATHсодержит разумный набор путей к утилитам. Ненормально иметь сломанный PATH, и сценарии написания, которые используют абсолютные пути для утилит, склонны ломаться, когда они перемещаются в другие системы.

  3. Он уже выполняет рекурсию во все подкаталоги вашего домашнего каталога.

  4. Удалите каталог, который вы хотите исключить из дерева поиска. Например, чтобы избежать всех каталогов с именемavoid:

    find "$HOME" -name avoid -prune -o -name delete_me -type f -exec rm {} +
    

    Обратите внимание, что мы не можем использовать здесь -delete, так как это подразумевает -depth, то есть поиск в глубину -сначала. При первом поиске в глубину -мы посетим все подкаталоги и файлы внутри avoid, прежде чем заметим, что каталог avoidдолжен быть удален из дерева поиска.

    Другой пример :Не входить в определенный каталог $HOME/dir/save_me:

    find "$HOME" -path "$HOME/dir/save_me" -prune -o -name delete_me -type f -exec rm {} +
    
2
18.03.2021, 22:26

Теги

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