【问题标题】:How to run functions and local resources over SSH in a shell script如何在 shell 脚本中通过 SSH 运行函数和本地资源
【发布时间】:2018-05-25 12:08:02
【问题描述】:

我有一个这样的 shell 脚本文件:

#!/bin/bash

CONF_FILE="/tmp/settings.conf" #settings.conf contains OS_NAME="Caine Linux"
source $CONF_FILE

display_os_name() { echo "My OS is:" $OS_NAME }

#using the function locally works fine
display_os_name
#displays: My OS is: Caine Linux

#using the function on the remote host doesn't work
ssh user@host "$(declare -f); display_os_name"
#displays: My OS is:

如果我删除 -f 并只使用 ssh user@host "$(declare); display_os_name" 它可以工作,但会显示这些错误和警告:

bash: line 10: BASHOPTS: readonly variable
bash: line 18: BASH_VERSINFO: readonly variable
bash: line 26: EUID: readonly variable
bash: line 55: PPID: readonly variable
bash: line 70: SHELLOPTS: readonly variable
bash: line 76: UID: readonly variable

如果我使用ssh user@host "$(declare); display_os_name >/dev/null" 来抑制警告,则只会抑制函数的输出(我的操作系统是:Caine Linux),而不是警告。

有没有办法在远程 SSH 主机上运行本地函数和本地源文件?

【问题讨论】:

  • 这个answer对你有帮助吗?
  • @krampstudio,不,它没有。如果我使用typeset -f,只有远程主机上可以使用该功能,而不是导入的设置文件。
  • 最终,您想在远程主机上使用的所有内容都必须发送到远程主机。 ssh只是一个连接工具,不是分布式计算框架。
  • 2>/dev/null 而不是 >/dev/null 以抑制错误消息而不是标准输出。当然,最好修复这些错误消息的来源。
  • 由于您是sourceing 文件,您可以将其内容放入发送到远程主机执行的字符串中。 ssh user@host "$(</tmp/settings.conf); $(declare -f); display_os_name"

标签: bash shell ssh


【解决方案1】:

一种简单的方法(如果您的本地端是 Linux)是在您的 source 命令之前使用 set -a 启用自动导出;在标准输入上复制/proc/self/environ;并将其解析为远程端的一组变量。

因为BASHOPTSEUID 等不是环境变量,所以可以避免尝试修改它们。 (如果您遵守POSIX recommendations 并为您自己的变量使用小写名称,您甚至可以完全忽略所有大写的变量)。

set -a # enable export of all variables defined, **before** the source operation
source /tmp/settings.conf

import_env() {
  while IFS= read -r -d '' item; do
    printf -v "${item%%=*}" "%s" "${item#*=}" && export "$item"
  done
}

cat /proc/self/environ | ssh user@host "$(declare -f); import_env; display_os_name"

更简单的方法是通过网络复制您想要获取的文件。

ssh user@host "$(declare -f); $(</tmp/settings.conf); display_os_name"

【讨论】:

  • 谢谢查尔斯,我现在尝试了文件复制,它可以工作。该脚本现在很小,因此我可以将变量更改为小写,但这有什么帮助?我怎样才能“完全忽略全大写变量”?谢谢!
  • while 循环内(printf 之前),[[ $item =~ ^[[:upper:]]*= ]] &amp;&amp; continue 是一种跳过全大写名称变量的方法,从而确保您只在内部传输变量命名空间 POSIX 保留供应用程序使用。这里的优点是像LD_PRELOADLD_LIBRARY_PATHLC_LOCALE 等不属于您的脚本但属于本地系统级配置的任何内容都会被忽略;同样,即使有人确实标记了要导出的 shell 变量(BASHOPTS 等),也能确保您的安全。
猜你喜欢
  • 2014-04-02
  • 1970-01-01
  • 1970-01-01
  • 2011-02-09
  • 2017-10-11
  • 2019-09-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多