1

I'm newbie to Tcl. I have a list like this:

set list1 {
    dir1
    fil.txt
    dir2
    file.xls
    arun
    baskar.tcl
    perl.pl
}

From that list I want only elements like:

dir1
dir2
arun

I have tried the regexp and lsearch but no luck.

Method 1:

set idx [lsearch $mylist "."]

set mylist [lreplace $mylist $idx $idx]

Method 2:

set b [regsub -all -line {\.} $mylist "" lines]
Peter Lewerin
  • 13,140
  • 1
  • 24
  • 27
Samuel E
  • 13
  • 5
  • It looks you might be generating the list from `glob` and might be looking for the directories in that list. Did you know that you can pass the option `-type d` (for directory) to `glob` to get it to do the file type filtering for you? (The converse is to look for type `f` for file.) Very useful! – Donal Fellows Jul 14 '18 at 05:35
  • I have seen some documentations regarding list of directory but I'm comfortable with my own idea. Thanks anyways @DonalFellows – Samuel E Jul 14 '18 at 11:04

3 Answers3

1

The lsearch command has many options, some of which can help to make this task quite easy:

lsearch -all -inline -not $list1 *.*
Schelte Bron
  • 4,113
  • 1
  • 7
  • 13
1

Method 1 would work if you did it properly. lsearch returns a single result by default and the search criteria accepts a glob pattern. Using . will only look for an element equal to .. Then you'll need a loop for the lreplace:

set idx [lsearch -all $list1 "*.*"]
foreach id [lsort -decreasing $idx] {
    set list1 [lreplace $list1 $id $id]
}

Sorting in descending order is important because the index of the elements will change as you remove elements (also notice you used the wrong variable name in your code snippets).


Method 2 would also work if you used the right regex:

set b [regsub -all -line {.*\..*} $list1 ""]

But in that case, you'd probably want to trim the results. .* will match any characters except newline.


I would probably use lsearch like this, which avoids the need to replace:

set mylist [lsearch -all -inline -not $list1 "*.*"]
Jerry
  • 70,495
  • 13
  • 100
  • 144
1

Alternatively, filter the list for unaccepted elements using lmap (or an explicit loop using foreach):

lmap el $list1 {if {[string first . $el] >= 0} {continue} else {set el}}

See also related discussion on filtering lists, like Using `lmap` to filter list of strings

mrcalvin
  • 3,291
  • 12
  • 18