Krishh
Krishh

Reputation: 33

How to return values from foreach loop in tcl

I have a list of all the files in the directory. I have stored them in a variable file_list. I want to get the tail name for each file. My approach is like this.

set file_list [list /a/b/a.txt /a/b/b.txt /a/b/c/file1.tcl /a/b/c/file2.tcl]

proc file_tail {filename} {
   set x {}
   set f_tail [file tail $filename]
   lappend x $f_tail
return $x

}

foreach ft $file_list {
    set f_tail [file_tail $ft]
}

but f_tail only contains last value stored i.e. "file2.tcl" Please guide me. I want a list of all tail values of file

Upvotes: 0

Views: 1324

Answers (2)

Donal Fellows
Donal Fellows

Reputation: 137567

If you are making a list of all the tails, do this:

set f_tail {}
foreach ft $file_list {
    lappend f_tail [file tail $ft]
}

If your helper function is going to do the lappend, you need to keep the variable holding the list outside the procedure:

proc file_tail {filename listVariable} {
    upvar 1 $listVariable theList
    set f_tail [file tail $filename]
    lappend theList $f_tail
}

set tails {}
foreach ft $file_list {
    file_tail $ft tails ;  # <<< NAME, so not $tails as that would READ the variable
}

Note that we are passing in the name of the variable (tails outside) and using upvar 1 inside the procedure to make a linked local variable (theList inside) that can be updated. However, you can't do it by passing in a list value; Tcl uses copy-on-write semantics for its values. You need to be careful about the difference between the names of variables and the values they contain; they're not the same.

Upvotes: 0

Peter Lewerin
Peter Lewerin

Reputation: 13252

I suggest either:

set f_tail {}
foreach ft $file_list {
    lappend f_tail [file_tail $ft]
}

or (if you have a later version of Tcl):

set f_tail [lmap ft $file_list {file_tail $ft}]

Documentation: foreach, lappend, lmap (for Tcl 8.5), lmap

Upvotes: 1

Related Questions