Составьте команду find из аргументов в сценарии оболочки, совместимом с POSIX.

Вопрос или проблема

Я хотел бы узнать, возможно ли написать совместимый с POSIX скрипт, который строит команду find из её аргументов.

Способ сделать это для Bash (и zsh) объясняется в этой другой статье SE, но она использует средства, специфичные для Bash (или zsh).

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

find -iname '*foo*' -o -iname '*bar*' -o -iname '*blah*'

Ответ представлен в следующем коде скрипта Bash:

findany() {
    local args=('-iname' "*$1*")
    shift

    while [ "$#" -gt 0 ]; do
        args+=('-o' '-iname' "*$1*")
        shift
    done

    find . "${args[@]}"
}

Возможно ли сделать что-то подобное в совместимом с POSIX скрипте?

В оболочках POSIX есть только один массив – массив аргументов. Вы могли бы использовать это здесь:

findany() {
    n=$#    # Сохранить исходное количество аргументов
    if [ "$n" -gt 0 ]
    then
        for arg # Цикл по аргументам функции
        do
            # Перезаписать аргументы с существующими аргументами + дополнительными опциями
            # с текущим обрабатываемым аргументом
            set -- "$@" -o -iname "*$arg*"
        done
        # Удалить исходный набор аргументов и `-o` после них,
        # оставив только `-iname ...` аргументы.
        shift $((n+1))
    fi
    # Передать аргументы `-iname ...`, если они есть, в find
    find . "$@"
}

Это должно работать и в bash, и в zsh.

Ответ или решение

Вопрос о том, возможно ли создать POSIX-совместимый скрипт для динамического построения команды find из аргументов, является интересной задачей для разработчиков, работающих с оболочками Unix. В данной статье мы подробно рассмотрим, как это можно сделать, следуя принципам POSIX, и, в частности, разберем реализацию функции findany.

Задача

Построить команду find, которая будет использовать оператор ИЛИ (-o) для поиска файлов с несколькими шаблонами имен. Например:

find -iname '*foo*' -o -iname '*bar*' -o -iname '*blah*'

Реализация POSIX-совместимого скрипта

В POSIX-совместимых оболочках, таких как sh, есть ограничение в использовании массивов, что требует другого подхода к построению команд. Мы можем использовать встроенную функцию set для управления списками аргументов.

Вот пример реализации функции findany, которая принимает список строк и динамически строит команду find:

findany() {
    n=$#  # Сохраняем первоначальное количество аргументов
    if [ "$n" -gt 0 ]; then
        for arg; do  # Пробегаем по всем аргументам функции
            # Используем set для добавления аргументов ИЛИ
            set -- "$@" -o -iname "*$arg*"
        done
        # Убираем оригинальные аргументы и оператор -o
        shift $((n + 1))
    fi
    # Передаем аргументы -iname в команду find
    find . "$@"
}

Объяснение работы функции

  1. Сохранение количества аргументов: Переменная n сохраняет количество аргументов, переданных функции. Это необходимо для дальнейшего управления аргументами.

  2. Итерация по аргументам: С помощью цикла for arg; do мы перебираем каждый аргумент, который будет передан функции.

  3. Построение команды: Внутри цикла мы используем set -- "$@" -o -iname "*$arg*" для добавления новых условий поиска. "$@" представляет собой текущий набор аргументов, а -o -iname "*$arg*" добавляет условие для поиска.

  4. Удаление оригинальных аргументов: После завершения итерации мы используем shift $((n + 1)) для удаления первоначальных аргументов и лишнего -o, оставляя только аргументы с -iname.

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

Пример использования

Теперь, чтобы использовать нашу функцию, мы можем выполнить следующие команды в оболочке:

$ findany foo bar blah

Это сгенерирует команду, аналогичную:

find . -o -iname '*foo*' -o -iname '*bar*' -o -iname '*blah*'

Заключение

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

Если у вас возникли дополнительные вопросы или требуется помощь в деталях реализации, не стесняйтесь обращаться за помощью.

Оцените материал
Добавить комментарий

Капча загружается...