Systeminformationen
OS: OS X
bash: GNU bash, Version 3.2.57 (1) -release (x86_64-apple-darwin16)
Hintergrund
Ich möchte, dass Time Machine eine Reihe von Verzeichnissen und Dateien aus meinem git / nodejs-Projekt ausschließt. Meine Projektverzeichnisse befinden sich in ~/code/private/
und ~/code/public/
deshalb versuche ich, die Bash-Schleife zu verwenden tmutil
.
Problem
Kurze Version
Wenn ich eine berechnete Zeichenfolgenvariable habe k
, wie mache ich sie in oder direkt vor einer for-Schleife:
i='~/code/public/*'
j='*.launch'
k=$i/$j # $k='~/code/public/*/*.launch'
for i in $k # I need $k to glob here
do
echo $i
done
In der langen Version unten sehen Sie k=$i/$j
. Daher kann ich die Zeichenfolge in der for-Schleife nicht fest codieren.
Lange Version
#!/bin/bash
exclude='
*.launch
.classpath
.sass-cache
Thumbs.db
bower_components
build
connect.lock
coverage
dist
e2e/*.js
e2e/*.map
libpeerconnection.log
node_modules
npm-debug.log
testem.log
tmp
typings
'
dirs='
~/code/private/*
~/code/public/*
'
for i in $dirs
do
for j in $exclude
do
k=$i/$j # It is correct up to this line
for l in $k # I need it glob here
do
echo $l
# Command I want to execute
# tmutil addexclusion $l
done
done
done
Ausgabe
Sie sind nicht kugelförmig. Nicht was ich will.
~/code/private/*/*.launch
~/code/private/*/.DS_Store
~/code/private/*/.classpath
~/code/private/*/.sass-cache
~/code/private/*/.settings
~/code/private/*/Thumbs.db
~/code/private/*/bower_components
~/code/private/*/build
~/code/private/*/connect.lock
~/code/private/*/coverage
~/code/private/*/dist
~/code/private/*/e2e/*.js
~/code/private/*/e2e/*.map
~/code/private/*/libpeerconnection.log
~/code/private/*/node_modules
~/code/private/*/npm-debug.log
~/code/private/*/testem.log
~/code/private/*/tmp
~/code/private/*/typings
~/code/public/*/*.launch
~/code/public/*/.DS_Store
~/code/public/*/.classpath
~/code/public/*/.sass-cache
~/code/public/*/.settings
~/code/public/*/Thumbs.db
~/code/public/*/bower_components
~/code/public/*/build
~/code/public/*/connect.lock
~/code/public/*/coverage
~/code/public/*/dist
~/code/public/*/e2e/*.js
~/code/public/*/e2e/*.map
~/code/public/*/libpeerconnection.log
~/code/public/*/node_modules
~/code/public/*/npm-debug.log
~/code/public/*/testem.log
~/code/public/*/tmp
~/code/public/*/typings
bash
shell-script
quoting
wildcards
John Siu
quelle
quelle
k
ist eine berechnete Zeichenfolge, und ich muss es so bleiben, bis die Schleife. Bitte überprüfen Sie meine lange Version.Antworten:
Sie können eine weitere Evaluierungsrunde mit erzwingen
eval
, dies ist jedoch nicht unbedingt erforderlich. (Und eseval
treten ernsthafte Probleme auf, sobald Ihre Dateinamen Sonderzeichen wie enthalten$
.) Das Problem liegt nicht beim Globbing, sondern bei der Tilde-Erweiterung.Globbing erfolgt nach Variablenerweiterung, wenn die Variable nicht in Anführungszeichen gesetzt ist, wie hier (*) :
Auf die gleiche Weise ähnelt dies dem, was Sie getan haben und funktioniert:
Aber mit der Tilde tut es nicht:
Dies ist für Bash eindeutig dokumentiert :
Die Tildeerweiterung erfolgt vor der Variablenerweiterung, sodass Tilde in Variablen nicht erweitert werden. Die einfache Problemumgehung besteht darin,
$HOME
stattdessen den vollständigen Pfad zu verwenden.(* Das Erweitern von Globs aus Variablen ist normalerweise nicht das, was Sie wollen.)
Etwas anderes:
Wenn Sie die Muster durchlaufen, wie hier:
Beachten Sie, dass es, wie
$exclude
nicht zitiert, sowohl aufgeteilt als auch globalisiert ist. Wenn das aktuelle Verzeichnis also etwas enthält, das mit dem Muster übereinstimmt, wird es folgendermaßen erweitert:Verwenden Sie eine Array-Variable anstelle einer geteilten Zeichenfolge, um dies zu umgehen:
Als zusätzlichen Bonus können Array-Einträge auch Leerzeichen ohne Probleme mit der Aufteilung enthalten.
Ähnliches könnte getan werden
find -path
, wenn es Ihnen egal ist, auf welcher Verzeichnisebene sich die Zieldateien befinden sollten. Zum Beispiel, um einen Pfad zu finden, der endet in/e2e/*.js
:Wir müssen
$HOME
statt aus~
dem gleichen Grund wie zuvor verwenden und$dirs
müssen in derfind
Befehlszeile$pattern
nicht in Anführungszeichen gesetzt werden, damit es aufgeteilt wird, sollten aber in Anführungszeichen gesetzt werden, damit es nicht versehentlich durch die Shell erweitert wird.(Ich denke, Sie könnten mit
-maxdepth
GNU find spielen, um zu begrenzen, wie tief die Suche geht, wenn es Sie interessiert, aber das ist ein etwas anderes Problem.)quelle
find
? Eigentlich erkunde ich auch diese Route, da die for-Schleife immer komplizierter wird. Aber ich habe Schwierigkeiten mit dem '-Pfad'."${array[@]}"
(mit den Anführungszeichen!) ist dokumentiert (siehe hier und hier ), um die Elemente als eindeutige Wörter zu erweitern, ohne sie weiter aufzuteilen.[abc]
ist ein Standardteil von Glob-Mustern .?
Ich glaube nicht, dass es notwendig ist, alle hier zu behandeln.Sie können es als Array anstelle einer Zeichenfolge speichern, um es später in vielen Fällen zu verwenden, und das Globbing beim Definieren zulassen. In Ihrem Fall zum Beispiel:
oder im späteren Beispiel werden Sie
eval
einige der Zeichenfolgen benötigenquelle
$exclude
Platzhalter enthält, den Sie deaktivieren Globbing brauchen würde , bevor die Verwendung von Split + glob Operator auf sie und es wieder für die$i/$j
und nicht verwenden ,eval
aber die Verwendung"$i"/$j
@ilkkachu Antwort löste das Hauptproblem Globbing. Volle Ehre für ihn.
V1
Da
exclude
Einträge mit und ohne Platzhalter (*) enthalten sind und möglicherweise auch nicht in allen vorhanden sind, ist nach dem Verschieben von eine zusätzliche Überprüfung erforderlich$i/$j
. Ich teile meine Erkenntnisse hier.Output Erklärung
Das Folgende ist die Teilausgabe, um die Situation zu erklären.
Die obigen Angaben sind selbsterklärend.
Das obige wird angezeigt, da der Exclude-Eintrag (
$j
) kein Platzhalterzeichen enthält und$i/$j
eine einfache Zeichenfolgenverkettung ist. Die Datei / dir existiert jedoch nicht.Das oben
$j
gezeigte Ergebnis enthält als Eintrag ausschließen ( ) einen Platzhalter, hat aber keine Datei- / Verzeichnisübereinstimmung. Beim Verschieben von wird$i/$j
nur die ursprüngliche Zeichenfolge zurückgegeben.V2
V2 verwenden Sie einfache Anführungszeichen
eval
undshopt -s nullglob
erhalten Sie ein sauberes Ergebnis. Keine Datei / Verzeichnis-Endkontrolle erforderlich.quelle
for j in $exclude
die Globs in$exclude
zum Zeitpunkt dieser$exclude
Erweiterung erweitert werden könnten (und das Anrufeneval
ist problematisch ). Sie möchten, dass das Globbing fürfor i in $dir
undfor l in $k
, aber nicht für aktiviert wirdfor j in $exclude
. Sie möchten einset -f
vor dem letzteren und einset +f
für den anderen. Im Allgemeinen möchten Sie Ihren split + glob-Operator optimieren, bevor Sie ihn verwenden. In jedem Fall möchten Sie nicht split + glob fürecho $l
, also$l
sollten Sie dort zitieren.exclude
unddirs
in einfachen Anführungszeichen (), so no globbing till
eval`.foo=*
undfoo='*'
ist das gleiche. Aberecho $foo
undecho "$foo"
sind es nicht (in Shells wiebash
, es wurde in Shells wie zsh, fish oder rc behoben, siehe auch den Link oben). Hier möchten Sie diesen Operator verwenden, an einigen Stellen jedoch nur den aufgeteilten Teil und an anderen nur den globalen Teil.Mit
zsh
:${^array}string
ist zu erweitern als$array[1]string $array[2]string...
.$=var
ist das Aufteilen von Wörtern auf die Variable (etwas, was andere Shells standardmäßig tun!),$~var
das Globbing auf die Variable (etwas, was andere Shells ebenfalls standardmäßig tun) (wenn Sie dies normalerweise nicht möchten, hätten Sie$f
oben in Anführungszeichen setzen müssen andere Muscheln)).(N)
ist ein Glob-Qualifizierer, der nullglob für jeden dieser aus dieser$^array1/$^array2
Erweiterung resultierenden Globs aktiviert . Dadurch werden die Globs zu nichts, wenn sie nicht übereinstimmen. Das passiert auch, dass ein Nicht-Glob wie~/code/private/foo/Thumbs.db
einer wird, was bedeutet, dass, wenn dieser bestimmte nicht existiert, er nicht enthalten ist.quelle
exclude
beiliegende Weg wirkt sich auf den Ausgang aus.$^array
sieht so aus, als ob der Split + Glob in zwei Schritten ausgeführt werden muss, um sicherzustellen, dass die leeren Elemente verworfen werden (siehe Bearbeiten). Das sieht ein bisschen nach einem Bug auszsh
, ich werde das Problem auf ihrer Mailingliste ansprechen.