Wie speichere ich Suchergebnisse in einer Variablen, damit ich sie vor dem Ändern anzeigen kann?

Wie speichere ich Suchergebnisse in einer Variablen, damit ich sie vor dem Ändern anzeigen kann?

Ich habe dieses Skript, das Dateien mit falschen Berechtigungen findet. Wenn welche gefunden werden, fragt es den Benutzer, ob er sie korrigieren oder anzeigen möchte. Die Suchergebnisse werden in einer Variablen gespeichert, um zu vermeiden, dass derselbe Befehl mehrmals ausgeführt wird:

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

Das Problem ist, dass chmodaufgrund der Zeilenumbrüche ein Fehler auftritt:

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

Wenn ich die Anführungszeichen darum entferne "$results", funktioniert es etwas besser, aber dann sind Dateinamen mit Leerzeichen natürlich problematisch.

Ich habe ein bisschen herumprobiert, IFS=$'\n'bin mir aber nicht sicher, wo ich das einstellen soll. Das hier scheint nicht zu funktionieren:

IFS=$'\n' chmod 644 $results

Dies hat jedoch folgende Auswirkungen:

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

Ich frage mich einfach, ob das richtig ist oder ob es einen besseren Weg gibt.

Antwort1

Die Einstellung IFSnur auf Zeilenumbrüche hilft, aber es bleiben immer noch die Probleme von 1) Dateinamen mit Zeilenumbrüchen (offensichtlich) und 2) Dateinamen mit Glob-Zeichen. Beispielsweise *würde eine aufgerufene Datei auf alle Dateinamen im Verzeichnis erweitert.

Verwenden Sie in Bash stattdessen mapfile/, readarrayum ein Array zu füllen:

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

Siehe auch:

Antwort2

Anstatt es IFSvorher zu setzen chmodund es sofort danach wieder zu entfernen, scheint es genauso gut zu funktionieren, wenn ich es vorher/nachher setze/entfernefind Undpacken Sie die Unterschale in ein Array, wie in den Kommentaren vorgeschlagen:

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

Auf diese Weise verfügt das Array über die richtige Anzahl von Elementen und chmod 644 "${results[@]}"funktioniert wie erwartet, solange keine Dateinamen Zeilenumbruchzeichen enthalten (obwohl ich mir nicht vorstellen kann, warum jemand so etwas absichtlich tun würde).

verwandte Informationen