Dan*_*scu 10 bash ssh wildcards
我有一个本地和一个远程主机,都运行 Ubuntu,外壳设置为 bash。在我的主目录中,我有两个文件file-1
和file-2
,分别位于本地主机和名为remote
. 每个主目录中还有一些其他文件,我只想列出匹配file-*
.
在本地,这些会产生预期的结果file-1 file-2
:
$ ls file-*
$ bash -c 'ls file-*'
Run Code Online (Sandbox Code Playgroud)
但是这些命令会返回我的远程主目录中的所有文件。那里发生什么事了?
$ ssh remote bash -c 'ls file-*'
$ ssh remote bash -c 'ls "file-*"'
$ ssh remote bash -c 'ls file-\*'
$ ssh remote bash -c 'ls "file-\*"'
Run Code Online (Sandbox Code Playgroud)
我知道这只会ssh remote 'ls file-*'
产生预期的结果,但为什么ssh remote bash -c 'ls ...'
似乎放弃了传递给 的参数ls ...
?(我还通过管道从远程执行的 ls 输出,它被传递了,所以ls
似乎只有 ls受到影响:ssh remote bash -c 'ls file-* | xargs -I {} echo "Got this: {}"'
。)
Kus*_*nda 14
使用时在远程主机上执行的命令ssh remote bash -c 'ls file-*'
是
bash -c ls file-*
Run Code Online (Sandbox Code Playgroud)
这意味着bash -c
执行脚本ls
。作为位置参数,bash -c
脚本获取远程主机上匹配的名称file-*
(这些名称中的第一个将放入$0
,因此它实际上不是位置参数的一部分)。参数不会传递给ls
命令,因此会列出目录中的所有名称。
ssh
将命令传递到远程主机上执行,并删除一级引号(您在命令行上使用的外部引号集)。您ssh
从中调用的 shell会删除这些引号,并且ssh
不会插入新引号来分隔远程命令的参数(因为这可能会干扰命令使用的引号)。
如果您使用,您可以看到这一点ssh -v
:
[...]
debug1: Sending command: bash -c ls file-*
[...]
Run Code Online (Sandbox Code Playgroud)
其他三个命令你展示的作品相同,但将只设置$0
为字符串file-*
,而不是设置$1
,$2
等的bash -c
外壳。
您可能想要做的是引用整个命令:
ssh remote 'bash -c "ls file-*"'
Run Code Online (Sandbox Code Playgroud)
其中,在ssh -v
调试输出中,被报告为
[...]
debug1: Sending command: bash -c "ls file-*"
[...]
Run Code Online (Sandbox Code Playgroud)
简而言之,您必须确保作为远程命令传递的字符串是您要在本地 shell 的引号删除后运行的命令。
你也可以用
ssh remote bash -c \"ls file-\*\"
Run Code Online (Sandbox Code Playgroud)
或者
ssh remote bash -c '"ls file-*"'
Run Code Online (Sandbox Code Playgroud)