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 chmod
aufgrund 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 IFS
nur 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
/, readarray
um 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 IFS
vorher zu setzen chmod
und 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).