TCL,期待:带有/ SCP的多个文件

时间:2014-01-28 13:41:32

标签: linux tcl expect scp multiple-files

我能够使用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\""等等,但根本没有任何作用。

有任何想法或建议吗?


EDITS

P.S。:我正在传输相当小的文件。建立连接是转移的最大部分。这就是我希望在一个scp中完成的原因。

P.P.S .: 我玩了一下,想出了:

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"

3 个答案:

答案 0 :(得分:2)

您不希望将文件名作为单个字符串发送。要么这样做:

spawn scp {*}[split $files] $ACCOUNT@$SERVER:[esc $newfolder]

继续引用文件名:

my_scp_multi "ACCOUNT" "SERVER" "PW" "~/testfileA ~/testfileB ~/testfileC" "~/test/"

执行此操作:

proc my_scp_multi {ACCOUNT SERVER PW args} {
    set timeout 30
    send_user -- "\n"
    set files [lrange $args 0 end-1]
    set newfolder [lindex $args end]
    spawn scp {*}$files $ACCOUNT@$SERVER:[esc $newfolder]

然后引用文件名

my_scp_multi "ACCOUNT" "SERVER" "PW" ~/testfileA ~/testfileB ~/testfileC "~/test/"

splat({*})将列表拆分为单个元素,因此spawn命令可以看到多个单词,而不是单个单词。见http://tcl.tk/man/tcl8.5/TclCmd/Tcl.htm

答案 1 :(得分:1)

您可以生成一个shell,然后运行scp命令:

spawn bash
send "scp $files $ACCOUNT@$SERVER:[esc $newfolder]\r"

这允许全局扩展但增加了额外的内务管理,因为在scp进程完成时你需要陷阱,因为你仍然有一个shell运行。 您可以在下面添加到您的预期块:

-re "100%" {
    if { $index < $count } {
        set index [expr $index + 1]
        exp_continue
    }
}

其中index是要传输的文件的数量,并计算nr个文件。

答案 2 :(得分:0)

您应该使用SSH公钥身份验证,而不是使用expect键入密码。正确设置后,scp无需人工输入密码即可正常工作,同时保持系统安全。 expect将为您免除所有麻烦。

如果有一些原因导致您无法使用pubkey,您可能会发现sftp非常有用,因为它接受批处理命令文件为-b batchfile。请参阅man 1 sftp expect实际拆分参数时,这不是一个很好的解决方案