Como armazeno resultados de busca em uma variável para poder exibi-los antes de modificá-los?

Como armazeno resultados de busca em uma variável para poder exibi-los antes de modificá-los?

Eu tenho esse script que encontra arquivos com permissões incorretas. Se algum for encontrado, ele pergunta ao usuário se deseja corrigi-lo ou mostrá-lo. Os resultados da descoberta são armazenados em uma variável para evitar a execução do mesmo comando várias vezes:

#!/usr/bin/env sh

results=$(find "$0" -type f -not -perm 644)

if [ -z "$results" ]; then
    echo 'No files with incorrect permissions found'
else
    while true; do
        read -p 'Fix files with incorrect permissions? (yes/no/show) ' ans
        case "$ans" in
            Y | y | yes)
                echo 'Changing file permissions...'
                chmod 644 "$results"
                break;;
            N | n | no)
                break;;
            S | s | show)
                echo "$results";;
            *)
                echo 'Please answer yes or no';;
        esac
    done
fi

O problema chmodgera um erro devido às novas linhas:

chmod: cannot access 'test/foo'$'\n''test/bar'$'\n''test/foo bar': No such file or directory

Se eu remover as aspas "$results", funciona um pouco melhor, mas é claro que nomes de arquivos contendo espaços são problemáticos.

Tenho brincado, IFS=$'\n'mas não tenho certeza de onde devo definir isso. Isso não parece funcionar:

IFS=$'\n' chmod 644 $results

No entanto, isso faz:

IFS=$'\n'
chmod 644 $results
unset IFS

Acho que só estou me perguntando se isso está correto ou se existe uma maneira melhor.

Responder1

Definir IFSapenas novas linhas ajuda, mas ainda deixa problemas de 1) nomes de arquivos com novas linhas (obviamente) e 2) nomes de arquivos com caracteres glob. Por exemplo, um arquivo chamado *seria expandido para todos os nomes de arquivos no diretório.

No Bash, use mapfile/ readarraypara preencher um array:

mapfile -d '' files < <(find . -type f ! -perm 0644 -print0)
printf "%d matching files found\n" "${#files[@]}"
printf "they are:\n"
printf "  %q\n" "${files[@]}"

Veja também:

Responder2

Em vez de armar IFSantes chmode desarmar imediatamente depois, parece funcionar igualmente bem se eu armar/desarmar antes/depoisfind eenvolva o subshell em uma matriz, conforme sugerido nos comentários:

IFS=$'\n'
results=($(find "$0" -type f -not -perm 644))
unset IFS

Dessa forma, o array tem o número correto de itens e chmod 644 "${results[@]}"funciona conforme o esperado, desde que não haja nomes de arquivos contendo caracteres de nova linha (embora eu não consiga imaginar por que alguém faria isso de propósito).

informação relacionada