def each_command_substitution_for(input, &blk)
      return unless input

      i = 0
      loop do
        break if i >= input.length

        @chunk = input[i..-1]
        if md=@chunk.match(COMMAND_SUBSTITUTION)
          start = i
          delimiter = md[1] == "$(" ? ")" : md[1]
          result = process_string @chunk[md[0].length-1..-1], delimiter
          consumed_length_so_far = result.consumed_length + (md[0].length - 1)
          i += consumed_length_so_far
          yield OpenStruct.new(str:result.str, position:(start..i))
        else
          i += 1
        end
      end
    end
def each_command_substitution_for(input, &blk)
      return unless input

      i = 0
      loop do
        break if i >= input.length

        @chunk = input[i..-1]
        if md=@chunk.match(COMMAND_SUBSTITUTION)
          start = i
          delimiter = md[1] == "$(" ? ")" : md[1]
          result = process_string @chunk[md[0].length-1..-1], delimiter
          consumed_length_so_far = result.consumed_length + (md[0].length - 1)
          i += consumed_length_so_far
          yield OpenStruct.new(str:result.str, position:(start..i))
        else
          i += 1
        end
      end
    end
Loop over the given input and yield command substitutions. This yields
 an object that responds to #str, and #position.

 * The #str will be the contents of the command substitution, e.g. foo in `foo` or $(foo)
 * The #position will be range denoting where the command substitution started and stops in the string

 This will yield a result for every command substitution found.

 == Note

 This will not yield nested command substitutions. The caller is responsible
 for that.