find: ничего не делать, если не указано ни одного файла

find: ничего не делать, если не указано ни одного файла

Я хочу вызвать use findдля некоторых имен файлов.

find $(do_something to find filenames) -print0 | xargs -r0 ls -ld

Это прерывает работу, если $(do_something to find filenames)ничего не возвращает: команда find начинает выполнять рекурсивный поиск.

Есть ли способ заставить find ничего не делать, если в качестве аргумента не указано явное имя файла/каталога?

решение1

С zsh, я бы сделал:

files=($(do_something to find filenames))
(($#files)) && find $files ...

С tcsh:

set files=(`do_something to find filenames`)
if ($#files) find $files:q ...

С bash, mkshили ksh93,

set -f; files=($(do_something to find filenames))
((${#files[@]})) && find "${files[@]}" ...

POSIXly:

set -f; set -- $(do_something to find filenames)
[ "$#" -gt 0 ] && find "$@" ...

(в bash и других оболочках POSIX $(...)разделяет ( $IFSпо умолчанию по пробелу, табуляции и новой строке), но также выполняет подстановку результирующих слов, что, как я ожидаю, вам здесь не понадобится, отсюда и set -f. В других оболочках ((t)csh, zsh, fish, rc, es...) такой проблемы нет).

решение2

Как насчет того, чтобы сделать это:

paths=$(do_something to find filenames)
if [ "$paths" ]; then
    find "$paths" ...
fi

Это работает независимо от findреализации.

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

dofind() {
    set -f
    set -- $(do_something to find filenames)
    if [ $# -gt 0 ]; then
        find "$@" ...
    fi
    set +f
}

Он отключает подстановку файлов и затем использует set --для установки вектора аргументов оболочки. Это работает с любой оболочкой POSIX.

решение3

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

find " " $(do_something to find filenames) -print0 | xargs -r0 ls -ld

Чтобы сделать это аккуратнее, удалите findвывод ошибок:

find " " $(do_something to find filenames) -print0 2>/dev/null | xargs -r0 ls -ld

(но тогда вы не заметите, если возникнет еще одна ошибка...).

Когда do_something to find filenamesвыводит имена файлов, findбудет жаловаться " ", но все равно обработает остальную часть командной строки. Когда имена файлов не выводятся, findснова будет жаловаться, " "но не добавит свой default ..

решение4

В zsh(и большинстве не-Bourne-производных оболочек), когда a (иливсев зависимости от оболочки)шарне расширяется, команда прерывается.

$(do_something to find filenames)не является глобом, но вы можете сделать его таковым, добавив квалификатор глобуса в zsh:

 find $(do_something to find filenames)(#q) -print0...

Выше, это (#q)(пустой квалификатор glob, так что ничего не делает в противном случае) добавляется к последнему слову, полученному в результате разделения вывода do_something to find filenames, поэтому команда будет прервана, если эта команда не даст (или даст пустой) вывод, но также если это последнее слово (и только это последнее слово) не разрешается в существующий путь. Вы можете применить это к каждому слову, полученному в результате этого разделения (так что команда будет прервана, если любое из этих слов не разрешается в существующий файл) с помощью:

 find ${^$(do_something to find filenames)}(#q) -print0...

Связанный контент