What does the -i flag in Expect do? - expect

I am parsing through some tcl scripts left for me by a long-gone ex-coworker and trying to make some sense of them without having to actually learn tcl (maybe some other time). I have some scripting experience but not with tcl, so I think I'm getting most of it but I wonder if anyone can tell me what the '-i' flag does, e.g.:
expect {
-i $tbs -re "(.*)\n" {
or
send -i $ftp "put /dev/acq/$data $data\r"
This is generally found in an expect{} block, but I don't know if that's relevant.
Thanks for the help,
Mario

This is specific to expect, not tcl in genreal (so it's the expect manpage you should be referring to).
For both the expect and send commands the -i flag is similar: it specifies a particular spawn_id (subprocess) to work with, rather than the default.
expect
[...]
By default, patterns are matched against output from the current
process, however the -i flag declares the output from the named
spawn_id list be matched against any following patterns (up to
the next -i).
and
send
[...]
The -i flag declares that the string be sent to the named
spawn_id.

Related

Capturing output of an expect session with a bash script

I have a bash script that is using xmlstarlet to manipulate some key/value pairs in an application configuration file to prepare the file to be moved to a new production host. The values that need changed are host/encryption specific.
In order to discover one of the new values I need to interact with a vendor provided script in an expect session and capture the output into a variable in the bash script so I can continue to use it.
The expect part of the bash script looks something like this:
expect <<DONE
spawn command_provided_by_vendor
expect :
send -- "newvalue\r"
DONE
This is where I get stuck
In a shell the output of this command looks like:
Encrypted value (case sensitive, please cut and paste): 2qIrRvcSoHMb55dpcef6vw==
What I need to do is capture the non-whitespace output after the ":" and nothing I've tried works due to regexp errors, the parenthesis in the prompt string, etc.
There are other questions on stackoverflow that are similar, but I failed to understand how those answers helped my problem.
Any help, pointers appreciated.
I would use the expect command to look for an appropriate regular expression and capture the value there:
value=$(
expect <<DONE
spawn command_provided_by_vendor
expect :
send -- "newvalue\r"
expect -re {Encrypted value.*: (\S+)}
puts $expect_out(1,string)
expect eof
DONE
)

grep Ipaddress in expect script

I want to grep ipaddress from file and set it to variable in expect scritp
send -- "cat $filename |grep ([0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\})\r"
expect -re "([0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}) *$prompt$"
set IP $expect_out(1,string)
but I'm not suceeding. Any idea? I'm using /usr/local/bin/expect. Thanks
From a quick scan, it seems to me you're trying to match a double prompt in your statement. You seem to have a variable followed by a literal prompt at the end of your expect regexp. Are you sure that is what you want?
Aside from that, I strongly recommend that you put expect_internal 1 somewhere at the top of your script, and that way expect will log output showing you what it is (and is not) matching. You really shouldn't be trying to debug regexp matching without it, it's like searching in the dark...

Can't execute a string as a shell command in elisp

(shell-command "\"C:\\Documents and Settings\\ggustafson\\Desktop\\stuff\\ctags58\\ctags.exe\" -eR -f \"C:\\Documents and Settings\\ggustafson\\Desktop\\BlueTooth_7020\\TAGS\" \"C:\\Documents and Settings\\ggustafson\\Desktop\\BlueTooth_7020\"")
(message "\"C:\\Documents and Settings\\ggustafson\\Desktop\\stuff\\ctags58\\ctags.exe\" -eR -f \"C:\\Documents and Settings\\ggustafson\\Desktop\\BlueTooth_7020\\TAGS\" \"C:\\Documents and Settings\\ggustafson\\Desktop\\BlueTooth_7020\"")
Executing the top form gives me the error 'C:\Documents' is not recognized as an internal or external command, operable program or batch file.. Executing the output the second form puts into the *Messages* buffer works as intended (creates a tags file).
Why am I not getting the same results with both techniques? Does shell-command do something that changes the string before sending it to the shell? How can I use elisp to execute a string exactly as if I had pasted it into a command prompt?
shell-quote-argument does not work either as it produces a string that cannot be executed with either method:
(message (shell-quote-argument "\"C:\\Documents and Settings\\ggustafson\\Desktop\\stuff\\ctags58\\ctags.exe\" -eR -f \"C:\\Documents and Settings\\ggustafson\\Desktop\\BlueTooth_7020\\TAGS\" \"C:\\Documents and Settings\\ggustafson\\Desktop\\BlueTooth_7020\""))
"^\"\\^\"C:\\Documents and Settings\\ggustafson\\Desktop\\stuff\\ctags58\\ctags.exe\\^\" -eR -f \\^\"C:\\Documents and Settings\\ggustafson\\Desktop\\BlueTooth_7020\\TAGS\\^\" \\^\"C:\\Documents and Settings\\ggustafson\\Desktop\\BlueTooth_7020\\^\"^\""
shell-quote-argument is for quoting a single argument to a shell command (hence the name), not a shell command in its entirety.
Given that the error you were seeing suggested a lack of quoting somewhere, it seemed like a good idea to use the built-in command to deal with quoting rather than writing it manually and assuming you had the correct syntax.
Another alternative is using M-! to execute the command (or a similar one) interactively, figure out what gets accepted, and then afterwards use C-xM-: to obtain the elisp form.
I would suggest you to doublecheck both if executions are using same path, and therefore same ctags.exe. I think that might be the problem. You may want to use the full path to ctags.exe to make sure of that.
My ctags (Linux) gives me the same error if I use the -Re option on a normal shell; that is what makes me think that way.
I'd strongly recommend you use call-program instead of shell-command here, since you don't use any of the features of the shell, and it just gets in the way, forcing you to do quoting gymnastics to explain to the shell what you mean.

What is the standard usage argument style?

I'm making some command-line tools for some research I'm doing. I'd like these tools to follow commonly used conventions regarding command line programs in Unix.
Should I use flags or just list parameters?
program one two three
program -a one -b two -c three
Where in the list of commands does the input file normally go, or is it better to < it into the program?
What about the output filename?
Should I specify the file extension for the output format, or have my program automatically put the correct extension on?
When the user enters an invalid command, is there a prototypical "correct usage" message?
Is "--help" or "-h" required?
Also, is there some sort of header file I can include that would help with managing these?
If you're looking for a "standard", then you could do worse than look at GNU's Standards for Command Line Interfaces. Other standards are available.
As far as coding for this goes, take a look at boost::program_options. Not only will this save you rolling a lot of your own code, but it does a good job of formatting the options for presenting to the user (the prototypical "correct usage" message, you asked for).
In answer to your specific questions:
Where in the list of commands does the input file normally go, or is it better to < it into the program?
I would expect these to come at the end of a command line. Like in GNU grep. If you are only processing one file and would like to make stdin available as an input source, that would not surprise most users.
If your command processes lots of files, then it would be unusual to have to specify a switch before the filenames. Think cat.
What about the output filename?
A -o or --output option is fairly common. If your file takes exactly one input and one output, then program inputfile outputfile would not surprise many users. If no output file is specified, perhaps you'll output to stdout; that would not be unusual behaviour and would allow your users to pipe the output through other commands (such as grep, less, etc...), They could also redirect stdout to a file using >.
Should I specify the file extension for the output format, or have my program automatically put the correct extension on?
This is probably a matter for debate. If I specified an output filename, I would expect to find that file created (or replaced, after a prompt) without the program changing the name.
When the user enters an invalid command, is there a prototypical "correct usage" message?
Using GNU grep as an example again:
grep: unrecognized option '--incorrect'
Usage: grep [OPTION]... PATTERN [FILE]...
Try 'grep --help' for more information.
This wouldn't surprise too many users and points them in the right direction if they've made a typo without swamping them with information.
Is "--help" or "-h" required?
That depends on your customer! I find it frustrating when this option isn't available.
Usually speaking, flags are there for providing options and parameter are for passing information. If you have input,output file as command line argument, use flags like -i -o, so sequence will not matter. -h is required if you want to (and need to) give documentation.

Unix pipes and positional arguments

I'm combining sox and lame to generate a new music file, but in order to do everything on one line using pipes, it seems necessary to 'mark' the output and input boundaries with a - character. I've inherited this code, so let me show.
sox $DIRNAME/$BASENAME -e signed-integer -r 8000 -c 2 -t wav - trim $POSITIONS | lame -v -V4 --resample 8 - $DIRNAME/${NOEXT}.mp3
The - between wav and trim is the output file, and the - between --resample 8 and $DIRNAME/${NOEXT}.mp3 is the input file.
I'm trying to find further information on this, like whether any character can be used, or if - is special in this way. What is this called, and what makes it work?
Many Unix command-line utilities use "-" as a shorthand to mean "don't use a real file here, use stdin (or stdout) instead". Sox is one of these programs:
This is from the sox manpage
SoX can be used in simple pipeline operations by using the special
filename '-' which, if used in place of an input filename, will cause
SoX will read audio data from 'standard input' (stdin), and which, if
used in place of the output filename, will cause SoX will send audio
data to 'standard output' (stdout). Note that when using this option,
the file-type (see -t below) must also be given.
By convention, unix and friends use - to represent stdin and stdout.
It's not 100% universal, but it's a pretty widely used.
In your example, it's the same thing as
/dev/stdin
Try to replace your - with it, you will see.
"-" is often use as a convention instead of a file name to say "use the standard input (instead or reading for the file) or standard output (instead of writing to the file)". This is not a feature of the command shell (i.e. bash), so in that sense, it is not a special character. It is a feature of some commands (like in your case "sox" and "lame") and is very useful to chain these commands through pipes.

Resources