问题
I am writing an expect script to figure out the existence of a specific file on a remote server. My test server is located in the same network as the remote server. While I tried to search through stackoverflow for similar stuff all I could find is expect scripts that would work on local server.
This link (How to find if a file exists in expect script) was the closest.
On similar lines I found the following website to - Expect with SFTP
Expect Script
Based on both I tried to write my expect script -
#! /usr/bin/expect
set fileName [lindex $argv 0]
set hostIp "10.0.0.1"
puts "SSH to server"
spawn sftp local@$hostIp
sleep 2
expect "Password:"
sleep 2
exp_send "local123\r"
sleep 2
expect "sftp> "
sleep 2
set prompt "sftp> "
exp_send "ls $fileName\r"
sleep 2
expect {
"$fileName" { send_user "\n Found \n" }
"sftp>" { send_user "\n Not Found \n" }
}
Regardless of the response to "ls $fileName", I get the output as "Found". The logic on expect part was -
Found Logic
spawn sftp local@10.0.0.1
Connecting to 10.0.0.1...
CentOS release 6.2 (Final)
Kernel 2.6.32-279.14.1.el6.x86_64 on an x86_64
Password:
sftp> ls file1.txt
file1.txt
Not Found Logic
spawn sftp local@10.0.0.1
Connecting to 10.0.0.1...
CentOS release 6.2 (Final)
Kernel 2.6.32-279.14.1.el6.x86_64 on an x86_64
sftp> ls file2.txt
Couldn't stat remote file: No such file or directory
Can't ls: "/file2.txt" not found
sftp>
So in both cases the script output is "FOUND" which is where I don't get the logic. I am expecting the file name to pop up if the file is present. Else I am expecting to see the message "Could not state .....".
QUESTIONS
Can expect detect a prompt? Can I store it somewhere?
Is there a better way to find the existence of a file on a remote server?
Is my script having issues?
Thank you in advance for the help!
回答1:
Expect
can do whatever tcl
can do. Of course, you can save the prompt into some variable and use it further.
set prompt "sftp> $"
What is this $
symbol doing here ? By default, expect
will match with glob style and ^
is used to match the beginning and $
is to match the end of a string.
You can make use of it in the code as
expect $prompt
Whatever the way you are trying to get is good approach only when it comes to expect
.
I can see some issues in your script. As Brad Lanam pointed out, you should not use filename as match criteria for checking whether the file present or not.
A compromised approach can be written as
#!/usr/bin/expect
if {$argc!=1} {
puts "\nUsage : $argv0 <file-name>\n"
exit
}
set prompt "sftp> $"; # To match 'sftp> ' at the end
set filename [lindex $argv 0]; # User input
set timeout 60; # 1 min
spawn sftp dinesh1,nmd@frs.sourceforge.net; # Replace this with your sftp server
expect "Password:"
send "mypassword\r"
expect $prompt
send "cd htdocs\r"
expect $prompt
send "ls $filename\r"
expect {
"No such file or directory" { puts "\n\n File is not available :( \n\n" }
-re "\n$filename\\s+\n$prompt" { puts "\n\n File is available :) \n\n" }
timeout { puts "\n\n timeout happened :( \n\n" }
}
If file is not available, we are getting the message as No such file or directory
, which is obviously the criteria if file not available.
In case of file present, then the output looks like this,
sftp>ls dinesh.txt
ls dinesh.txt
dinesh.txt
sftp>
You might be wondering why the command ls dinesh.txt
being seen twice in the output. That is because, the spawned process is echoing back the command being sent via send
. (This is different story. Have a look at here to know more about if you are interested)
To match this, I have used regular expressions as
-re "\n$filename\\s+\n$prompt"
What I am trying to match is as follows,
dinesh.txt
sftp>
\n
- to match the new line which is from the previous line
$filename
- this will be replaced with the given file name. i.e. 'dinesh.txt'
\\s+
- to match more than one space
$prompt
- this will be replaced with 'sftp> $'
At last, I have added timeout
, if in case timeout happens with expect
. Default timeout value is 10s and I have changed it to 60s in the script.
Note : How to know there are multiple spaces between file name and the prompt ? Why it can't be like filename, newline and the prompt. By seeing the output we can come to any conclusion like this. There is no magic to find and there is a reason why expect
is brought up with an option of -d
(or exp_internal 1
). Trigger it with those options and you are an expect's expert. :)
来源:https://stackoverflow.com/questions/27641153/expect-script-to-find-file-existence-on-remote-server