Tcl rsync错误:使用包含“0”的源时*&引用;性格

Tcl rsync错误:使用包含“0”的源时*&引用;性格,tcl,rsync,Tcl,Rsync,在我的TCL脚本中,我使用rsync命令,不幸的是,它拒绝同步包含“*”字符的路径 代码示例: set srs "/users/home/username/common/*" catch {exec rsync -av $src /tmp} res puts $res 输出: building file list ... done sent 29 bytes received 20 bytes 98.00 bytes/sec total size is 0 speedup

在我的TCL脚本中,我使用rsync命令,不幸的是,它拒绝同步包含“*”字符的路径

代码示例:

 set srs "/users/home/username/common/*"
 catch {exec  rsync -av $src /tmp} res
 puts $res
输出:

 building file list ... done

 sent 29 bytes  received 20 bytes  98.00 bytes/sec
 total size is 0  speedup is 0.00
 rsync: link_stat "/users/home/username/common/*" failed: No such file or directory (2)
 rsync error: some files could not be transferred (code 23) at main.c(977) [sender=2.6.9]
    while executing
  "exec  rsync -rLptgov  $src /tmp "

这是因为tcl解释器不像shell那样扩展“*”符号

例如:

$ tclsh
% cd /usr
% exec ls -d *
ls: *: No such file or directory
% exec sh -c "ls -d *"
X11R6
bin
docs
etc
...
为了详细说明所说的内容,您必须显式地构建源文件列表,可能使用
glob
,因此您可以这样做

set cmd [concat [list exec rsync -av] \
                [glob -nocomplain /users/home/username/common/*]]
lappend cmd /tmp
catch {eval $cmd} res
puts $res
或者,使用
{*}
展开
exec
的agment列表(这是针对Tcl>=8.5的),如下所示:

set cmd [concat [list rsync -av] \
                [glob -nocomplain /users/home/username/common/*]]
lappend cmd /tmp
catch {exec {*}$cmd} res
puts $res

更新:修复了示例,使其真正起作用。

规范的写作方式是:

set srs "/users/home/username/common/*"
catch {exec rsync -av {*}[glob $src] /tmp} res
puts $res
这是因为Tcl在默认情况下不扩展glob元字符;这样更安全,也更容易编写正确的代码(很难编写好的shell代码来抵抗这方面的问题),但这确实意味着您需要做一些额外的工作。额外的工作是:

  • 使用
    glob
    命令请求对
    $srs
    进行glob扩展。返回一个列表
  • 通过使用
    {*}
    伪运算符(它不是一个运算符,从技术上讲是一种语法,但它的工作原理非常类似于一个运算符),请求将列表从
    glob
    中展开

  • 如果您使用的是Tcl 8.4(或更早的版本!),那么您可以采用一种不同的方式:

    set srs "/users/home/username/common/*"
    catch {eval [list exec rsync -av] [glob $src] [list /tmp]} res
    puts $res
    

    好的,有时会通过省略
    列表
    位(还有许多更模糊的编写方法!)来缩短时间,但这是一个坏习惯,因为在处理值不“好”的变量时,可能会导致巨大的问题,例如,路径名中的空格。如果您有8.5或更高版本,请使用
    {*}
    。真的。

    我发现最重要的例子是对我有效的那一行。我发现最重要的例子是对我有效的那一行:catch{exec csh-c”/usr/local/bin/rsync-av$src$dest“}res显式使用的解决方案列表未正确完成cmd:/usr/local/bin/rsync-av/users/home/username/common/RCS/users/home/username/common/1/users/home/username/common/2/users/home/username/common/3/tmp结果:无法执行“/usr/local/bin/rsync-av/users/home/username/common/RCS/home/username/commo”:没有此类文件或directory@rkaganov,对不起,这是我的错:
    exec
    希望它的参数“按原样”传递给它,而不是一个列表参数。因此,我修正了我的示例,这样它现在应该可以工作了:第一个变体将
    exec
    嵌入到命令规范中,然后
    eval
    ,而第二个变体使用Tcl 8.5中出现的
    {*}
    语法扩展构造的参数列表。@rkaganov,@GrAnd方法的问题是您通过shell传递命令。这有两个含义:1)现在您的命令字符串经过shell扩展——看看您的调用,想想如果
    $src
    $dest
    中恰好嵌入了空格字符或分号,会发生什么情况。如果您的程序获得
    $src
    和/或
    $dest
    作为用户输入,这甚至会打开漏洞利用的可能性;2) 这是fork+exec的又一个进程。没什么大不了的,但还是。。。