【发布时间】:2014-02-19 20:16:51
【问题描述】:
我可以使用 scp 传输文件并期待,现在我尝试一次上传多个文件:
#!/usr/bin/expect -f
# Escapes spaces in a text
proc esc text {
return [regsub -all {\ } $text {\\&}]
}
# Uploads several files to a specified server
proc my_scp_multi {ACCOUNT SERVER PW files newfolder} {
set timeout 30
send_user -- "\n"
spawn scp $files $ACCOUNT@$SERVER:[esc $newfolder]
match_max 100000
# Look for password prompt
expect {
-re ".*Connection closed.*" {
sendError "\n\n\nUpload failed!\nPlease check the errors above and start over again.\nThis is most likely induced by too many wrong password-attempts and will last quite a time!"
}
-re ".*Permission denied.*" {
sendError "\n\n\nUpload failed!\nPlease check the errors above and start over again.\nYou entered most likely a wrong password!"
}
-re ".*Are.*.*yes.*no.*" {
send "yes\n"
exp_continue
#look for the password prompt
}
-re ".*sword.*" {
# Send password aka $PW
send -- "$PW\r"
# send blank line (\r) to make sure we get back to gui
send -- "\r\n"
exp_continue
}
send_user -- "Upload successful!\n"
}
set timeout -1
}
当我要上传多个文件时,sh命令是:
scp $a $b $c user@server:$folder,所以我打电话给my_scp_multi "ACCOUNT" "SERVER" "PW" "~/testfileA ~/testfileB ~/testfileC" "~/test/"。这也产生了这个输出:
spawn scp ~/testfileA ~/testfileB ~/testfileC user@server:~/test/
user@server's password:
~/testfileA ~/testfileB ~/testfileC: No such file or directory
似乎将“~/testfileA ~/testfileB ~/testfileC”视为一个文件。但是当我将scp ~/testfileA ~/testfileB ~/testfileC user@server:~/test/ 复制粘贴到控制台时,它工作正常!
我做错了什么?我已经尝试过"\"~/testfileA\" \"~/testfileB\" \"~/testfileC\"" 之类的东西,但根本没有任何效果。
有什么想法或建议吗?
编辑
P.S.:我正在传输相当小的文件。建立联系是转移的最大部分。这就是我希望它在 ONE scp 中完成的原因。
附: 我玩了一下,想出了:
my_scp_multi3 "user" "server" "pw" "~/a\ b/testfileA, ~/a\\ b/testfileB, ~/a\\\ b/testfileC" "~/test"
使用您的第一个解决方案,但 {*}[split $files ","] 和
my_scp_multi2 "user" "server" "pw" "~/a b/testfileA" "~/a\ b/testfileB" "~/a\\ b/testfileC" "~/test"
使用您的第二个解决方案。这打印:
~/a b/testfileA: No such file or directory
~/a\ b/testfileB: No such file or directory
~/a\ b/testfileC: No such file or directory
和
~/a b/testfileA: No such file or directory
~/a b/testfileB: No such file or directory
~/a\ b/testfileC: No such file or directory
(顺便说一句:我当然移动了文件 :))
感谢所有答案,这是我的解决方案:
使用 \n \0 (nullbyte) 作为分隔符,因为它是除了 / 和 \ 之外的唯一符号,不能在文件名中使用。
#!/usr/bin/expect -f
# Escapes spaces in a text
proc esc text {
return [regsub -all {\ } $text {\\&}]
}
# Returns the absolute Filepath
proc makeAbsolute {pathname} {
file join [pwd] $pathname
}
proc addUploadFile {files f} {
if {$files != ""} {
set files "$files\0"
}
return "$files[makeAbsolute $f]"
}
#Counts all files from an upload-list
proc countUploadFiles {s} {
set rc [llength [split $s "\0"]]
incr rc -1
return $rc
}
# Uploads several files from a list (created by addUploadFile) to a specified server
proc my_scp_multi {ACCOUNT SERVER PW files newfolder} {
foreground blue
set nFiles [countUploadFiles $files]
set timeout [expr $nFiles * 60]
send_user -- "\n"
spawn scp -r {*}[split $files "\0"] $ACCOUNT@$SERVER:[esc $newfolder]
match_max 100000
# Look for password prompt
expect {
-re ".*Connection closed.*" {
sendError "\n\n\nUpload failed!\nPlease check the errors above and start over again.\nThis is most likely induced by too many wrong password-attempts and will last quite a time!"
}
-re ".*Permission denied.*" {
sendError "\n\n\nUpload failed!\nPlease check the errors above and start over again.\nYou entered most likely a wrong password!"
}
-re ".*Are.*.*yes.*no.*" {
send "yes\n"
exp_continue
#look for the password prompt
}
-re ".*sword.*" {
# Send password aka $PW
send -- "$PW\r"
# send blank line (\r) to make sure we get back to gui
send -- "\r\n"
exp_continue
}
send_user -- "Upload successful!\n"
}
set timeout -1
}
set fls [addUploadFile "" "a b/testfileA"]
set fls [addUploadFile $fls "a b/testfileB"]
set fls [addUploadFile $fls "a b/testfileC"]
my_scp_multi "user" "server" "pw" $fls "~/test"
【问题讨论】:
-
从技术上讲,目录分隔符和空字节
\0是文件名中唯一不允许使用的字符。换行符是一个有效的文件名字符。在 bash 中尝试:touch $'a\nfile\nname'。这个事实让 shell 脚本编写者和工具开发者头疼不已:这就是为什么 GNU find 有-print0指令,xargs 有-0等等 -
这很痛苦!所以你建议只使用 \0 而不是 \n ?
-
你为什么要构造一个字符串然后拆分它?首先使用一个列表:
foreach f {"a b/A" "a b/B" "a b/C"} {lappend fls [makeAbsolute $f]}; ... spawn ... {*}$files ... -
完全正确。嗯,现在可以了,我懒得改了。
-
因为 Tcl 不是 sh。使用“双引号”或 {braces} 进行分组,而不是依赖转义空格。