
Mein Qnap NAS ist mit einem find
Befehl geplagt, dem der Parameter fehlt -exec
, also muss ich irgendwohin weiterleiten. Die Shell ist: GNU bash, Version 3.2.57(2)-Release-(arm-unknown-linux-gnueabihf)
Ich versuche, das Setgid-Bit für alle Unterverzeichnisse (nicht Dateien) des aktuellen Verzeichnisses zu setzen.
Das funktioniert nicht:
find . -type d | xargs chmod g+s $1
Die Verwendung von "$1"
, "$(1)"
, $("1")
usw. funktioniert auch nicht. Sie alle weisen darauf hin, dass chmod
ein Verzeichnisname mit Leerzeichen als zwei oder mehr Parameter übergeben wird (es gibt seine Standardhilfemeldung darüber aus, welche Parameter unterstützt werden).
Ich verwende es nicht, xargs
wenn es nicht unbedingt sein muss. Ich finde, bei langen Namen würgt es sowieso, oder?
Diese und Varianten davon funktionieren nicht:
find . -type d | chmod g+s
find . -type d | chmod g+s "$1"
Ich habe überlegt, Anführungszeichen mit awk
oder einzufügen, aber ich muss mir vorstellen, dass es dafür einen einfacheren Weg gibt. Was haben die Leute vorher gemacht ? (Das Traurige ist, dass ich es wahrscheinlich schon 1995 oder so wusste, es aber längst vergessen habe.)sed
-exec
PS: Einige dieser Verzeichnisnamen enthalten Unicode-Zeichen, das ?
Symbol usw. Sie stammen ursprünglich aus macOS, das ziemlich freizügig ist. Trotzdem sollte ich wahrscheinlich alle ?
Instanzen durch etwas wie das Unicode-Zeichen ersetzen, damit Windows nicht daran erstickt. Aber das wird auch mit dieser Crippleware-Version von ⁇
einen ähnlichen Vorgang erfordern .find
find
Antwort1
Die Ausgabe von find
gibt Dateinamen aus, die durch Zeilenumbrüche 1 getrennt sind . Dies ist nicht das gewünschte Format xargs
und find
es gibt keine Möglichkeit, das xargs
gewünschte Format zu erzeugen: Es analysiert seine Eingabe als durch Leerzeichen getrennte Elemente, wobei \'"
zum Anführen verwendet wird. Einige Versionen von xargs
können durch Zeilenumbrüche getrennte Eingaben verarbeiten, aber wenn Ihrem find
die Standardoptionen fehlen, ist die Wahrscheinlichkeit groß, dass Ihr dies xargs
auch tut.
find . -type d | xargs chmod g+s
funktioniert, solange Ihre Verzeichnisnamen keine Leerzeichen oder enthalten \'"
. Beachten Sie, dass es kein $1
: gibt, das für eine Shell von Bedeutung ist, aber keine Shell ist am Parsen der Ausgabe von find
und an der Weiterleitung an beteiligt chmod
, sondern nur an xargs
.
Wenn Ihr find
hat -print0
und Ihr xargs
hat -0
, können Sie diese Optionen verwenden, um durch NULL getrennte Dateinamen zu übergeben, was mit beliebigen Dateinamen funktioniert.
find . -type d -print0 | xargs -0 chmod g+s
Wenn Ihr xargs
Computer die Standardoption unterstützt -I
, können Sie ihn damit anweisen, jede Zeile als Element zu verarbeiten, anstatt als durch Leerzeichen getrennte, in Anführungszeichen gesetzte Zeichenfolgen. Dies funktioniert mit Leerzeichen, aber nicht mit \"'
oder Zeilenumbrüchen.
find . -type d | xargs -I {} chmod g+s {}
Sie können die Shell verwenden, um über Zeilen zu schleifen, anstatt xargs
. Dies funktioniert für alle Dateinamen, die keine Zeilenumbruchzeichen enthalten.
find . -type d | while IFS= read -r line; do chmod g+s "$line"; done
Beide Lösungen funktionieren nur bei Dateinamen, die keine Zeilenumbruchzeichen enthalten. Die Ausgabe von find
mit Dateinamen, die Zeilenumbrüche enthalten, ist mehrdeutig, außer in einem Fall, der schwierig zu analysieren ist: find
gibt nicht spontan mehrere Schrägstriche aus, sodass Sie dies in der Ausgabe erkennen können, wenn Sie den Pfad zum zu durchlaufenden Verzeichnis eingeben . Hier ist ein minimal getesteter Code, der diese Tatsache nutzt, um die Ausgabe von in das Eingabeformat von //
zu konvertieren .find
xargs
chars=$(printf '\t "'\\\')
{ find .//. -type d; echo .// } | LC_ALL=C sed -n '
s/['"$chars"']/\\&/g
/^\.\/\// {
x
s/\n/\\&/g
p
b
}
H' | LC_ALL=C xargs chmod g+s
1 Genauer gesagt: durch Zeilenumbrüche beendet (nach dem Nachnamen kommt ein Zeilenumbruch).
Antwort2
Sie können die Rekursion selbst mit Bash durchführen. So etwas wie:
shopt -s nullglob dotglob
recurse_chmod () (
cd "$1"
for d in ./*/
do
if [ -L "$d" ]; then continue; fi
chmod g+s "$d"
recurse_chmod "$d"
done
)
recurse_chmod .
Antwort3
Sie können xargs anweisen, \0 als Trennzeichen zu verwenden.find . -type d -print0 | xargs -0 chmod g+s
oder
find . -type d | xargs -I{} -d '\n' chmod g+s "{}"
. Es wird \n als Trennzeichen verwendet.