AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 563985
Accepted
annahri
annahri
Asked: 2020-01-25 16:50:17 +0800 CST2020-01-25 16:50:17 +0800 CST 2020-01-25 16:50:17 +0800 CST

如何 ssh 并运行包含在 if else 中的多个命令?

  • 772

我想使用 ssh 从各种服务器捕获一些数据并在某些条件下运行一些命令。

我不想这样做:

if ssh $host test -f /file; then
  # If file exists
  var=$(ssh $host long pipeline)
else
  # if it doesn't
  var=$(ssh $host another long pipeline)
fi

因为它会使过程更长。我想在远程机器上执行 if else 。


我尝试了几种方法,但我没有运气。

var=$(ssh $host if [ -f /file ]\; then long pipeline1 \; else long pipeline2 \; fi)

基于这个答案,它可以工作,但 pipeline1 的最后一个命令假定它else和 pipeline2 的其余部分作为它的参数。

command: can't read else: No such file or directory
...
command: can't read fi: No such file or directory

然后我尝试了这个

var=$(ssh $host test -f /file \&\& pipeline1 \|\| pipeline2)

同样, pipeline1 的最后一个命令被||视为其参数。


我也在下面尝试过(基于this),它正在工作:

do_this () {
  if [ -f /file ]; then
    pipeline1
  else
    pipeline2
  fi
}
var=$(ssh $host "$(set); do_this")

然而,它会打印不影响我的变量的不需要的错误消息,但它对我的脚本来说很难看。

bash: line 1: BASHOPTS: readonly variable
bash: line 8: BASH_VERSINFO: readonly variable
bash: line 24: EUID: readonly variable
bash: line 71: PPID: readonly variable
bash: line 82: SHELLOPTS: readonly variable
bash: line 92: UID: readonly variable

有什么建议么?


更新

我想我必须包括我的管道是什么,基本上它只是一堆文本处理:

cat file | grep "something" | sed 's/.*="\(.*\)"/\1/' | tr ' ' '-'

根据Jetchisel的回答,简而言之,我必须用单引号括起我的命令。

var=$(ssh $host 'if [ -f /file ]; then cat file | grep "something" | sed 's/.*="\(.*\)"/\1/' | tr ' ' '-' ; else cat otherfile | ... ; fi'

我得到了tr: invalid option -- ';'。tr当作;它的论据。


它使用heredoc:

var=$(ssh $host <<-EOF
  if [ -f file ]; then
    pipeline1
  else
    pipeline2
  fi
EOF
)

然而,由于我在 sed 中使用的正则表达式,它破坏了 vim 的着色。我现在会接受heredoc作为答案。


更新 2:我相信我的问题不是sshpass 中的多个命令的重复,我的情况更具体,而另一个线程一般会问它。

bash shell-script
  • 2 2 个回答
  • 1395 Views

2 个回答

  • Voted
  1. Best Answer
    Stéphane Chazelas
    2020-01-25T22:57:20+08:002020-01-25T22:57:20+08:00

    在:

    ssh host code
    

    ssh实际上运行一个 shell(目标用户的登录 shell)来解释您作为参数传递的代码。如果给出了多个参数,ssh 将它们与空格连接起来,并再次让用户的登录 shellhost解释它。

    通常,您希望将单个代码参数传递给并确保它用单ssh引号引起来,以确保本地 shell 不会进行扩展。

    如果您知道远程用户的登录 shell 类似于 Bourne/POSIX,那么您所要做的就是:

    var=$(ssh "$host" '
      if [ -f /file ]; then
        pipeline1
      else
        pipeline2
      fi'
    )
    

    如果要远程解释的代码必须在其中包含单引号,则需要将它们插入为'\''(保留单引号,插入带引号的(带反斜杠)单引号,重新输入单引号)。

    如果您不能保证远程用户的外壳,并且您不需要通过其标准输入将数据传递给远程命令(并且没有远程命令从其标准输入读取,除非它重定向到其他东西比 ssh 连接),您可以改为:

    ssh "$host" sh << 'EOF'
      if [ -f /file ]; then
        pipeline1
      else
        pipeline2
      fi
    EOF
    

    通过引用第一个EOF,我们确保本地 shell 没有在 here 文档中进行扩展。我们显式调用sh以解释其标准输入上的代码,因此我们知道编写脚本的语法。

    这种方法还避免了必须转义单引号。

    您的

    cat file | grep "something" | sed 's/.*="\(.*\)"/\1/' | tr ' ' '-'
    

    可以写成:

    <file sed '/something/!d; s/.*="\(.*\)"/\1/; y/ /-/'
    

    所以这给了我们:

    ssh "$host" '
      file=/path/to/some/file
      otherfile=/path/to/some/other/file
    
      if [ -f "$file" ]; then
        <"$file" sed '\''/something/!d; s/.*="\(.*\)"/\1/; y/ /-/'\''
      else
        <"$otherfile" ...
      fi'
    

    (如果远程用户的登录 shell 是例如 csh、tcsh、fish、rc、es、akanga,其语法与 Bourne/POSIX-like 语法不同,这将不起作用)

    或者:

    ssh "$host" sh << 'EOF'
      file=/path/to/some/file
      otherfile=/path/to/some/other/file
    
      if [ -f "$file" ]; then
        <"$file" sed '/something/!d; s/.*="\(.*\)"/\1/; y/ /-/'
      else
        <"$otherfile" ...
      fi
    EOF
    
    • 2
  2. Jetchisel
    2020-01-25T17:48:28+08:002020-01-25T17:48:28+08:00

    几年前我做了类似的事情,这就是我的做法。

    首先测试退出状态。

    ssh -t remoteuser@lremotehost 'if [[ -e /etc/fstabs ]]; then exit 0; else exit 127; fi' >/dev/null 2>&1
    

    检查退出状态。

    echo $?
    

    输出是127因为没有/etc/fstabs但/etc/fstab

    现在更改/etc/fstabs以/etc/fstab注意没有尾随s

    ssh -t remoteuser@lremotehost 'if [[ -e /etc/fstab ]]; then exit 0; else exit 127; fi' >/dev/null 2>&1
    

    再次检查退出状态

    echo $?
    

    输出是0因为/etc/fstab在远程机器中有。

    然后只需将其放入变量中并检查退出状态并根据它执行您的脚本。也将退出状态保存在变量中。

    var=$(ssh -t remoteuse@remotehost 'if [[ -e /etc/fstabs ]]; then exit 0; else exit 127; fi; exec bash -li' >/dev/null 2>&1); pid=$?
    
    case $pid in
       0) echo 'good!';;
       *) echo 'bad!' >&2;;
    esac
    

    这就是我在那种情况下幸存下来的方式,我并不是说这是一个完美的解决方案,但你可以检查一下。顺便说一句,我将 ssh 密钥转发到远程主机,因此当我通过 ssh 登录时没有密码检查。我还在两台机器上都使用 bash 作为登录 shell,这就是为什么我exec bash -li最后有

    • 0

相关问题

  • 从文本文件传递变量的奇怪问题

  • 虽然行读取保持转义空间?

  • MySQL Select with function IN () with bash array

  • `tee` 和 `bash` 进程替换顺序

  • 运行一个非常慢的脚本直到它成功

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    模块 i915 可能缺少固件 /lib/firmware/i915/*

    • 3 个回答
  • Marko Smith

    无法获取 jessie backports 存储库

    • 4 个回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    user12345 无法获取 jessie backports 存储库 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl 为什么大多数 systemd 示例都包含 WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve