Wie kann ich mit einem Find, dem -exec fehlt, rekursiv Verzeichnisberechtigungen festlegen?

Wie kann ich mit einem Find, dem -exec fehlt, rekursiv Verzeichnisberechtigungen festlegen?

Mein Qnap NAS ist mit einem findBefehl 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 chmodein 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, xargswenn 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 awkoder 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 .findfind

Antwort1

Die Ausgabe von findgibt Dateinamen aus, die durch Zeilenumbrüche 1 getrennt sind . Dies ist nicht das gewünschte Format xargsund findes gibt keine Möglichkeit, das xargsgewünschte Format zu erzeugen: Es analysiert seine Eingabe als durch Leerzeichen getrennte Elemente, wobei \'"zum Anführen verwendet wird. Einige Versionen von xargskönnen durch Zeilenumbrüche getrennte Eingaben verarbeiten, aber wenn Ihrem finddie Standardoptionen fehlen, ist die Wahrscheinlichkeit groß, dass Ihr dies xargsauch tut.

find . -type d | xargs chmod g+sfunktioniert, 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 findund an der Weiterleitung an beteiligt chmod, sondern nur an xargs.

Wenn Ihr findhat -print0und Ihr xargshat -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 xargsComputer 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 findmit Dateinamen, die Zeilenumbrüche enthalten, ist mehrdeutig, außer in einem Fall, der schwierig zu analysieren ist: findgibt 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 .findxargs

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.

verwandte Informationen