Bash命令行参数通过ssh传递给sed [英] Bash command line arguments passed to sed via ssh

查看:103
本文介绍了Bash命令行参数通过ssh传递给sed的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望编写一个简单的脚本来同时在许多主机上执行SSH命令,而哪些主机正是从另一个脚本生成的.问题是,当我像sed这样使用sometihng运行脚本时,它无法正常工作.

I am looking to write a simple script to perform a SSH command on many hosts simultaneously, and which hosts exactly are generated from another script. The problem is that when I run the script using sometihng like sed it doesn't work properly.

它应该像 sshall.sh {anything} 一样运行,并且它将在列表中的所有节点上运行 {anything here} 部分.

It should run like sshall.sh {anything here} and it will run the {anything here} part on all the nodes in the list.

sshall.sh

#!/bin/bash

NODES=`listNodes | grep "node-[0-9*]" -o`

echo "Connecting to all nodes and running: ${@:1}"

for i in $NODES
do
   :
        echo "$i : Begin"
        echo "----------------------------------------"

        ssh -q -o "StrictHostKeyChecking no"  $i "${@:1}"

        echo "----------------------------------------"
        echo "$i : Complete";
        echo ""
done

当它与 whoami 之类的东西一起运行时,它可以工作,但是当我运行时:

When it is run with something like whoami it works but when I run:

[root@myhost bin]# sshall.sh sed -i '/^somebeginning/ s/$/,appendme/' /etc/myconfig.conf
Connecting to all nodes and running: sed -i /^somebeginning/ s/$/,appendme/ /etc/myconfig.conf

node-1 : Begin
----------------------------------------
sed: -e expression #1, char 18: missing command
----------------------------------------
node-1 : Complete

node-2 : Begin
----------------------------------------
sed: -e expression #1, char 18: missing command
----------------------------------------
node-2 : Complete

…

请注意,引号在发送到远程客户端时在sed命令上消失.

Notice that the quotes disappear on the sed command when sent to the remote client.

  1. 我该如何解决我的bash命令?
  2. 是否有更好的方法来实现这一目标?

推荐答案

将命令的 eval 安全引用版本替换为heredoc:

Substitute an eval-safe quoted version of your command into a heredoc:

#!/bin/bash
#      ^^^^- not /bin/sh; printf %q is an extension

# Put your command into a single string, with each argument quoted to be eval-safe
printf -v cmd_q '%q ' "$@"

while IFS= read -r hostname; do
  # run bash -s remotely, with that string passed on stdin
  ssh -q -o 'StrictHostKeyChecking no' "$hostname" "bash -s" <<EOF
$cmd_q
EOF
done < <(listNodes | grep -o -e "node-[0-9*]")


为什么这可靠地起作用(而其他方法却不行):


Why this works reliably (and other approaches don't):

  • printf%q 知道如何引用同一外壳程序要评估的内容(因此将始终支持空格,通配符,各种本地引用方法等).
  • 赋予 ssh 的参数不会单独传递给远程命令!而是将它们串联成一个字符串,该字符串传递给 sh -c .
  • 但是: printf%q 的输出不能移植到所有POSIX派生的shell!保证与本地使用的同一外壳程序兼容 – ksh将始终解析ksh中 printf'%q'的输出,bash将解析的输出bash中的printf'%q'等;因此,您不能在远程参数向量上安全地传递此字符串,因为它是/bin/sh 而不是 bash 的地方.(如果您知道您的远程/bin/sh 由bash提供,则然后您可以安全地运行 ssh"$ hostname""$ cmd_q" ,但仅在这种情况下).
  • bash -s 从stdin读取要运行的脚本,这意味着将您的命令(而不是参数向量)传递到该位置可确保将其解析为参数逃脱它的目的是安全的shell .
  • printf %q knows how to quote contents to be eval'd by that same shell (so spaces, wildcards, various local quoting methods, etc. will always be supported).
  • Arguments given to ssh are not passed to the remote command individually! Instead, they're concatenated into a string passed to sh -c.
  • However: The output of printf %q is not portable to all POSIX-derived shells! It's guaranteed to be compatible with the same shell locally in use -- ksh will always parse output from printf '%q' in ksh, bash will parse output from printf '%q' in bash, etc; thus, you can't safely pass this string on the remote argument vector, because it's /bin/sh -- not bash -- running there. (If you know your remote /bin/sh is provided by bash, then you can run ssh "$hostname" "$cmd_q" safely, but only under this condition).
  • bash -s reads the script to run from stdin, meaning that passing your command there -- not on the argument vector -- ensures that it'll be parsed into arguments by the same shell that escaped it to be shell-safe.

这篇关于Bash命令行参数通过ssh传递给sed的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