FOREACH

Mivel a PowerShellben nagyon sokszor gyűjteményekkel (collection) dolgozunk, így az alkotók praktikusnak találták ezek elemein történő műveletvégzést megkönnyítő ciklust is készíteni. Köszönet ezért nekik! A FOREACH  kulcsszó segítségével olyan ciklust tudunk létrehozni, ahol nem nekünk kell nyilvántartani, számlálni és léptetni a ciklusváltozót, hanem a PowerShell ezt megteszi helyettünk:

[25] PS C:\> $egyveleg = 1,"szöveg",(get-date),@{egy=2}

[26] PS C:\> foreach($elem in $egyveleg){$elem.gettype()}

 

IsPublic IsSerial Name                                     BaseType

-------- -------- ----                                     --------

True     True     Int32                                    System.ValueType

True     True     String                                   System.Object

True     True     DateTime                                 System.ValueType

True     True     Hashtable                                System.Object

Látszik a ciklus működési elve: az $elem változóba a PowerShell mindig betölti az aktuális tömbelemet az $egyveleg tömbből egészen addig, amíg van elem, és minden elem mellett a sor végén látható szkriptblokkot végrehajtja. Ugyanezt FOR ciklussal is meg tudnánk csinálni, de mennyivel többet kell gépelni, és eggyel több változóra is szükségünk van, plusz még az olvashatósága is sokkal nehézkesebb:

[27] PS C:\> $egyveleg = 1,"szöveg",(get-date),@{egy=2}

[28] PS C:\> for($i=0;$i -lt $egyveleg.length;$i++){$egyveleg[$i].GetType()}

...

Láthattunk a 1.3.3.1 Egyszerű tömbök fejezetben, hogy a PowerShell képes automatikusan „kifejteni” a tömböket (gyűjteményeket) például a get-member cmdletbe való becsövezéskor. A FOREACH ennek ellenkezőjét végzi, azaz egy skaláris (nem tömb) paraméterből képes automatikusan egyelemű tömböt készíteni, ha erre van szükség:

[29] PS I:\>$skalár = 1

[30] PS I:\>foreach($szám in $skalár){"Ez egy szám: $szám"}

Ez egy szám: 1

A fenti példában nem okozott a PowerShellnek problémát foreach ciklust futtatni egy nem tömb típusú változóra, automatikusan egy elemű tömbként kezelte.

$foreach változó

A foreach ciklus belsejében a PowerShell automatikusan létrehoz egy $foreach  változót, aminek a $foreach.current tulajdonsága az éppen aktuális elemet tartalmazza, így akár a [26]-os sorban levő példát másként is írhatnánk:

[53] PS C:\> foreach($elem in $egyveleg) {$foreach.current.gettype()}

 

IsPublic IsSerial Name                                     BaseType

-------- -------- ----                                     --------

True     True     Int32                                    System.ValueType

True     True     String                                   System.Object

True     True     DateTime                                 System.ValueType

True     True     Hashtable                                System.Object

Nézzük meg, hogy ennek a $foreach változónak milyen tagjellemzői vannak:

 [50] PS C:\> foreach($elem in "a"){,$foreach | get-member}

 

 

   TypeName: System.Array+SZArrayEnumerator

 

Name        MemberType Definition

----        ---------- ----------

Clone       Method     System.Object Clone()

Equals      Method     System.Boolean Equals(Object obj)

GetHashCode Method     System.Int32 GetHashCode()

GetType     Method     System.Type GetType()

get_Current Method     System.Object get_Current()

MoveNext    Method     System.Boolean MoveNext()

Reset       Method     System.Void Reset()

ToString    Method     System.String ToString()

Current     Property   System.Object Current {get;}

Az igazán izgalmas számunkra a MoveNext()  metódus, amellyel arra késztethetjük a foreach ciklust, hogy egy elemet kihagyjon:

[54] PS C:\> $tömb = 1,2,3,4,5,6,7

[55] PS C:\> foreach($elem in $tömb){$elem; $foreach.MoveNext()}

1

True

3

True

5

True

7

False

A fenti példában miután minden elemnél rögtön még egy elemet léptettünk, ezért csak minden második számot írtam ki. Ugyan a MoveNext() ad visszatérési $true vagy $false értéket attól függően, hogy van-e még elem vagy nincs, de ezt elnyomhatjuk a [void] típuskonverzióval:

[56] PS C:\> foreach($elem in $tömb){$elem; [void] $foreach.MoveNext()}

1

3

5

7

A $foreach változó másik fontos metódusa a Reset() , ezzel vissza lehet ugrani a ciklus első elemére:

[60] PS C:\> $első = $true

[61] PS C:\> foreach($elem in $tömb){$elem; if($első -and !$foreach.MoveNext()) {$foreach.Reset(); $első = $false}}

1

3

5

7

1

2

3

4

5

6

7

A fenti példában egy ciklussal kétszer is végig járom a $tömb tagjait, első menetben minden másodikat írom ki, a második menetben pedig az összes tagot. Itt is jól jött, hogy az –or feltétel második operandusa csak akkor kerül kiértékelésre, ha az első tag $false, ezzel értem el, hogy a második menetben már ne legyen végrehajtva a MoveNext().



Word To HTML Converter