Just to make it a bit easier to read:
''List of items in "Test":''
<<set _Items = UInv.GetItemsArray("Test")>>
<<if _Items.length == 0>>
(empty)
<<else>>
<<for _i = 0; _i < _Items.length; _i++>>
_Items[_i] (<<print UInv.BagHasItem("Test", _Items[_i])>>)
<<if _i < _Items.length - 2>>, <<elseif _i < _Items.length - 1>>
<<if _Items.length > 2>>,<</if>> & <</if>>
<</for>>
<</if>>
Now, the <<for>> macro is explained in the SugarCube documentation (see link).
The "_i = 0" sets _i to 0 initially, the "_i < _Items.length" is how the loop determines when to stop (when that is no longer true), and the "_i++" causes the value of _i to increase by 1 after each time through the loop. Looking at the SugarCube documentation should help explain SugarCube macros, functions, and methods like these.
As for the rest, _Items is set to an array by the UInv.GetItemsArray() function. Arrays have a .length property, which tells how many elements are in it, and those elements will be numbered from 0 to .length - 1. So if the array's .length property is 5, then the items in that array will be at array indexes 0 to 4. The UInv.BagHasItem() function returns the number of items the bag has with that name, which can also act as a kind of true/false value, since 0 is a falsy value, and any other number is a truthy value.
So, what this <<for>> loop does is go through each item in the array and display each item's name ("_Items[_i]") and how many of that item there are ("<<print UInv.BagHasItem("Test", _Items[_i])>>"). If there are no items, then it will display "(empty)" instead.
If you still find <<for>> loops confusing, you could probably just use the UInv.DisplayItemList() function instead, since it handles doing the loop for you. Examples of its use exist in the sample code in passages 4-7, plus the simple "<<print UInv.DisplayItemList("Test")>>" example in the "Let's begin" passage.
Hope that helps! :-)