seq is a command line interface program that is very popular in Unix/Linux. I find myself using it often in my Tcl code so I wrote my own seq.
LES 2025-01-05: added two new blocks (the first ones) to get rid of the "08" octal interpretation. I doubt the octal interpretation will ever be useful in the context of seq. Note that Tcl 9 no longer does the octal assumption.
proc p.seq {args} { # remove unwanted zeros set cleanargs {} for {set x 0} {$x < [llength $args]} {incr x} { if {[string length [lindex $args $x]] > 1} { set newitem [string trimleft [lindex $args $x] 0] lappend cleanargs $newitem } else {lappend cleanargs [lindex $args $x]} } set args $cleanargs # the same again, but with negative integers set cleanargs {} for {set x 0} {$x < [llength $args]} {incr x} { if {[string range [lindex $args $x] 0 0] == "-"} { set newitem [string trimleft [string range [lindex $args $x] 1 end] 0] lappend cleanargs "-$newitem" } else {lappend cleanargs [lindex $args $x]} } set args $cleanargs if {[llength $args] > 3 || [llength $args] < 1} {return ""} set mode "" set intcount 0 for {set x 0} {$x < [llength $args]} {incr x} { if {[string is integer [lindex $args $x]]} {incr intcount} } if {$intcount == [llength $args]} {set mode "integer"} set alphacount 0 for {set x 0} {$x < [llength $args]} {incr x} { if {[string length [lindex $args $x]] > 1} {continue} if {[string is alpha [lindex $args $x]]} {incr alphacount} } if {$alphacount == [llength $args]} {set mode "alpha"} if {$mode == ""} {return ""} # INT MODE if {$mode == "integer"} { lassign $args A B C if {[llength $args] == 3 && $B < 1} {return ""} if {[llength $args] == 3 && $A < $C} { for {set i $A} {$i <= $C} {set i [expr {$i + $B}]} {lappend _output $i} return $_output } if {[llength $args] == 3 && $A > $C} { for {set i $A} {$i >= $C} {set i [expr {$i - $B}]} {lappend _output $i} return $_output } if {[llength $args] == 1} { set A 1; set B [lindex $args 0] if {$B <= 1} {return $args} for {set i $A} {$i <= $B} {incr i} {lappend _output $i} return $_output } if {$A == $B} {return $A} if {$A < $B} { for {set i $A} {$i <= $B} {incr i} {lappend _output $i} return $_output } if {$A > $B} { for {set i $A} {$i >= $B} {incr i -1} {lappend _output $i} return $_output } } # ALPHA MODE if {$mode == "alpha"} { if {[llength $args] < 1 || [llength $args] > 2} {return ""} if {[llength $args] == 1} { if {[string is lower $args]} { set args "a $args" } else {set args "A $args"} } lassign $args A B if {$A == $B} {return $A} set An [scan $A %c]; set Bn [scan $B %c] set _output {} foreach i [p.seq $An $Bn] { if {[string is alpha [format %c $i]] == 1} {lappend _output [format %c $i]} } return $_output } }
Testing it:
> p.seq 4 1 2 3 4 > p.seq 4 11 4 5 6 7 8 9 10 11 > p.seq 11 4 11 10 9 8 7 6 5 4 > p.seq 4 -4 4 3 2 1 0 -1 -2 -3 -4 > p.seq 3 3 18 3 6 9 12 15 18 > p.seq 3 2 18 3 5 7 9 11 13 15 17 > p.seq a g a b c d e f g > p.seq A G A B C D E F G > p.seq A g A B C D E F G H I J K L M N O P Q R S T U V W X Y Z a b c d e f g > p.seq g A g f e d c b a Z Y X W V U T S R Q P O N M L K J I H G F E D C B A