Tcl rsync错误:使用包含“0”的源时*&引用;性格
在我的TCL脚本中,我使用rsync命令,不幸的是,它拒绝同步包含“*”字符的路径 代码示例: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
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的又一个进程。没什么大不了的,但还是。。。