Executando uma função Bash para cada arquivo encontrado com o comando find

Executando uma função Bash para cada arquivo encontrado com o comando find

Atualmente tenho este comando, que imprime com sucesso cada nome de arquivo em sua própria linha:

find . -exec echo {} \;

Estou tentando dividir a lógica para que o findcomando execute uma função. Baseado emessa questãoEu tentei isso:

my_function() {
    echo $1
}
export -f my_function
find . -exec bash -c 'my_function "$@"' bash {} +

Então recebo esta saída:

.

Também tentei substituir $@por, $*mas isso faz com $1que todos os arquivos fiquem sem quebras de linha. Eu gostaria de executar uma lógica que verificasse cada arquivo, então gostaria $1de ser apenas um arquivo por vez. Tentei dividir a saída com espaços, for file in $1mas isso não funciona para arquivos que possuem espaços no nome do arquivo. Como executo uma função Bash para cada arquivo encontrado pelo findcomando?

EDIT: Aqui está todo o script que estou usando. Parece funcionar bem.

# 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 {} \;

Responder1

Para executar dos2unix --newlineem todos os arquivos regulares dentro e abaixo do diretório atual, evitando qualquer arquivo cujo nome contenha a string git:

find . -type f ! -name '*git*' -exec dos2unix --newline {} +

Ou seja, encontre todos os arquivos regulares cujos nomes não correspondam ao padrão *git*e execute dos2unix --newlinetodos eles em lotes tão grandes quanto possível de uma só vez. Mude ! -name '*git*'para ! -path '*git*'para evitar qualquer arquivo cujo caminho contenha a string git(por exemplo, arquivos em .gitdiretórios).

Para evitar explicitamente quaisquer .gitdiretórios, mas para incluir qualquer outra coisa que possa ter gitem seu nome:

find . -name .git -prune -o -type f -exec dos2unix --newline {} +

Isso impede findaté mesmo que você entre em qualquer diretório chamado .gitusando -prunepara excluir esses caminhos da árvore de pesquisa.


Responda antes de editar a pergunta:

Sua função imprime apenas o primeiro argumento. O ponto é o caminho de pesquisa de nível superior que você usa com o find. Ele é aprovado porque você não faz nenhuma filtragem específica das entradas do diretório (como, por exemplo, -type fapenas para arquivos regulares, ou -name, ou qualquer outro tipo de findteste).

Se você quiser que sua função imprima cada um de seus argumentos, use

my_function() {
    printf '%s\n' "$@"
}

que permite printfimprimir cada um dos argumentos com uma nova linha no meio, ou

my_function() {
    for pathname do
        printf '%s\n' "$pathname"
    done
}

que percorre os argumentos e chama printfuma vez para cada um.

Espera-se que isso funcione corretamente se você chamar a função como

my_function "$@"

de dentro do seu script in-line bash -c. O "$@"expande-se para todos os argumentos dados ao script, citados individualmente.

Outra maneira seria mover o loop para o bash -cscript:

for pathname do
    my_function "$pathname"
done

e então ter

my_function () {
    printf '%s\n' "$1"
}

Isso seria explicitamente fazer o que você diz que gostaria de fazer, ou seja, chamar a função uma vez para cada nome de caminho.

O findcomando seria então parecido com

find . -exec bash -c 'for pathname do my_function "$pathname"; done' bash {} +

ou, possivelmente um pouco mais legível,

find . -exec bash -c '
    for pathname do
        my_function "$pathname"
    done' bash {} +

Isto seria, aliás, o mesmo que

shopt -s globstar nullglob dotglob

for pathname in ./**/*; do
    my_function "$pathname"
done

exceto que .não seria processado. Usando isso, você não precisaria exportar sua my_functionfunção.

Com o loop dentro da função (como nos dois primeiros trechos de código desta resposta), isso seria abreviado para

shopt -s globstar nullglob dotglob

my_function ./**/*

informação relacionada