検索結果を変数に保存して、変更する前に表示できるようにするにはどうすればよいでしょうか?

検索結果を変数に保存して、変更する前に表示できるようにするにはどうすればよいでしょうか?

不正な権限を持つファイルを検索するスクリプトがあります。 不正な権限を持つファイルが見つかった場合、ユーザーに修正するか表示するかを尋ねます。 検索結果は、同じコマンドを複数回実行しないように、変数に保存されます。

#!/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

問題は、chmod改行が原因でエラーが発生することです。

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

を囲む引用符を削除すると"$results"、少しは改善されますが、もちろん、スペースを含むファイル名は問題になります。

いろいろ試してみましたIFS=$'\n'が、どこに設定すればいいのかわかりません。これはうまくいかないようです:

IFS=$'\n' chmod 644 $results

ただし、次のようになります:

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

これが正しいのか、あるいはもっと良い方法があるのだろうかと疑問に思っているだけだと思います。

答え1

改行だけに設定するIFSと役立ちますが、1) 改行を含むファイル名 (当然)、および 2) glob 文字を含むファイル名の問題は依然として残ります。たとえば、 というファイルは、*ディレクトリ内のすべてのファイル名に展開されます。

Bash では、代わりにmapfile/ を使用しreadarrayて配列を設定します。

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

参照:

答え2

IFS事前に設定して直後に設定解除するのではなくchmod、前/後に設定/解除しても同じように機能するようです。find そしてコメントで提案されているように、サブシェルを配列でラップします。

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

この方法では、配列には正しい数の項目が含まれ、chmod 644 "${results[@]}"改行文字を含むファイル名がない限り、期待どおりに動作します (ただし、誰かがわざとこのようなことを行う理由は想像できません)。

関連情報