How to do string substitution in expect? - expect

Say I have the following variable s:
set s [lindex $argv 0]
How can I make sure s does not contain any "-" characters?
So, basically I want to replace all occurrences of "-" in s with "".
How can I achieve it?

Use set s [string map { - {} } [lindex $argv 0]]
As pynexj says, details can be found at http://www.tcl-lang.org/man/tcl/TclCmd/string.htm#M34

Related

Bash parameter expansion inside expect

What I'm trying to do:
./script 192.168.1.{1..100}
#!/bin/expect -f
set servers_ip [lindex $argv 0]
set servers_port [lindex $argv 1]
set timeout -1
foreach ip $servers_ip {
puts "\nIP = $ip"
}
expected output:
IP = 192.168.1.1
IP = 192.168.1.2
IP = 192.168.1.3
Actual output:
IP=192.168.1.1
I just can't make the parameter expansion work, and I CANNOT use external files.
Your shell has already expanded the brace expansion before launching expect. The first 100 elements of $argv are individual IP addresses.
Here, you want
set servers_ip $argv
then, iterating over them should give you what you want

for loop, expect and pssh

I need a script to modify the same data in multiple servers. For now the for loop generate the command lines, but i'm experiencing some problems with expect and pssh.
The for loop:
<code>
for ((var1=1;var1<=14; var1++))
{
cda stm add "$var1/$var2/$var3" ss 1
for ((var2=1;var2<=8;var2++))
{
cda stm add "$var1/$var2/$var3" ss 1
for ((var3=1; var3<64; var3++))
{
cda stm add "$var1/$var2/$var3" ss 1
}
}
}
</code>
I'm using pssh instead ssh in expect script.
The full code:
<code>
#!/usr/bin/expect
set timeout 20
set ip [lindex $argv 0]
set user [lindex $argv 1]
set password [lindex $argv 2]
for ((var1=1;var1<=14; var1++))
{
cda stm add "$var1/$var2/$var3" ss 1
for ((var2=1;var2<=8;var2++))
{
cda stm add "$var1/$var2/$var3" ss 1
for ((var3=1; var3<64; var3++))
{
cda stm add "$var1/$var2/$var3" ss 1
}
}
}
spawn pssh "$user\#$ip"
expect "yes/no" {
send "yes\r"
expect "*?assword" { send "[lindex $argv 2]\r" }
} "*?assword" { send "[lindex $argv 2]\r" }
expect "SH"
interact
</code>
I'm getting the following error:
<code>
wrong # args: should be "for start test next command"
while executing
"for ((var1=1"
(file "./ssh" line 9)
</code>
for loops in expect and Tcl have to look like this:
for {set var1 1} {$var1<=14} {incr var1} {
commands...
}
In other words, the for command requires four arguments: the start code, the condition, the "next" code and the loop body. Note that newlines are command separators in Tcl, so the open brace for the loop body must be on the same line as the for command (or you must use a backslash-newline line continuation).
You used bash/ksh syntax instead.
Apart from the syntax error in for loop, there's a logical problem with the code snippet in the question:
var2 isn't available for printing in the outermost loop (for the first time).
var3 isn't available for printing in the 2nd loop (for the first time).
Here's probably what you need:
for {set var1 1} {$var1 <=14} {incr var1} {
puts "LEVEL_1: $var1"
# cda stm add "$var1" ss 1
for {set var2 1} {$var2 <=8} {incr var2} {
puts "LEVEL_2: $var1/$var2"
# cda stm add "$var1/$var2" ss 1
for {set var3 1} {$var3 <64} {incr var3} {
puts "LEVEL_3: $var1/$var2/$var3"
# cda stm add "$var1/$var2/$var3" ss 1
}
}
}

How to store a line from expect_out(buffer) to a variable in tcl

For example, if the output ( in expect_out(buffer) )is
blah
blh blah
asdjsudfsdf
how can I store the 2nd line to a variable? so far I have this:
foreach line [split $expect_out(buffer) "\n"] {
if [lindex $line 1] {
set variable $line
}
}
But this does not work, it says the variable variable is undefined. I tried adding a counter, but that didn't work either. There has to be an easier way!
yes there is an easier way:
set lines [split $expect_out(buffer) \n]
set variable [lindex $lines 1]
or in one line
set variable [lindex [split $expect_out(buffer) \n] 1]
Keep mindful you know what Tcl commands return: split returns a list. You then use lindex to find the 2nd element of the list.

