sh递归副本(cp -r)-如何排除子文件夹


8

我需要运行使用远程脚本ssh通过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。这个问题似乎与括号或感叹号的转义有关。我试图从外壳(macos)运行命令,这是实际的命令:

ssh -i .ssh/key.pem ubuntu@X.X.X.X '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 ubuntu@X.X.X.X '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 `('

3
ssh(好sshd)使用远程用户的登录外壳。可以是任何东西。
斯特凡Chazelas

Unix没有文件夹,只有目录。:)
tchrist

1
在这种情况下,我经常想只在远程主机上开发脚本,然后1)将其保留在那里,ssh插入(如果需要,以编程方式执行),或者2)如果每次更改,将其覆盖,执行通过ssh将其删除,然后将其删除。也许可以采取额外的步骤,但您最终并不会逃脱噩梦和世界各地(而不是远程扩展)的问题。否则,我将始终使用Heredoc格式,例如@StéphaneChazelas在下面使用的格式。
Josh Rumbut

Answers:


10

不管是什么,SSH都会在远程系统上运行您的登录Shell。但是!(foo)require 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; 回声srcdir /!(subdir)'

同样不是说如果您用反斜杠转义了括号,它们就会失去其特殊属性,就像其他任何glob字符一样。在这种情况下,这不是您想要执行的操作。

$ touch foo bar; shopt -s extglob; set +o histexpand
$ echo *
bar foo
$ echo !(foo)
bar
$ echo \*
*
$ echo !\(foo\)
!(foo)

10

我不知道您为什么认为rsync会很慢。副本的速度主要取决于磁盘的速度。Rsync有许多选项来指定要包含和排除的内容,因此它比shell全局控制要好得多。

如bash手册所述,!(patter)仅在extglob设置了bash时才能识别。在您的示例中,您没有设置extglob。此外,bash始于sh依然bash,但会禁止一些扩展的兼容性。

SSH服务器将启动用户的登录Shell,如中所述/etc/passwd。您可以更改外壳,也可以使用该外壳启动另一个更适合您需求的外壳。


我测试了timetime cp -r mesh/!(constant) N->真正的1.04s和time rsync -a mesh/ N --exclude=constant->真正的1.8s
Rojj,

7
@Rojj那是苹果与桔子的比较。一方面,您将-a用于rsync,而不用于cp。这涉及到保留权限和其他属性,因此您实际上并没有做同样的事情。
通配符

6

首先要注意以下几点:

  • ssh服务器不会开始sh解释客户端发送的命令行,而是在远程主机上运行用户的登录外壳,如that-shell -c <the-string-provided-by-the-client>。远程用户的登录外壳可以是任何东西。请记住,有些shell的语法与相似tcshfish或者rc语法与完全不同sh
  • 它实际上是一个命令行,或更确切地说是一个字符串(可以包含换行符,因此包含多行)。即使你ssh host cmd arg1 'arg 2'在那里cmdarg1arg 2三个参数传递给sshssh串接与空间的参数和实际发送的cmd arg1 arg 2字符串sshd,以及远程shell会拆分成cmdarg1arg2
  • !(subdir)是一个glob运算符(和ksh也支持glob运算符)。像所有glob一样,它会排除隐藏文件,因此请注意,可能还会排除其他文件。zsh -o kshglobbash -O extglob

在这里,为避免为远程外壳找到正确的语法而出现问题,您实际上可以告诉其他外壳来启动所需的外壳,并通过stdin向其提供代码(如何执行任意简单命令中列出的选项之一)命令通过ssh在不知道远程用户的登录shell?

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,可能由用户的外壳修改使用诸如~/.zshenvfor zsh~/.cshrcfor csh~/.bashrcfor的登录shell bash

POSIXly(尽管在实践中,您可能会发现bashpax命令更多的系统具有命令),您可以执行以下操作:

ssh host sh << 'EOF'
cd srcdir && pax -rw -'s|^\.//\./subdir\(/.*\)\{0,1\}$||' .//. /path/to/destdir/
EOF

-s将替代应用于正在传输的路径。当替换扩展为空时,将排除文件。问题在于替换也适用于符号链接的目标。这就是为什么我们.//.在上面使用它来减少符号链接受到影响的可能性。


4

我认为不仅ssh限于使用sh。而是取决于目标系统上安装了什么,如何设置用户以及允许使用哪些shell /etc/shells

您是否考虑过该chsh命令?


4

如果您想以快速的方式进行操作,可以rsync使用其他加密算法。这使您可以选择以不多的速度来轻松排除等。

rsync -aHAXxv --numeric-ids --progress -e "ssh -T -c arcfour -o Compression=no -x" user@<source>:<source_dir> <dest_dir>

以及将arcfour加密添加到以Ciphersin 开头的行/etc/ssh/ssh_config(如果尚未启用),则可以达到可接受的速度。

警告:arcfour加密不安全。不要在不安全的通道上运行此命令。如果您担心使用arcfour加密从不安全的通道访问服务器,请更改源主机etc/ssh/ssh_config主机特定部分- Host在ssh_config中为源主机创建一个部分,您可以Ciphers arcfour在其中镜像上述-c开关,该开关arcfour仅将加密限制为此主机。

有关详细信息,请参见ssh_config手册页。

但是,如果您的CPU支持AES-NI指令集,请尝试切换到aes128-gcm@openssh.com(是的,这是密码名称,包括@东西),它将使用非常快的(带有AES-NI的)AES128 -GCM。

因此,使用支持AES-NI的CPU,更改"ssh -T -c arcfour -o Compression=no -x""ssh -T -c aes128-gcm@openssh.com -o Compression=no -x"可获得更安全的结果。

说明

同步

  • (不要使用-z,速度要慢得多)
  • a:存档模式-递归,保留所有者,保留权限,保留修改时间,保留组,将符号链接复制为符号链接,保留设备文件。
  • H:保留硬链接
  • A:保留ACL
  • X:保留扩展属性
  • 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.6 MB /秒 rsync -az
  • 16.7 MB /秒 scp -Cr
  • 44.8 MB /秒 rsync -a
  • 59.8 MB /秒 sftp
  • 61.2 MB /秒 scp -r
  • 61.4 MB /秒 sftp -R 128 -B 65536
  • 62.4 MB /秒 rsync -a -P -e "ssh -T -c arcfour -o Compression=no -x"
  • 143.5 MB /秒 scp -r -c arcfour
  • 144.2 MB /秒 sftp -oCiphers=arcfour

资料来源

https://gist.github.com/KartikTalwar/4393116

http://nz2nz.blogspot.com/2018/05/rsync-scp-sftp-speed-test.html


3
好吧,它们似乎cp -r在远程系统中运行,因此SSH连接使用的加密并不真正相关。自6.7版(2014-10-06)起,默认情况下,无论哪种情况都arcfour被认为是相当糟糕的,并且OpenSSH 会在服务器上将其与其他服务器一起禁用。无论如何,ssh -o Ciphers='aes128-ctr'给我大约90 MB / s,这在1 Gbit / s的链路上应该足够快。
ilkkachu

是的,arcfour坏了,但在这种情况下,它不应该是SECURE shell,而是更“舒适的shell”,不强调加密。我不会在不安全的连接上使用它,这是正确的。如果“ aes128-ctr”足够快,则可以并且应该改用它。
emk2203 '18

有关支持AES-NI的CPU的用法,另请参见我的扩展答案。
emk2203 '18

2

根据我的计算,最快的完整副本始终使用“ tar”(此处假定为GNU tar或兼容)。

mkdir -p photos2 &&
  tar -C photos -cf - --exclude=./.thumbcache . |
  tar -C photos2 -xpf -

tar具有大量的选项来操纵属性,权限和文件选择/排除。例如,上面的命令在复制时不包括名为.thumbcache的顶级子文件夹。


请注意,--exclude=.thumbcache不包括所有.thumbcache文件,而不是只有一个在顶层。使用GNU tar(不是bsdtar),您可以--exclude=./.thumbcache用来仅排除顶级.thumbcache文件。
斯特凡Chazelas
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.