Send command output in shell expect - expect

Following is the code I'm trying to execute with expect in shell script.
send "date +%d%m%y \n"
set date1 "$expect_out(buffer)"
puts "$date1"
expect "#"
The output I'm getting is
date +%d%m%y
111217
Is there any way to suppress the command(date +%d%m%y) and only store the output in variale date1?

Try this: expect to see 6 digits as a whole word
send "date +%d%m%y\r" ;# typically we use \r to "hit enter"
expect -re {\m(\d{6})\M}
set date1 "$expect_out(1,string)"
puts "$date1"
expect "#"
More generally, to select the text between the first line (the command) and the last line (the prompt), you can do:
lassign [regexp -inline {.*?\n(.*)\r\n#} $expect_out(buffer)] _ date1
where _ is a throw-away variable that will hold the entire matching text of the regex, and date1 will hold only the captured text.
See https://tcl.tk/man/tcl8.6/TclCmd/re_syntax.htm for Tcl regex syntax.
Without lassign, you could write
regexp {.*?\n(.*)\r\n#} $expect_out(buffer) _ date1

Related

I want to change newline to a string when saving the result of a linux command in a variable

I am trying to write a shell script that reads the system configuration status of linux and saves the result as CSV.
The result to be saved is the hostname, setting criterion ID, and actual setting value.
The most problematic part when saving as csv is the newline.
For example,
#!/bin/bash
hostname='linux01'
id='SRV-01'
result="*result*\n"
result=$result`cat /etc/passwd | head -n 5`
echo "$hostname, $id, $value" >> test.csv
When the above script exists, the CSV format is broken due to newline.
When script result is as below
linux01, SRV-01, *result*
root:x:0:0:root:/root:/bin/zsh
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
I want to save to csv file this change.
linux01, SRV-01, *result*\nroot:x:0:0:root:/root:/bin/zsh\ndaemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin\nbin:x:2:2:bin: /bin:/usr/sbin/nologin\nsys:x:3:3:sys:/dev:/usr/sbin/nologin\nsync:x:4:65534:sync:/bin:/bin/sync
First, I used sed as a test to change \n to \\n, but when outputting with echo, the \n string is changed to newline.
echo `cat /etc/passwd | head -n 5 | sed -z 's/\n/\\\n/g'`
It is saved as a \n string in the variable, but it is judged that "\n" is changed to 0x0a in echo.
Ask if there is a way to change the echo output to the string "\n" instead of newline.
You can replace the the newlines.
echo "$hostname, $id, ${result//$'\n'/\\n}" >> test.csv

How to avoid the read command cutting the user input which is a string by space

I wrote a bash script to read multiple inputs from the user
Here is the command:
read -a choice
In this way, I can put all the inputs in the choice variable as an array so that I can extract them using an index.
The problem is that when one of the inputs, which is a string has space in it, like
user1 google.com "login: myLogin\npassword: myPassword"
the read command will split the quoted string into 3 words. How can I stop this from happening?
bash doesn't process quotes in user input. The only thing I can think of is to use eval to execute an array assignment.
IFS= read -r input
eval "choice=($input)"
Unfortunately this is dangerous -- if the input contains executable code, it will be executed by eval.
You can use a tab instead of space as a field delimiter. For instance :
$ IFS=$'\t' read -a choice
value1 value2 a value with many words ## This is typed
$ echo ${choice[2]}
a value with many words
Regards!
Given risk of using eval, and the fact the input seems to have only two types of tokens: unquoted, and quoted, consider using scripting engine that will put all text into proper format that will be easy to read.
It's not clear from the example what other quoting rules are used. Example assume 'standard' escaped that can be processed with bash #E processor.
The following uses Perl one liner to generate TAB delimited tokens (hopefully, raw tabs can not be part of the input, but other character can be used instead).
input='user1 google.com "login: myLogin\npassword: myPassword"'
tsv_input=$(perl -e '$_ = " $ARGV[0]" ; print $2 // $3, "\t" while ( /\s+("([^"]*)"|(\S*))/g) ;' "$input")
IFS=$'\t' read -d '' id domain values <<< $(echo -e "${tsv_input#E}")
Or using a function to get more readable code
function data_to_tsv {
# Translate to TSV
local tsv_input=$(perl -e '$_ = " $ARGV[0]" ; print $2 // $3, "\t" while ( /\s+("([^"]*)"|(\S*))/g) ;' "$1")
# Process escapes
echo -n "${tsv_input#E}"
}
input='user1 google.com "login: myLogin\npassword: myPassword"'
IFS=$'\t' read -d '' id domain values <<< $(data_to_tsv "$input")

Bash using --- (triple dash) at start of format string for printf

I have a stored string "--- RE%d ---\n" in a format variable for printf, but when I use it like:
format="--- RE%d ---\n"
printf $format 1
printf treats -- like I want to use some option. When I put anything before ---, it works fine. Is there a way to make printf to print just: --- RE1 ---? I was using \r as 1st character, but it is shown at script output as ^H.
Add --:
format="--- RE%d ---\n"
printf -- "$format" 1
Use -- to signify the end of the options.

Parse Expect and set output as a string

Im trying to figure out how to parse the output of a command in expect and then set what it returns as a variable. Basically i have a command output that looks like a list IE:
OneA
OneB
OneB
TwoA
TwoB
TwoC
ThreeA
ThreeB
ThreeC
Basically i need it to find all the values let say that start with One and then run another command with each instance. Something like stat OneA and print the output then Stat OneB then Stat OneC...
Hopefully that makes sence.
Thanks
Dave
Might be easier to use a shell pipeline:
send -- "yourCommand | grep '^One' | xargs -L 1 stat\r"
In expect, that would be something like:
send -- "yourCommand\r"
expect -re $thePrompt
foreach line [split $expect_out(buffer) \n] {
if {[string match {One*} $line]} {
send -- "stat $line\r"
expect -re $thePrompt
}
}

No space between *gettext* string and cursor of *read* command

Say the following Bash script:
#!/bin/bash
export TEXTDOMAINDIR=./locale
export TEXTDOMAIN=test-gettext-read
. gettext.sh
echo -n $(gettext "Insert a word: ")
read word
GNU gettext is used to make the string translatable and read is used to get user input. However, even if there's a trailing space in the gettext message, there's no space in the terminal when I run the script. Example (cursor is |):
$ bash test-gettext-read.sh
Insert a word:|
As a workaround, I remove the trailing space in the gettext string and I add a space outside:
echo -n $(gettext "Insert a word:")" "
Then it works:
$ bash test-gettext-read.sh
Insert a word: |
My question: is there a better workaround?
Thanks a lot.
Dont use echo -n.
Simply do this:
gettext "Insert a word: "
read word
Or you could wrap your expression whit quotes and then pass it to echo:
echo -ne "$(gettext 'Insert\ta\tword: ')"
Using quotes will ensure that the result passed to echo will be interpreted as one parameter "Insert a word: " insteand of 3: 'Insert' 'a' 'word:'.

Resources