我需要使用ssh
via Ruby
( net/ssh )运行远程脚本来递归复制文件夹并排除子文件夹。我正在寻找最快的方法,所以rsync
不好。另外,我知道ssh
使用sh
而不是bash
.
在 bash 我做:
cp -r srcdir/!(subdir) dstdir
Run Code Online (Sandbox Code Playgroud)
它工作正常。但是,当我通过启动脚本时ssh
收到错误
sh: 1: Syntax error: "(" unexpected
Run Code Online (Sandbox Code Playgroud)
因为它正在使用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
Run Code Online (Sandbox Code Playgroud)
编辑2:
好的。所以 bash 它是可用的,这似乎不是问题。我已经验证 ssh 实际上正在使用bash
. 该问题似乎与括号或感叹号的转义有关。我试图从 shell (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'
Run Code Online (Sandbox Code Playgroud)
通过这种方式,我收到了不同的错误
cp: cannot stat '/home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/mesh/!(constant)': No such file or directory
Run Code Online (Sandbox Code Playgroud)
编辑 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'
Run Code Online (Sandbox Code Playgroud)
我收到以下错误:
cp: cannot stat '/home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/mesh/!(constant)': No such file or directory
Run Code Online (Sandbox Code Playgroud)
如果我不转义括号,我会得到
bash: -c: line 0: syntax error near unexpected token `('
Run Code Online (Sandbox Code Playgroud)
Ral*_*edl 10
我不知道你为什么认为 rsync 会很慢。拷贝的速度主要取决于磁盘的速度。Rsync 有许多选项来指定您想要包含和排除的内容,因此它为您提供比 shell globbing 更好的控制。
正如 bash 手册所述,!(patter)
仅在 bash 中extglob
被识别 if被设置。在您的示例中,您没有设置extglob
. 此外,一个bash
开始sh
的仍然是bash
,但为了兼容性会禁用一些扩展。
SSH 服务器将启动用户的登录 shell,如/etc/passwd
. 您可以更改 shell,或使用该 shell 启动另一个更适合您需要的 shell。
ilk*_*chu 10
SSH 在远程系统上运行您的登录 shell,无论是什么。但是!(foo)
requires shopt -s extglob
,您可能没有在遥控器上设置。
试试这个,看看 SSH 是否在远程端运行 Bash:
ssh me@somehost 'echo "$BASH_VERSION"'
Run Code Online (Sandbox Code Playgroud)
如果打印出任何内容,但您的启动脚本没有设置extglob
,您可以通过传递给的命令手动完成ssh
:
ssh me@somehost 'shopt -s extglob
echo srcdir/!(subdir)'
# or
ssh me@somehost $'shopt -s extglob\n echo srcdir/!(subdir)'
Run Code Online (Sandbox Code Playgroud)
extglob
影响命令行的解析,并且只在换行后生效,所以我们必须在那里放一个文字换行,一个分号是不够的。
ssh me@somehost 'shopt -s extglob; echo srcdir/!(subdir)'
也不是如果你用反斜杠转义括号,它们会失去它们的特殊属性,就像任何其他 glob 字符一样。在这种情况下,这不是您想要做的。
$ touch foo bar; shopt -s extglob; set +o histexpand
$ echo *
bar foo
$ echo !(foo)
bar
$ echo \*
*
$ echo !\(foo\)
!(foo)
Run Code Online (Sandbox Code Playgroud)
先说几点:
sh
解释客户端发送的命令行,它会在远程主机上运行用户的登录 shell,如that-shell -c <the-string-provided-by-the-client>
. 远程用户的登录 shell 可以是任何东西。请记住,一些炮弹喜欢tcsh
,fish
或者rc
有来自非常不同的语法sh
。ssh host cmd arg1 'arg 2'
在那里cmd
,arg1
和arg 2
三个参数传递给ssh
,ssh
串接与空间的参数和实际发送的cmd arg1 arg 2
字符串sshd
,以及远程shell会拆分成cmd
,arg1
,arg
和2
。!(subdir)
是 glob 运算符(和ksh
也支持的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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
-s
将替换应用于正在传输的路径。当该替换扩展为空时,将排除该文件。问题是替换也适用于符号链接的目标。这就是为什么我们使用.//.
上面的方法来降低符号链接受到影响的可能性。