
В настоящее время у меня есть эта команда, которая успешно выводит каждое имя файла на отдельной строке:
find . -exec echo {} \;
Я пытаюсь разделить логику так, чтобы find
команда выполняла функцию. На основеэтот вопросЯ попробовал это:
my_function() {
echo $1
}
export -f my_function
find . -exec bash -c 'my_function "$@"' bash {} +
Затем я получаю такой вывод:
.
Я также пробовал заменить $@
на $*
, но это приводит к тому $1
, что каждый файл будет без переносов строк. Я хотел бы запустить логику, которая проверяет каждый файл, поэтому я хотел бы $1
просто быть одним файлом за раз. Я пробовал разделять вывод пробелами через , for file in $1
но это не работает для файлов, в имени которых есть пробелы. Как мне запустить функцию Bash для каждого файла, найденного командой find
?
EDIT: Вот весь скрипт, который я использую. Кажется, он работает нормально.
# Ensures that non-csproj text files are formatted with LF line endings.
format() {
for pathname do
if [[ $pathname == *"git"* ]]; then
continue
elif [[ $pathname == *"csproj"* ]]; then
continue
fi
dos2unix $pathname
done
}
export -f format
find . -exec bash -c 'format "$@"' bash {} \;
решение1
Для запуска dos2unix --newline
каждого обычного файла в текущем каталоге и ниже, избегая любых файлов, имя которых содержит строку git
:
find . -type f ! -name '*git*' -exec dos2unix --newline {} +
То есть, найти все обычные файлы, имена которых не соответствуют шаблону *git*
, и запустить dos2unix --newline
их все в максимально больших пакетах одновременно. Измените ! -name '*git*'
на ! -path '*git*'
, чтобы избежать любого файла, чье имя пути содержит строку git
(например, файлы в .git
каталогах).
Чтобы явно избегать любых .git
каталогов, но включать все, что может содержать git
в своем названии:
find . -name .git -prune -o -type f -exec dos2unix --newline {} +
Это останавливает find
даже вход в любой каталог, вызываемый .git
с помощью -prune
удаления таких путей из дерева поиска.
Ответьте на вопрос перед редактированием:
Ваша функция выводит только свой первый аргумент. Точка — это путь поиска верхнего уровня, который вы используете с find
. Он передается, поскольку вы не выполняете никакой особой фильтрации записей каталога (как, например, -type f
для обычных файлов только, или -name
, или любого другого типа find
теста).
Если вы хотите, чтобы ваша функция вывела каждый из своих аргументов, используйте либо
my_function() {
printf '%s\n' "$@"
}
что позволяет printf
вывести каждый из аргументов с новой строкой между ними, или
my_function() {
for pathname do
printf '%s\n' "$pathname"
done
}
который перебирает аргументы и вызывается printf
один раз для каждого.
Ожидается, что это будет работать правильно, если вы вызовете функцию следующим образом:
my_function "$@"
из вашего встроенного bash -c
скрипта. "$@"
Расширяется до всех аргументов, данных скрипту, индивидуально заключенных в кавычки.
Другой способ — перенести цикл в bash -c
скрипт:
for pathname do
my_function "$pathname"
done
и затем иметь
my_function () {
printf '%s\n' "$1"
}
Это будет явно делать то, что вы хотите сделать, т.е. вызывать функцию один раз для каждого имени пути.
Тогда команда find
будет выглядеть так:
find . -exec bash -c 'for pathname do my_function "$pathname"; done' bash {} +
или, возможно, немного более читабельно,
find . -exec bash -c '
for pathname do
my_function "$pathname"
done' bash {} +
Это, кстати, было бы то же самое, что
shopt -s globstar nullglob dotglob
for pathname in ./**/*; do
my_function "$pathname"
done
за исключением того, что это .
не будет обработано. Используя это, вам не придется экспортировать вашу my_function
функцию.
С циклом внутри функции (как в первых двух фрагментах кода в этом ответе) это можно сократить до
shopt -s globstar nullglob dotglob
my_function ./**/*