0

I am going through the Tcl tutorial and the lappend operator is returning unexpected results.

I am running this on F5 load-balancing hardware's command line interface. Here is the relevant system info:

~ \#  cat /proc/version
  Linux version 2.6.32-431.56.1.el6.f5.x86_64 (f5cm@build19) (gcc version 4.4.7 20120313 (Red Hat 4.4.7-3) (GCC) ) #1 SMP Wed Jun 8 11:41:48 PDT 2016

% puts $tcl_version
8.5

I attempted every permutation of variable grouping I could think of, and I was still unable to get results that I expect. It appears as though there is a buffer that is holding on to all the results of the command: 'puts' command and using it in the 'lappend' command. Here is the lines I executed. The first few 'puts' are just to show that nothing has been initialized yet:

% puts $l1

can't read "l1": no such variable

% puts $l2

can't read "l2": no such variable

% puts $l3

can't read "l3": no such variable

% puts $l4

can't read "l4": no such variable

% puts $l5

can't read "l5": no such variable

% set l1 { {item 1} {item 2} {item 3} }

 {item 1} {item 2} {item 3}

% set l2 { {item 4} {item 5} {item 6} }

 {item 4} {item 5} {item 6}

% set l3 [concat $l1 $l2]

{item 1} {item 2} {item 3} {item 4} {item 5} {item 6}

#things working as expected here
% puts $l3

{item 1} {item 2} {item 3} {item 4} {item 5} {item 6}

#this is where things start to get squirrelly. I would expect this to return the result of $l1 concat with $l2 and the result stored in $l1
% lappend $l1 $l2

{ {item 4} {item 5} {item 6} }

#as you can see, it appears to return the second argument when that argument is a list. 
% lappend $l2 $l1

{ {item 1} {item 2} {item 3} }

# $l1 remains unchanged. at the very least, according to the documentation,
# I would expect that second item would be treated as a single entity
# when it is a list, and that the fourth item in '% lappend $l2 $l1' would be $l1
% puts $l1

 {item 1} {item 2} {item 3}

#neither $l2 nor $l1 are modified as the result of the 'lappend' command.
% puts $l2

 {item 4} {item 5} {item 6}

#more squirrelly-ness. when the arguments being passed are individual, it seems as though the last call to 'puts' is what 'lappend' uses for its first argument. this is confirmed on the last 3 commands below. **strong text**
% lappend $l1 "a" "b" "c"

{ {item 4} {item 5} {item 6} } a b c

% puts $l1

 {item 1} {item 2} {item 3}

% lappend "$l1" "$l2"

**{ {item 4} {item 5} {item 6} } a b c { {item 4} {item 5} {item 6} }**

% puts $l1

 {item 1} {item 2} {item 3}

% puts $l2

 {item 4} {item 5} {item 6}

% set l4 [lappend $l1 $l2]

 **{ {item 4} {item 5} {item 6} } a b c { {item 4} {item 5} {item 6} } { {item 4} 
{item 5} {item 6} }**

% puts $l4

 { {item 4} {item 5} {item 6} } a b c { {item 4} {item 5} {item 6} } { {item 4} 
{item 5} {item 6} }

# confirmed. 'lappend' is using last call to 'puts' as its argument for it's first argument. this can't be intended behavior right?
% puts $l1
 {item 1} {item 2} {item 3}
% set l5 [lappend $l2 "a" "b" "c"]
 { {item 1} {item 2} {item 3} } a b c
% puts $l2
 {item 4} {item 5} {item 6}

I can't imagine that this behavior is intended.

Here's how I would imagine this should work:

#should return something like [$list1, [$list2]] or something like concat $list1 $list2
% lappend $list1 $list2

#should return each item concatenated to the end of $list1
% lappend $list1 "a" "b" "c"

If the answer is that lappend does not modify the first argument in place, and I have to use a set command to save the results of the lappend command, that is fine; However, the lappend command does not appear to be behaving in a consistent manner.

Thanks in advance for any help/insight.

4

2 回答 2

3

lappend $l1 $l2 appends the contents of l2 to the variable NAMED by the contents of l1. You want lappend l1 $l2, in much the same way that you set variables via set l1 whatever, rather than set $l1 whatever.

于 2017-01-17T22:07:50.173 回答
2

lappend takes a variable name as its first argument, not a list. In the case:

   set l1 [list a b c]
   lappend $l1 x
   puts [set {a b c}]
   # returns: x

x is appended to the variable named {a b c}.

Instead, use the variable name as the first argument to lappend:

   set l1 [list a b c]
   set l2 [list d e f]
   lappend l1 {*}$l2
   # result: a b c d e f

The general rule to remember is that if a Tcl command modifies its argument, pass a variable name. If the Tcl command does not modify its argument, pass the value (this rule doesn't work for arrays).

References: lappend

于 2017-01-17T22:09:55.237 回答