我已经设置了 ssh 代理,我可以在 Bash 脚本中的外部服务器上运行命令,执行以下操作:
ssh blah_server "ls; pwd;"
现在,我真正想做的是在外部服务器上运行很多长命令。将所有这些括在引号之间会非常难看,我真的宁愿避免多次使用 ssh'ing 来避免这种情况。
那么,有没有一种方法可以让我一次性用括号或其他东西做到这一点?我正在寻找类似的东西:
ssh blah_server (
ls some_folder;
./someaction.sh;
pwd;
)
基本上,只要它是干净的,我会对任何解决方案感到满意。
编辑
为了澄清,我说这是一个更大的 bash 脚本的一部分。其他人可能需要处理脚本,所以我想保持干净。我不想有一个 bash 脚本,其中一行看起来像:
ssh blah_server "ls some_folder; ./someaction.sh 'some params'; pwd; ./some_other_action 'other params';"
因为它非常丑陋且难以阅读。
ssh
调用来调用它?
scp
、ssh
并运行。我认为这将是最干净的方式。
Bash Here Document 怎么样:
ssh otherhost << EOF
ls some_folder;
./someaction.sh 'some params'
pwd
./some_other_action 'other params'
EOF
为避免@Globalz 在评论中提到的问题,您可以(取决于您在远程站点上执行的操作)将第一行替换为
ssh otherhost /bin/bash << EOF
请注意,您可以在 Here 文档中进行变量替换,但您可能必须处理引用问题。例如,如果您引用“限制字符串”(即上面的 EOF
),那么您不能进行变量替换。但不引用限制字符串,变量将被替换。例如,如果您在 shell 脚本中定义了上面的 $NAME
,您可以这样做
ssh otherhost /bin/bash << EOF
touch "/tmp/${NAME}"
EOF
它会在目标 otherhost
上创建一个文件,其名称与您分配给 $NAME
的名称相同。其他关于 shell 脚本引用的规则也适用,但是这里太复杂了。
在本地编辑您的脚本,然后将其通过管道传输到 ssh,例如
cat commands-to-execute-remotely.sh | ssh blah_server
其中 commands-to-execute-remotely.sh
看起来像您上面的列表:
ls some_folder
./someaction.sh
pwd;
( echo $mycmd $myvar ; ...) | ssh myhost
- 与cat 用法一样,您可以确切地知道ssh 命令流中的内容。当然,为了便于阅读,脚本中的子 shell 可以是多行的 - 请参阅 linuxjournal.com/content/bash-sub-shells
commands-to-execute-remotely.sh
中的参数来执行此操作吗?
$localvar
解释本地定义的变量,\$remotevar
远程解释远程定义的变量,\$(something with optionnal args)
获取执行的输出在远程服务器上。您可以通过 1 进行 ssh 的示例(或者,如此处所示,多个 ssh 命令):echo " for remotedir in /*/${localprefix}* ; do cd \"\$remotedir\" && echo \"I am now in \$(pwd) on the remote server \$(hostname) \" ; done " | ssh user1@hop1 ssh user2@hop2 ssh user@finalserver bash
ssh blah_server < commands-to-execute-remotely.sh
)有何不同?
为了匹配您的示例代码,您可以将命令包装在单引号或双引号内。例如
ssh blah_server "
ls
pwd
"
我看到两种方法:
首先,您制作一个这样的控制套接字:
ssh -oControlMaster=yes -oControlPath=~/.ssh/ssh-%r-%h-%p <yourip>
并运行你的命令
ssh -oControlMaster=no -oControlPath=~/.ssh/ssh-%r-%h-%p <yourip> -t <yourcommand>
这样您就可以编写 ssh 命令而无需实际重新连接到服务器。
第二种是动态生成脚本,scp
执行它并运行。
这也可以如下进行。将您的命令放入脚本中,我们将其命名为 commands-inc.sh
#!/bin/bash
ls some_folder
./someaction.sh
pwd
保存文件
现在在远程服务器上运行它。
ssh user@remote 'bash -s' < /path/to/commands-inc.sh
对我来说从来没有失败过。
bash -s
?
ssh user@remote < /path/to/commands-inc.sh
(它似乎对我有用)。好吧,我猜您的版本确保我们使用 bash
外壳,而不是其他外壳 - 这就是目的,不是吗?
将所有命令放到一个脚本中,它可以像这样运行
ssh <remote-user>@<remote-host> "bash -s" <./remote-commands.sh
bash -s
的目的是什么?
man
页 If the -s option is present, or if no arguments remain after option processing, then commands are read from the standard input. This option allows the positional parameters to be set when invoking an interactive shell.
的说明
bash
命令,即 ssh remote-user@remote-host <./remote-commands.sh
。我尝试了我的方法,它似乎有效,但我不确定它是否在某些方面存在缺陷。
不确定是否是最干净的长命令,但肯定是最简单的:
ssh user@host "cmd1; cmd2; cmd3"
SSH 并在 Bash 中运行多个命令。
在字符串中用分号分隔命令,传递给 echo,全部通过管道传递到 ssh 命令。例如:
echo "df -k;uname -a" | ssh 192.168.79.134
Pseudo-terminal will not be allocated because stdin is not a terminal.
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/sda2 18274628 2546476 14799848 15% /
tmpfs 183620 72 183548 1% /dev/shm
/dev/sda1 297485 39074 243051 14% /boot
Linux newserv 2.6.32-431.el6.x86_64 #1 SMP Sun Nov 10 22:19:54 EST 2013 x86_64 x86_64 x86_64 GNU/Linux
这适用于创建脚本,因为您不必包含其他文件:
#!/bin/bash
ssh <my_user>@<my_host> "bash -s" << EOF
# here you just type all your commmands, as you can see, i.e.
touch /tmp/test1;
touch /tmp/test2;
touch /tmp/test3;
EOF
# you can use '$(which bash) -s' instead of my "bash -s" as well
# but bash is usually being found in a standard location
# so for easier memorizing it i leave that out
# since i dont fat-finger my $PATH that bad so it cant even find /bin/bash ..
-s
标志,我引用了他 您可能可以将第一行替换为...,而我无法仅调用 bash 就可以逃脱,我依稀记得。
使用多行字符串和多个 bash 脚本发布的答案对我不起作用。
长的多行字符串很难维护。
单独的 bash 脚本不维护局部变量。
这是一种在保持本地上下文的同时 ssh 和运行多个命令的实用方法。
LOCAL_VARIABLE=test
run_remote() {
echo "$LOCAL_VARIABLE"
ls some_folder;
./someaction.sh 'some params'
./some_other_action 'other params'
}
ssh otherhost "$(set); run_remote"
对于像我一样在这里跌跌撞撞的人-我成功地逃脱了分号和换行符:
第一步:分号。这样,我们就不会破坏 ssh 命令:
ssh <host> echo test\;ls
^ backslash!
列出了远程主机 /home 目录(以 root 身份登录),而
ssh <host> echo test;ls
^ NO backslash
列出了当前的工作目录。
下一步:拆线:
v another backslash!
ssh <host> echo test\;\
ls
这再次列出了远程工作目录 - 改进了格式:
ssh <host>\
echo test\;\
ls
如果真的比这里的文档或虚线周围的引号更好 - 好吧,不是我决定......
(使用 bash,Ubuntu 14.04 LTS。)
ssh host "echo test && ls"
将系统配置为默认使用单 ssh 会话和多路复用的最简单方法。
这可以通过为套接字创建一个文件夹来完成:
mkdir ~/.ssh/controlmasters
然后将以下内容添加到您的 .ssh 配置中:
Host *
ControlMaster auto
ControlPath ~/.ssh/controlmasters/%r@%h:%p.socket
ControlMaster auto
ControlPersist 10m
现在,您无需修改任何代码。这允许在不创建多个会话的情况下多次调用 ssh 和 scp,这在本地和远程机器之间需要更多交互时很有用。
感谢@terminus 的回答,http://www.cyberciti.biz/faq/linux-unix-osx-bsd-ssh-multiplexing-to-speed-up-ssh-connections/ 和 https://en.wikibooks.org/wiki/OpenSSH/Cookbook/Multiplexing。
在 Bash 中 ssh 和运行多个命令的最干净的方法是什么?
我推荐使用这个转义函数。该函数接受一个参数 - 一个要转义的函数。然后 sshqfunc
输出函数的 declare -f
,然后输出一个字符串,该字符串将调用带有正确引用的 "$@"
参数的函数。然后整个被引用 "%q"
并添加 bash -c
。如果遥控器没有 bash,您可以将 bash 更改为 sh。
sshqfunc() { echo "bash -c $(printf "%q" "$(declare -f "$@"); $1 \"\$@\"")"; };
然后用你想在遥控器上做的工作定义一个函数。该函数是正常定义的,因此它将被正确地“干净”。您可以在本地测试此类功能。定义后,将正确转义的函数传递给遥控器。
work() {
ls
pwd
echo "Some other command"
}
ssh host@something "$(sshqfunc work)"
传递 你也可以传递参数,它们将作为位置参数传递给你的函数。函数之后的右下一个参数将分配给 $0
- 通常使用 --
或 _
之类的占位符将参数与调用分开。
work() {
file=$1
num=$2
ls "$file"
echo "num is $num"
}
ssh host@something "$(sshqfunc work)" -- /this/file 5
但请注意,如果有任何魔术字符,也应正确引用参数:
ssh host@something "$(sshqfunc work)" -- "$(printf "%q" "$var1" "$var2")"
对于简单的命令,您可以使用:
ssh <ssh_args> command1 '&&' command2
或者
ssh <ssh_args> command1 \&\& command2
不定期副业成功案例分享