注意:我正在寻找SSH y解决方案在这里,超过巴什一。
我需要通过 ssh 以编程方式执行一系列命令。有很多方法可以做到这一点,但我找不到任何适合我的约束的方法:
一些命令在 shell 中设置变量。因此,我认为我无法使用多个 shell 来完成这项工作。
其中一些变量是函数,而不是普通值,所以我不认为我可以简单地序列化输出来
env
“恢复”旧环境。&&
我需要分别访问每个命令的 stdout、stderr 和退出代码。这使得使用或链接命令变得很困难;
。我相信这也使得使用 变得很困难screen
,因为我们无法可靠地判断命令何时完成。我需要实时访问 stdout、stderr 等,以便我们可以记录输出发生的时间。(我使用“实时”来表示“现在”,而不是“硬实时”或诸如此类的意思)。
更新
为什么我需要单个 bash 会话?因为命令可能会在环境中存储任意变量和函数。例如,运行 是很常见的rvm
,这是由先前运行的命令添加的 bash 函数。
为什么我不能使用&&
或;
?因为我需要 stdout 和 stderr 或每个单独的命令,而这会将它们混合在一起。
为何我无法使用屏幕?因为我们希望自动运行命令,而不是作为交互式会话的一部分。考虑一下这样做的难度:我必须使用输入表单重定向来运行命令,通过重定向输出,然后将结果 scp 回来。我需要 echo$?
来获取退出代码。我无法为 stderr/stdout 加时间戳。我无法使命令超时。而且它会非常容易出错。
答案1
如果你需要能够捕获输出、与 shell 会话交互和/或与 pty 应用程序交互的东西,screen
你可以尝试用更高级语言的 SSH 库编写,比如 Ruby 的网络:SSH。它有一点学习曲线,但我相信可以满足您的所有需求。
答案2
我需要分别访问每个命令的 stdout、stderr 和退出代码。这使得使用 && 或 ; 链接命令变得很困难。
好吧,我不知道我是否真的推荐这个,但是你可以编写一个类似这样的 shell 函数:
function prefix ()
(
PREFIX="$1"
OUT=''
while read -r ; do
OUT="${OUT}${PREFIX}${REPLY}"$'\n'
done
echo "$OUT"
)
function run_cmd ()
{
echo "Running command << $@ >> . . ."
(
( ( "$@" ; echo "\$?: $?" >&3 ) | prefix 'STDOUT: ' >&3 ) 2>&1 \
| prefix 'STDERR: '
) 3>&1
}
然后,如果./foo.sh bar
打印出foo\nbar\n
标准输出和baz\nbip\n
标准错误,并以代码 1 退出,run_cmd ./foo.sh bar
则会打印类似以下内容:
Running command << ./foo.sh bar >> . . .
$?: 0
STDOUT: foo
STDOUT: bar
STDERR: baz
STDERR: bip
这应该允许您链接一系列命令,前提是您使用run_cmd
它们来执行所有需要 STDOUT/STDERR/退出代码的命令。(但由于命令本身在五层深度的子 shell 中运行,因此您不能使用它来run_cmd
运行任何需要设置环境变量以供其他命令使用的命令。希望您没有任何命令两个都给出输出和设置变量?
答案3
你已经看过了吗pssh
?它涵盖了你的大部分需求,只要发挥一些创造力和想象力,它就可能对你有所帮助:
- 可以同时向多个服务器发送命令
- 能够实时输出
- stdout 和 stderr 可以保存到单独的文件中
- 报告服务器 Y 上的命令 X 是否成功
- 可以从 stdin 接收输入并将其发送到服务器
- 具有可配置的超时
等等...
答案4
我还认为 Kyle 的方法是最有希望的。如果这种方法行不通,您可以编写主脚本,使其进入无限循环,在其中查找命令文件,然后获取命令文件,并以可用于您目的的形式提供 stdout、stderr 和退出代码。
然后,您可以通过备用渠道插入命令文件,可能只是scp
或类似的东西。