我需要使用ssh
via Ruby
(网络/SSH) 递归复制文件夹并排除子文件夹。我正在寻找最快的方法来做到这一点,所以rsync
不好。另外,我知道ssh
使用sh
而不是bash
。
在 bash 中我这样做:
cp -r srcdir/!(subdir) dstdir
而且效果很好。但是,当我通过启动脚本时ssh
收到错误
sh: 1: Syntax error: "(" unexpected
因为它正在使用sh
.
我已经检查了sh
手册页,但没有排除文件的选项。
ssh
这是我使用sh
正确的假设吗?有什么替代建议吗?
编辑1:
如果它有用,输出sudo cat /etc/shells
如下:
# /etc/shells: valid login shells
/bin/sh
/bin/dash
/bin/bash
/bin/rbash
/usr/bin/tmux
/usr/bin/screen
编辑2:
好的。所以 bash 是可用的,这似乎不是问题。我已经验证 ssh 实际上正在使用bash
.该问题似乎与括号或感叹号的转义有关。我尝试从 shell (macos) 运行命令,这是实际的命令:
ssh -i .ssh/key.pem [email protected] 'mkdir /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/N; cp -r /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/mesh/!\(constant\) /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/N; ln -s /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/mesh/constant /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/N/constant'
这样我收到一个不同的错误
cp: cannot stat '/home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/mesh/!(constant)': No such file or directory
编辑3:
根据评论我改变了我的命令添加extglob
如果我使用
ssh -i .ssh/key.pem [email protected] 'shopt -s extglob; mkdir /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/N; cp -r /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/mesh/!\(constant\) /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/N; ln -s /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/mesh/constant /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/N/constant'
我收到以下错误:
cp: cannot stat '/home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/mesh/!(constant)': No such file or directory
如果我不逃避括号,我会得到
bash: -c: line 0: syntax error near unexpected token `('
答案1
SSH 在远程系统上运行您的登录 shell,无论远程系统是什么。但!(foo)
需要shopt -s extglob
,您可能没有在遥控器上设置。
试试这个来看看 SSH 是否在远程端运行 Bash:
ssh me@somehost 'echo "$BASH_VERSION"'
如果打印任何内容,但您的启动脚本未设置extglob
,您可以根据传递给的命令手动执行此操作ssh
:
ssh me@somehost 'shopt -s extglob
echo srcdir/!(subdir)'
# or
ssh me@somehost $'shopt -s extglob\n echo srcdir/!(subdir)'
extglob
影响命令行的解析,并且仅在换行符后生效,因此我们必须在那里放置一个文字换行符,分号是不够的。
ssh me@somehost 'shopt -s extglob; echo srcdir/!(子目录)'
同样,如果您用反斜杠转义括号,它们也会像任何其他全局字符一样失去其特殊属性。在这种情况下,这不是您想要做的。
$ touch foo bar; shopt -s extglob; set +o histexpand
$ echo *
bar foo
$ echo !(foo)
bar
$ echo \*
*
$ echo !\(foo\)
!(foo)
答案2
我不知道为什么你认为 rsync 会很慢。复制的速度主要取决于磁盘的速度。 Rsync 有很多选项来指定您想要包含和排除的内容,因此它为您提供了比 shell 通配符更好的控制。
正如 bash 手册所述,只有设置后,!(patter)
bash 才能识别。extglob
在你的例子中你没有设置extglob
.此外,a仍然bash
按原样启动,但会禁用某些扩展以实现兼容性。sh
bash
SSH 服务器将启动用户的登录 shell,如 中指定的/etc/passwd
。您可以更改 shell,或者使用该 shell 启动另一个更适合您需求的 shell。
答案3
首先有一些注意事项:
- ssh 服务器不会开始
sh
解释客户端发送的命令行,它会在远程主机上运行用户的登录 shell,如that-shell -c <the-string-provided-by-the-client>
.远程用户的登录 shell 可以是任何东西。请记住,某些 shell 的语法类似于或tcsh
与的语法非常不同。fish
rc
sh
- 它实际上是一个命令行,或更确切地说是一个字符串(可以包含换行符,所以有几行)。即使您执行
ssh host cmd arg1 'arg 2'
wherecmd
、arg1
andarg 2
是传递给 的三个参数ssh
,ssh
也会将这些参数与空格连接起来并实际将cmd arg1 arg 2
字符串发送到sshd
,远程 shell 会将其拆分为cmd
、arg1
和。arg
2
!(subdir)
是一个 glob 运算符(andksh
也支持 glob 运算符)。与所有 glob 一样,它排除隐藏文件,因此请注意它可能排除其他文件。zsh -o kshglob
bash -O extglob
在这里,为了避免找到远程 shell 的正确语法的问题,您实际上可以告诉其他 shell 启动您想要的 shell,并通过 stdin 向其提供代码(在如何在不知道远程用户的登录 shell 的情况下通过 ssh 执行任意简单命令?)
ssh host 'bash -O extglob -O dotglob' << 'EOF'
cp -r srcdir/!(subdir) dstdir/
EOF
bash -O extglob -O dotglob
是所有主要 shell 都可以理解的命令行,包括类似 Bourne 的 shell、csh、rc、fish...只要bash
安装并位于用户的$PATH
(默认$PATH
,可能由用户的修改)中,上面的内容就可以工作登录 shell 类似于~/.zshenv
for zsh
、~/.cshrc
for csh
、~/.bashrc
for bash
)。
POSIXly(尽管在实践中,您可能会发现更多的系统有一个bash
命令而不是一个pax
命令),您可以这样做:
ssh host sh << 'EOF'
cd srcdir && pax -rw -'s|^\.//\./subdir\(/.*\)\{0,1\}$||' .//. /path/to/destdir/
EOF
-s
将替换应用于正在传输的路径。当该替换扩展为空时,该文件将被排除。问题是替换也适用于符号链接的目标。这就是为什么我们使用.//.
上面的方法来降低符号链接受到影响的可能性。
答案4
如果你想以更快的方式做到这一点,你可以考虑rsync
使用不同的加密算法。这使您可以选择轻松排除等,而不会牺牲太多速度。
rsync -aHAXxv --numeric-ids --progress -e "ssh -T -c arcfour -o Compression=no -x" user@<source>:<source_dir> <dest_dir>
加上将加密添加到以inarcfour
开头的行(如果尚未启用),将为您提供可接受的速度。Ciphers
/etc/ssh/ssh_config
警告:arcfour
加密是不安全感。不要通过不安全的渠道运行此程序。如果您担心使用arcfour
加密从不安全的通道访问服务器,请etc/ssh/ssh_config
使用特定于宿主的源主机的部分 -Host
在 ssh_config 中为源主机创建一个部分,您可以使用Ciphers arcfour
它来镜像上述-c
开关,该arcfour
开关仅将加密限制到该主机。
有关详细信息,请参阅ssh_config
手册页。
但是,如果您的 CPU 支持 AES-NI 指令集,请尝试切换到[电子邮件受保护](是的,这就是密码名称,包括 @ 内容),它将使用速度极快(使用 AES-NI)的 AES128-GCM。
因此,如果 CPU 支持 AES-NI,请更改"ssh -T -c arcfour -o Compression=no -x"
为以获得更安全的结果。"ssh -T -c [email protected] -o Compression=no -x"
解释
同步
- (不要使用
-z
,速度慢得多) a
:存档模式 - 递归,保留所有者,保留权限,保留修改时间,保留组,将符号链接复制为符号链接,保留设备文件。H
:保留硬链接A
:保留 ACLX
:保留扩展属性x
:不要跨越文件系统边界v
: 增加详细程度--numeric-ds
:不要按用户/组名称映射 uid/gid 值- 如果需要同步,请添加
--delete
:从目标目录中删除无关文件(同步期间进行差异清理) --progress
:显示传输过程中的进度
SSH
T
:关闭伪 tty 以减少目标上的 CPU 负载。c arcfour
:使用最弱但最快的 SSH 加密。必须在目标上的 sshd_config 中指定“Ciphers arcfour”。o Compression=no
:关闭 SSH 压缩。x
:如果 X 转发默认打开,请关闭它。
牛肉在ssh
选项中 - 如果您只使用rsync -av
和-e ssh -T -c arcfour -o Compression=no -x"
零件,您也可以获得这些速度。
比较:
- 13.6MB/秒
rsync -az
- 16.7MB/秒
scp -Cr
- 44.8MB/秒
rsync -a
- 59.8MB/秒
sftp
- 61.2MB/秒
scp -r
- 61.4MB/秒
sftp -R 128 -B 65536
- 62.4MB/秒
rsync -a -P -e "ssh -T -c arcfour -o Compression=no -x"
- 143.5MB/秒
scp -r -c arcfour
- 144.2MB/秒
sftp -oCiphers=arcfour
来源:
https://gist.github.com/KartikTalwar/4393116
http://nz2nz.blogspot.com/2018/05/rsync-scp-sftp-speed-test.html