我似乎被困在这里。我想通过SSH将脚本中的系统请求发送到另一台服务器,检查是否存在文件夹。文件夹路径是从另一个脚本传递的,存储在变量中,并且其中可能包含空格。由于无法用其他字符替换空格,因此要避免在“ foo bar”之类的文件夹中出现“找不到”的情况,我需要传递类似
ls '/folderpath/foo bar'
到其他服务器的外壳。
示例代码如下:
$cmd = 'ssh -i id_pub $ssh_addr ls $remote_dir';
if (system($cmd) == 0) {
do something
}
我已经用尽了所有可能的选项-在将\传递给命令之前,累了用\逃避可能的空间,试图在内部将'',“”传递给它,并在将它们都传递给$ cmd之前添加了两者。 但是我总是以这样的结尾:
ls \folderpath\foo\\ bar or ls \' \folderpath\foo bar\'
但不是ls '\folderpath\foo bar'
我对Perl不太满意,有经验的人可以推荐解决方法吗?
答案 0 :(得分:5)
运行本地shell并使用它来逃逸命令,以确保远程shell的安全,如下所示:
system('env', "ssh_addr=$ssh_addr", "remote_dir=$remote_dir", 'bash', '-c',
'printf -v remote_cmd "%q " ls -- "$remote_dir"; ssh "$ssh_addr" "$remote_cmd"');
与仅使用"'$remote_cmd'"
不同,上述方法适用于所有可能的值,包括有意的恶意值,只要您的远程外壳程序也是bash。
感谢@ikegami's answer演示了使用选项结束标记--
来确保即使将以破折号开头的remote_dir
值也解析为位置ls
答案 1 :(得分:5)
String::ShellQuote的shell_quote
在构建Shell命令时很有用。
my $remote_cmd = shell_quote("ls", "--", $remote_dir);
my $local_cmd = shell_quote("ssh", "-i", "id_pub", $ssh_addr, $remote_cmd);
system($local_cmd);
当然,可以避免在本地使用shell,如下所示:
use String::ShellQuote qw( shell_quote );
my $remote_cmd = shell_quote("ls", "--", $remote_dir);
system("ssh", "-i", "id_pub", $ssh_addr, $remote_cmd);
答案 2 :(得分:2)
好的,您可以通过这种方式扩展外壳。
首先使用system()和一个字符串。这将破坏您在空格字符上的所有路径。您可以通过将系统用作列表来解决此问题
system('ssh', '-i', 'id_pub', $ssh_addr, 'ls', $remote_dir)
现在我们仍然有一个问题,因为ssh将在具有shell扩展的shell中在远程服务器上运行远程代码,这将再次破坏空格上的路径
因此,您需要将$ remote_dir放在'
字符内,以阻止远程Shell破坏路径:给定
system('ssh', '-i', 'id_pub', $ssh_addr, 'ls', "'$remote_dir'")
希望这对您有所帮助/有效
请注意,正如下面的评论者所述,这是假设$ remote_dir中没有'
个字符。您需要转义或解析$ remote_dir以确保您不会获得类似/file.txt'; rm -rf / #
的路径,该路径将尝试删除远程系统上的每个文件
答案 3 :(得分:1)
让Net::OpenSSH为您照顾一切:
my $ssh = Net::OpenSSH->new($ssh_addr);
$ssh->error and die "unable to connect to remote host: " . $ssh->error;
if ($ssh->test('test', '-d', $remote_dir)) {
# do something here!
}
哦,看来您在Windows机器上!您可以在此处以类似的方式使用Net::SSH::Any。