Ich bin etwas verwirrt darüber, wie Leerzeichen in Pfadnamen behandelt werden sollen, wenn sie in einer for-Schleife zurückgegeben werden.
Begründung: Ich bereinige die Berechtigungen für Ordner und Dateien, die ich von Windows kopiere. Die meisten Dateien haben -rwx------
oder -rwxr-xr-x
Berechtigungen, daher mache ich gerne " chmod -x *
" und dann " chmod u+x <folders>
", also versuche ich Folgendes:
$ alias getdirs='find . -maxdepth 1 -mindepth 1 -type d | cut -c 3-'
$ for i in $(getdirs); do chmod u+x $i; done
Das funktioniert gut, solange die Verzeichnisse kein Leerzeichen im Namen haben.
Ich habe verschiedene Permutationen versucht chmod u+x "$i"
, chmod u+x '$i'
und ähnliches , das Verhalten zu bekommen ich wollte, aber ohne Erfolg.
Wie kann ich meinen Bash-Code verbessern, der mit Ordnernamen funktioniert, die Leerzeichen enthalten?
Der Zweck davon ist, das "exec" -Bit aus einfachen Dateien (daher der chmod -x *
Teil) entfernen zu können, es dann aber in den Verzeichnissen wiederherzustellen, um den Zugriff darauf zu ermöglichen ( chmod u+x <dirname>
). Aufgrund der bisherigen Kommentare und Antworten denke ich, dass es wahrscheinlich einfacher sein wird, mit der richtigen Beschwörung "Finden" umzugehen
find
undsed
undawk
usw. auf wenige Schritte reduziert werden können, viele weniger erfahrene Shell-Bastler finden die Befehlsketten im Flowchart-Stil besser lesbar und verständlicher.Antworten:
Diese Art von Dingen kann in allen Unix-Shells schwierig sein, da der Speicherplatz als Trennzeichen fungiert. Das Ausführen von Aliasnamen als Teil von Shell-Skripten macht die Dinge nur noch interessanter. Ich würde wahrscheinlich zwei Suchdurchläufe ausführen, um zuerst die Verzeichnisse in der richtigen Reihenfolge und dann die Dateien festzulegen:
quelle
find . -maxdepth 1 -mindepth 1 -type f -exec chmod u-x '{}' \;
Im Allgemeinen besteht die "richtige" Methode zum Analysieren der Ausgabe von find in einer Bash-Schleife darin, eine
while read
Schleife anstelle einerfor
Schleife zu verwenden. In Bash für Schleifen, die standardmäßig mit einem beliebigen Leerzeichen (Leerzeichen, Tabulator, Zeilenumbruch) geteilt werden - dies kann geändert werden, ist jedoch einfacher und (meiner Meinung nach) sauberer zu verwendenread
, da standardmäßig jeweils eine Zeile gelesen wird.Beachten Sie, dass ich das
"$i"
dort zitiert habe - das ist genauso wichtig, weil das Zitieren von Variablen verhindert, dass die Shell ihren Inhalt aufteilt (es ist das gleiche Problem, das esfor
gibt, aber am anderen Ende). Beachten Sie auch, dass Sie keine einfachen Anführungszeichen verwenden können:'$i'
Gibt ein Literal$i
anstelle des Inhalts der Variablen zurück.Dies wird weiterhin in Verzeichnissen mit Zeilenumbrüchen in ihren Namen unterbrochen. Es gibt eine
-print0
Problemumgehung für Funds, aber ich habe bisher nur Zeilenumbrüche in Dateinamen gesehen, die speziell zum Testen von Skripten erstellt wurden. Ich weiß nicht, ob dies mit der Version von Bash in OSX funktioniert (aus Gregs Wiki ):In diesem Fall ist es jedoch einfacher, Globs zu verwenden: Ein Glob, der mit a endet,
/
wird nur auf Verzeichnisse erweitert, sodass Sie dies einfach tun können(Dies funktioniert perfekt mit Leerzeichen, Zeilenumbrüchen usw.). Allgemeiner gesagt, um alle Verzeichnisse zu durchlaufen:
Leider gibt es in keiner Bash-Version die Möglichkeit, Dateien nur mit Globs auszuwählen (dies ist einer der Gründe, warum ich zsh bevorzuge, wo die Globs so leistungsfähig sind, dass Sie sich nie um das Finden kümmern müssen).
quelle
find
ist nie richtig. Es gibt kein Szenario, in dem das Parsen der Ausgabe vonfind
effektiver ist als-exec
oder-execdir
, oder unter sehr begrenzten Umständen,find … -print0 | xargs -0 …
find … -print0
. Auch ich behaupte , dass eine Liste von Dateinamen aufpoliert Cachen ist , die Grenzen des einzeiligen Scripting schieben. Das Problem der Cache-Ungültigmachung ist ebenfalls nicht unerheblich.shopt -s dotglob
Glob-Erweiterung mit gepunkteten Namen.Ich habe zwei Vorschläge:
sed
diese Option, um alle Verzeichnisnamen in Anführungszeichen zu setzen.xargs
mit Argument-L 1
. Dadurch wird in jeder Zeile von stdin ein Befehl ausgeführt, wodurch diefor
Schleife vermieden wird.Versuchen Sie diese Pipeline:
find . -maxdepth 1 -mindepth 1 -type d | cut -c 3- | sed 's/.*/"&"/' | xargs -L 1 chmod u+x
quelle
Der Kern des Problems besteht darin, dass bei der Befehlsersetzung eine Wortaufteilung erfolgt , sodass Namen mit Leerzeichen nicht vollständig von separaten Namen unterschieden werden können. Globbing leidet nicht unter dieser Schwierigkeit. Wenn es also eine Möglichkeit gibt, Verzeichnisse mit einem Glob zu identifizieren und die Befehlsersetzung vollständig zu vermeiden, sind Sie frei zu Hause. Und da ist:
Aber auch das ist zu viel Arbeit, da
chmod
dasX
symbolische Flag (Großbuchstabe X) das ausführbare Bit nur auf Verzeichnisse und Dateien anwendet, die bereits ausführbar sind. Sie können also wirklich einfach Folgendes tun:quelle
Entweder zieht Ihr Alias nur das erste Bit vor dem Leerzeichen oder Ihre for-Schleife liest nur das erste Bit
Sie können dies testen, indem Sie Ihren Befehlen einige Testkommentare hinzufügen. Ich habe den Alias so beschränkt, dass nur das zuletzt gefundene Verzeichnis abgerufen wird, um die Iterationen auf 1 zu isolieren. Ich habe ausgedruckt, was der Alias für empfänglich hält, und dann den Inhalt der Variablen wiederholt, um sicherzustellen Sie passen:
BEARBEITEN: geändert
do; echo ...
in,do echo ...
da die Ausführung der Zeile verhindert wurdequelle
ZZPRODUCT data folder
! Wenn es wie erwartet gewesen wäre, wäre die AusgabeFilename is ZZPRODUCT data folder
nicht so gewesen,Filename is ZZPRODUCT
wie Sie es angegeben haben. Stuffe hat das Problem gefunden.getdirs
nicht, befindet sich das Problem in der Schleife. Wenngetdirs
die Ausgabe abgeschnitten ist, liegt das Problem bei Ihrem Alias. Trotzdem gefällt mir die Lösung von @ patrix. Haben Sie es versucht?