TCL/Expect equivalent of Bash $# or how to pass arguments to spawned process in TCL/Expect

If somebody wants to call external program (which was passed as a Bash argument) from Bash and also pass it command line options (which were also passed as a Bash arguments) the solution is fairy simple:
TCL_SCRIPT="$1"
shift
TCL_SCRIPT_ARGUMENTS="$#"
expect -f "$TCL_SCRIPT" "$TCL_SCRIPT_ARGUMENTS" 2>&1
Is something similar possible in TCL/Expect ?
EDIT:
So far I've come with this hack (there are Bash equivalents in comments), which seems that it is working. Can somebody explain lshift procedure?
# http://wiki.tcl.tk/918#pagetocc7993a2b
proc lshift {inputlist} {
upvar $inputlist argv
set arg [lindex $argv 0]
#set argv [lrange $argv 1 end] ;# below is much faster - lreplace can make use of unshared Tcl_Obj to avoid alloc'ing the result
set argv [lreplace $argv[set argv {}] 0 0]
return $arg
}
# BASH: TCL_SCRIPT="$1"
set script [lindex $argv 0]
# BASH: shift
lshift argv
# BASH: TCL_SCRIPT_ARGUMENTS="$#"
set arguments $argv
To literally translate your example
set program [lindex $argv 0]
set arguments [lrange $argv 1 end]
spawn $program {*}$arguments
{*} is Tcl's "list expansion" syntax (rule 5 of Tcl's 12 rules of syntax). It splits a list into its element in the current command.
If $argv is foo bar baz, then
spawn [lindex $argv 0] [lrange $argv 1 end]
will invoke foo with 1 argument: "bar baz"
spawn [lindex $argv 0] {*}[lrange $argv 1 end]
will invoke foo with 2 arguments: "bar" and "baz"
Tangentially, I would code your lshift proc like this:
proc lshift {varname} {
upvar 1 $varname var
set var [lassign $var first]
return $first
}
Then:
expect1.6> set argv {foo bar baz}
foo bar baz
expect1.7> set script [lshift argv]
foo
expect1.8> set script
foo
expect1.9> set argv
bar baz
I found #glenn jackman's answer to be insufficient for older TCL, namely versions before 8.5, and especially for older Unicies running Expect scipts as well. I went searching and found a note that the "lassign" function is not available in TCL before 8.5: (http://wiki.tcl.tk/1530 , in section "In Tcl prior to 8.5, foreach was used to achieve the functionality of lassign:").
On that same page, under the heading "Example: Perl-ish shift", there is a sentance stating "On the other hand, Hemang Lavana observes that TclXers already have lvarpop ::argv, an exact synonym for shift.") that redirects to this page for "lvarpop": http://wiki.tcl.tk/1965
The code at the end of that page is a simplified version, reproduced here for convenience:
proc lvarpop {upVar {index 0}} {
upvar 1 $upVar list
if {![info exists list]} { return "-1" }
set top [lindex $list $index]
set list [lreplace $list $index $index]
return $top
}
In my testing, this works for zero to practically an infinite number of space-separated args. For the TCL-challenged such as myself, this is a godsend.

How to count command line arguments in expect script?

This is my simple expect script:
#!/usr/local/bin/expect
puts "Argu 1 : [lindex $argv 0]"
Run
---
expect example.expt Testing
Output
------
Argu 1: Tesing
I need to count the arguments, which are passed by command line. Like this:
expect example.expt 1 2 3 4
I need the script for the following output
Total: 4 arguments
Arg1: 1
Arg2: 2
Arg3: 3
Arg4: 4
How can I do this? Thanks!
expect uses Tcl as its scripting language. You're looking for the llength command:
puts "Total: [llength $argv] argument(s)"
Late but will be useful i guess.
This prints the number of command line arguments and the arguments list as well.
#!/usr/bin/expect -f
puts "No of Command Line Arguments : [llength $argv]"
puts "Arguments List "
set argsCount [llength $argv];
set i 0
while {$i < $argsCount } {
puts [lindex $argv $i]
set i [expr $i+1];
}
More details about expect scripting can be found here

Resources