Rendszerinformáció
OS: OS X
bash: GNU bash, 3.2.57 verzió (1) -release (x86_64-apple-darwin16)
Háttér
 Azt akarom, hogy az időgép kizárjon egy könyvtárat és fájlt az összes git / nodejs projektemből. A projektkönyvtárak  ~/code/private/  és  ~/code/public/  könyvtárban vannak, így megpróbálom a bash looping használatával hajtsa végre a tmutil fájlt. 
Probléma
Rövid verzió
Ha van
 kiszámított  karakterlánc változó k, hogyan tehetem azt globálisá vagy jobbra egy for- loop:  
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 
 Az alábbi hosszú változatban látni fogja a k=$i/$j elemet. Tehát nem tudom kódolni a karakterláncot a for ciklus. 
Hosszú verzió
#!/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 
Output
Nem kerülnek ki. Nem az, amit akarok.
~/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 
Megjegyzések
Válasz
 Újabb értékelési kört kényszeríthet a eval gombbal, de ez valójában nem szükséges. (És eval elindul komoly problémái vannak abban a pillanatban, amikor a fájlnevek olyan speciális karaktereket tartalmaznak, mint a $.) A probléma nem a globbolással, hanem a tilde kibővítésével van. 
A globbing történik változó kibővítése után, ha a változó nem szerepel, mint itt (*) :
$ x="/tm*" ; echo $x /tmp 
Tehát, ugyanebben az értelemben hasonlít arra, amit tettél, és működik:
$ mkdir -p ~/public/foo/ ; touch ~/public/foo/x.launch $ i="$HOME/public/*"; j="*.launch"; k="$i/$j" $ echo $k /home/foo/public/foo/x.launch 
De a tildével nem “t”:
$ i="~/public/*"; j="*.launch"; k="$i/$j" $ echo $k ~/public/*/*.launch 
Ez egyértelműen dokumentált a Bash számára:
A kiterjesztések sorrendje: zárójel-kiterjesztés; tilde-kiterjesztés, paraméter- és változó-kiterjesztés, …
 A Tilde kiterjesztése a változó kiterjesztése előtt történik, így a változókon belüli Tilde nem bővül. Az egyszerű megoldás a $HOME vagy a teljes elérési út használata. 
(* a globusok változóból történő kibővítése általában nem az, amit akar)
Másik dolog:
Amikor átmásolod a mintákat, mint itt:
exclude="foo *bar" for j in $exclude ; do ... 
 vegye figyelembe, hogy mivel az $exclude nincs megadva, ezért mindkettő kettéhasad, és ezen a ponton is felcsendül. Tehát ha az aktuális könyvtár tartalmaz valamit, ami illeszkedik a mintához, akkor ez kibővült: 
$ i="$HOME/public/foo" $ exclude="*.launch" $ touch $i/real.launch $ for j in $exclude ; do # split and glob, no match echo "$i"/$j ; done /home/foo/public/foo/real.launch $ touch ./hello.launch $ for j in $exclude ; do # split and glob, matches in current dir! echo "$i"/$j ; done /home/foo/public/foo/hello.launch # not the expected result 
Ennek kiküszöböléséhez használjon egy tömb változót szétválasztott karakterlánc helyett:
$ exclude=("*.launch") $ exclude+=("something else") $ for j in "${exclude[@]}" ; do echo "$i"/$j ; done /home/foo/public/foo/real.launch /home/foo/public/foo/something else 
További bónuszként a tömbbejegyzések tartalmazhatnak szóközt is, felosztás nélkül.
 Valami hasonlót meg lehetne csinálni find -path, ha nem bánja, hogy a megcélzott fájloknak milyen könyvtárszintűeknek kell lenniük. Pl. a /e2e/*.js végződésű utak megtalálásához: 
$ dirs="$HOME/public $HOME/private" $ pattern="*/e2e/*.js" $ find $dirs -path "$pattern" /home/foo/public/one/two/three/e2e/asdf.js 
 A $HOME a ~ helyett ugyanazon okból, mint korábban, és a $dirs elemet fel kell tüntetni a find parancssor, így fel lesz osztva, de a $pattern -t idézni kell, így véletlenül nem bővül ki a héj által. 
 (Azt hiszem, játszhatna a -maxdepth vel a GNU keresőben, hogy korlátozza a keresés mélységét, ha érdekel, de ez “kicsit más kérdés.” 
Megjegyzések
-  Ön az egyetlen válasz a következővel: 
find? Valójában ezt az útvonalat is felfedezem, mivel a for-loop egyre bonyolultabb. De nehézségeim vannak a ‘ -path ‘ problémával. - Köszönjük, hogy a tilde adatairól ‘ ~ ‘ közvetlenebb a fő kérdésre. A végleges forgatókönyvet és magyarázatot egy másik válaszban teszem közzé. De teljes elismerés: D
 - @JohnSiu, igen, a találat használata volt az, ami először eszembe jutott. Lehet, hogy a pontos igénytől függően is használható. (vagy jobb is, néhány felhasználásra.)
 -  @kevinarpe, azt gondolom, hogy a tömbök alapvetően csak ezt jelentik, és igen, 
"${array[@]}"(az idézőjelekkel! ) dokumentálva van (lásd itt és itt ), hogy az elemekre külön szavakként bővülhessen tovább hasítva őket. -  @sixtyfive, nos, a 
[abc]a globális minták szokásos része, például?, nem hiszem, hogy ‘ nem gondolom, hogy ‘ el kell mennem mindet ide . 
Válasz
Tömbökként mentheti el karakterlánc helyett, hogy később később sok esetben használhassa, és hagyja, hogy a globbing történjen, amikor meghatározza. Az Ön esetében például:
 k=(~/code/public/*/*.launch) for i in "${k[@]}"; do  
 vagy a későbbi példában “eval néhány karakterláncot kell 
 dirs=(~/code/private/* ~/code/public/*) for i in "${dirs[@]}"; do for j in $exclude; do eval "for k in $i/$j; do tmutil addexclusion \"\$k\"; done" done done  
megjegyzések
-  Vegye figyelembe, hogy a 
$excludehogyan tartalmaz helyettesítő karaktereket, te ‘ d-nek le kell tiltania a hamisítást, mielőtt a rajta lévő split + glob operátort használni szeretné, és vissza kell állítania a$i/$jés nem használatraeval, de használja a"$i"/$j - Ön és ilkkachu egyaránt jó választ ad. Válasza azonban azonosította a problémát. Tehát hitel neki.
 
Válasz
A @ilkkachu válasz megoldotta a fő hibát. Teljes elismerés neki.
V1
 Azonban a exclude miatt helyettesítő karakterrel és helyettesítővel (*) rendelkező bejegyzéseket is tartalmaz, és előfordulhat, hogy nem is léteznek Összességében további ellenőrzésre van szükség az $i/$j beugrása után. Itt osztom meg megállapításaimat. 
#!/bin/bash exclude=" *.launch .DS_Store .classpath .sass-cache .settings 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=" $HOME/code/private/* $HOME/code/public/* " # loop $dirs for i in $dirs; do for j in $exclude ; do for k in $i/$j; do echo -e "$k" if [ -f $k ] || [ -d $k ] ; then # Only execute command if dir/file exist echo -e "\t^^^ Above file/dir exist! ^^^" fi done done done 
Kimenet magyarázata
Az alábbiakban bemutatjuk a helyzet magyarázatának részkimenetét.
/Volumes/HD2/JS/code/public/simple-api-example-ng2-express/a.launch ^^^ Above file/dir exist! ^^^ /Volumes/HD2/JS/code/public/simple-api-example-ng2-express/b.launch ^^^ Above file/dir exist! ^^^ /Volumes/HD2/JS/code/public/simple-api-example-ng2-express/.DS_Store ^^^ Above file/dir exist! ^^^ 
A fentiek önmagukban értendők.
/Volumes/HD2/JS/code/public/simple-api-example-ng2-express/.classpath /Volumes/HD2/JS/code/public/simple-api-example-ng2-express/.sass-cache /Volumes/HD2/JS/code/public/simple-api-example-ng2-express/.settings /Volumes/HD2/JS/code/public/simple-api-example-ng2-express/Thumbs.db /Volumes/HD2/JS/code/public/simple-api-example-ng2-express/bower_components /Volumes/HD2/JS/code/public/simple-api-example-ng2-express/build /Volumes/HD2/JS/code/public/simple-api-example-ng2-express/connect.lock /Volumes/HD2/JS/code/public/simple-api-example-ng2-express/coverage /Volumes/HD2/JS/code/public/simple-api-example-ng2-express/dist 
 A fentiek azért jelennek meg, mert a kizáró bejegyzés ($j) nincs helyettesítő karakter, $i/$j sima karakterlánc összefűzéssé válik. A fájl / dir azonban nem létezik. 
/Volumes/HD2/JS/code/public/simple-api-example-ng2-express/e2e/*.js /Volumes/HD2/JS/code/public/simple-api-example-ng2-express/e2e/*.map 
 A fentiek kizáró bejegyzésként jelennek meg ($j) tartalmazzák helyettesítő karakter, de nincs fájl / könyvtár egyezés, az $i/$j globbingja csak visszaadja az eredeti karakterláncot. 
V2
 V2 egyetlen idézetet használ, eval és shopt -s nullglob a tiszta eredmény elérése érdekében. Nincs szükség fájl / dir utolsó ellenőrzésre. 
#!/bin/bash exclude=" *.launch .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=" $HOME/code/private/* $HOME/code/public/* " for i in $dirs; do for j in $exclude ; do shopt -s nullglob eval "k=$i/$j" for l in $k; do echo $l done shopt -u nullglob done done 
Megjegyzések
-  Az egyik probléma az, hogy a 
for j in $exclude, a$excludeben található globusok kibővülhetnek a$excludebővítés (és hívás) idejénevalamely problémát kér). ‘ engedélyezni szeretné, hogy afor i in $dirés afor l in $kesetén a globbing engedélyezve legyen, de afor j in $exclude. ‘ szeretne egyset -f-t az utóbbi elé, a másikra pedig egyset +f-t. Általánosabban véve, ‘ hangolni szeretné a split + glob operátort, mielőtt használná. Mindenesetre nem ‘ nem akar split + globot használni aecho $lszámára, tehát$lott kell idézni. -  @St é phaneChazelas v1-re vagy v2-re hivatkozik? A v2 esetében mind a 
exclude, mind adirsegyetlen idézetben szerepel (), so no globbing tilleval`. -   A globbing a jegyzék nélküli kontextusban a nem jegyzett változó  kibővítése  után következik be , hogy (ha egy változó nem szerepel) néha felhívja a  split + glob  operátort. ‘ nincs skálázó változóhoz rendelt hozzárendelés. 
foo=*és Afoo='*'ugyanaz. Deecho $fooésecho "$foo"nem (olyan kagylóban, mint abash, ‘ olyan kagylókban rögzítették, mint a zsh, a fish vagy az rc, lásd a fenti linket is.) Itt csinál azt az operátort akarja használni, de néhol csak a felosztott részt, másutt csak a globális részt. - @St é phaneChazelas Köszönjük az információ !!! Vitt valamikor, de most már értem az aggodalmat. Ez nagyon értékes !! Köszönöm !!! l>
 
Válasz
 A következővel: zsh: 
 exclude=" *.launch .classpath .sass-cache Thumbs.db ... " dirs=( ~/code/private/* ~/code/public/* ) for f ($^dirs/${^${=~exclude}}(N)) { echo $f }  
 ${^array}string bővíteni kell, mint $array[1]string $array[2]string.... A $=var a szó felosztásának végrehajtása a változón (ezt alapértelmezésben más héjak is megteszik!), a $~var a változót lobogtatja (valami más a héjak alapértelmezés szerint is (amikor általában nem akarja őket, akkor a fenti $f t kellett idéznie más héjakban)).
 (N) egy globális minősítő, amely a $^array1/$^array2 nullglob  t az egyes globusoknál 
bővítés. Ez arra készteti a földgömböket, hogy a semmibe táguljanak, ha nem egyeznek. Ez egy olyan nem-gömböt is átalakít, mint a~/code/private/foo/Thumbs.db, ami azt jelenti, hogy ha az adott nem létezik, nincs benne.
Megjegyzések
-  Ez nagyon szép. Teszteltem és működik. Úgy tűnik azonban, hogy a zsh érzékenyebb az új vonalakra, amikor egyetlen idézet használata. A 
excludebezárása befolyásolja a kimenetet. -  @JohnSiu, ja, igen, te ‘ igaza van. Úgy tűnik, hogy a split + glob-ot és a 
$^array-et két külön lépésben kell elvégezni annak biztosítása érdekében, hogy az üres elemeket eldobják (lásd a szerkesztést). Ez kicsit hasonlít egyzshhiba, ‘ felvetem a problémát a levelezőlistájukon. - előállok egy v2-vel A bash esetében, amely tisztább, de még mindig nem olyan kompakt, mint a zsh szkripted, lol
 
Válasz
Régi poszt, de itt botlottam be, így t gondoltam, ez másoknak is segíthet 🙂
A bash-ban van egy kinda-glob () függvény … compgen -G-nek hívják. Soronként ad ki egy értéket, így a működéshez újra kell írni.
Próbálja ki:
i="~/code/public/*" j="*.launch" k=$i/$j # $k="~/code/public/*/*.launch" readarray -t files < <(compgen -G "$k") # $k is globbed here for i in "${files[@]}" do echo "Found -$i-" done 
kegy számított karakterlánc, és nekem szükségem van rá y így a hurokig. Kérjük, ellenőrizze a hosszú verziómat.