Замена строки с использованием подстановочного знака в команде find

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

Я хочу исключить все файлы C, которые имеют соответствующий файл asm. Файлы сборки заканчиваются на _x86_64.S. Файлы C имеют одинаковые имена, но с .c вместо _x86_64.S в конце. Как мне сделать что-то вроде:

find . -not -name *{_x86_64.S but replace with .c}

Так, например, если существуют my_func.c и my_func_x86_64.S, то файл my_func.c будет исключен вышеуказанной командой.

Правка:
Ответ, предоставленный ниже, работает. Я забыл упомянуть, что использовал это в Makefile.
Вот что я делал:

ASM_FILES = $(shell find ./src/assembly/x86_64/ -name "*.S" -printf "-not -name \"*%f*\" -and ")
ASM_INCLUDE += -wholename "./src/assembly/x86_64/*.S" -or
EXCLUDE += $(subst _x86_64.S,.c,$(ASM_FILES))

Это работает, но я надеялся на что-то более чистое.

Что ж, что-то вроде [ -e "${1%.c}.asm" ] проверит, есть ли у файла .c, названного первым аргументом командной строки, соответствующий .asm.

Таким образом, помня, что -exec в команде find является условием, это можно использовать, чтобы распечатать все .c файлы без соответствующего .asm.

find . -name "*.c" -exec sh -c '! [ -e "${1%.c}.asm" ]' find-sh {} \; -print

Затем нам придется включить все остальное (предполагая, что вы хотите только обычные файлы), например:

find . -type f \( ! -name "*.c" -o
                  -name "*.c" -exec sh -c '! [ -e "${1%.c}.asm" ]' find-sh {} \; \
               \) -print

Например, учитывая четыре файла bar.c foo.asm foo.c hello.txt, это выведет:

./hello.txt
./foo.asm
./bar.c

Хотя это может быть немного медленно, так как для каждого .c файла создается новый экземпляр оболочки.

В качестве альтернативы, вы можете сделать это в цикле оболочки с использованием ** для рекурсивного сопоставления (нужна команда shopt -s globstar в Bash):

$ shopt -s globstar
$ for f in ./**/* ; do
    case $f in *.c)
        if [ -e "${f%.c}.asm" ]; then continue; fi
    esac;
    printf -- "%s\n" "$f"
  done
./bar.c
./foo.asm
./hello.txt

(Обратите внимание, что есть различия между оболочками в том, как ** работает с символьными ссылками внутри дерева.)

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

Чтобы выполнить задачу, заключающуюся в исключении всех файлов на языке C, соответствующих существующим файлам сборки с окончанием в формате _x86_64.S, можно воспользоваться командой find в комбинации с различными параметрами и условными операциями. Рассмотрим решение проблемы более подробно.

Шаг 1: Поиск файлов C

Для начала нужно найти все файлы с расширением .c. Команда выглядит следующим образом:

find . -name "*.c"

Шаг 2: Исключение файлов C с соответствующими asm файлами

Теперь необходимо исключить из этого списка те файлы, для которых существует файл с соответствующим именем, заканчивающим на _x86_64.S. Делается это с помощью команды find и проверки на существование.

Возможно использовать следующий подход:

find . -name "*.c" -exec sh -c 'for cfile; do 
    asmfile="${cfile%.c}_x86_64.S"; 
    [ ! -e "$asmfile" ] && echo "$cfile"; 
done' sh {} +

Здесь мы используем конструкцию -exec для вызова оболочки sh, в которую передаем все найденные файлы C. Для каждого файла осуществляется проверка существования соответствующего asm файла.

Шаг 3: Комбинирование с другими типами файлов

Если нужно вывести также и другие типы файлов (например, текстовые файлы или asm файлы), кроме .c, можно использовать следующую конструкцию:

find . -type f \( ! -name "*.c" -o -name "*.c" -exec sh -c 'for cfile; do 
    asmfile="${cfile%.c}_x86_64.S"; 
    [ ! -e "$asmfile" ] && echo "$cfile"; 
done' sh {} + \) -print

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

Разделение слежения за производительностью

Важно отметить, что такой подход может оказаться несколько медленным, поскольку для каждого файла .c создается новая оболочка, что увеличивает накладные расходы. В случае, если производительность имеет первостепенное значение, можно рассмотреть вариант с использованием циклов оболочки, что может быть выполнено с помощью globstar в bash. Например:

shopt -s globstar
for f in ./**/* ; do
    case $f in *.c)
        if [ -e "${f%.c}_x86_64.S" ]; then continue; fi
    esac
    printf -- "%s\n" "$f"
done

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

Выводы

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

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

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