linux - Bash 命令行参数通过 ssh 传递给 sed

标签 linux bash shell ssh sed

我正在寻找一个简单的脚本来同时在许多主机上执行 SSH 命令,以及哪些主机是由另一个脚本生成的。问题是,当我使用像 sed 这样的 sometihng 运行脚本时,它无法正常工作。

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

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 之类的东西运行时它可以工作但是当我运行时:

[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 命令中的引号会消失。

  1. 我该如何修复我的 bash 命令?
  2. 有没有更好的方法来实现这一目标?

最佳答案

将您的命令的 eval 安全引用版本替换为 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*]")

为什么这能可靠地工作(而其他方法不能):

  • printf %q 知道如何引用要由同一个 shell 评估的内容(因此将始终支持空格、通配符、各种本地引用方法等)。
  • 提供给 ssh 的参数 不会单独传递给远程命令! 相反,它们被连接成一个字符串,传递给 sh -c
  • 但是:printf %q 的输出不能移植到所有 POSIX 派生的 shell!它保证与本地使用的相同 shell 兼容——ksh 将始终在 ksh 中解析来自 printf '%q' 的输出,bash 将解析来自 的输出bash 等中的 printf '%q';因此,您不能安全地将此字符串传递到远程参数向量,因为它是 /bin/sh —— 而不是 bash —— 在那里运行。 (如果你知道你的远程 /bin/sh 是由 bash 提供的,那么你可以安全地运行 ssh "$hostname""$cmd_q" ,但仅在这种情况下)。
  • bash -s 从 stdin 读取要运行的脚本,这意味着将您的命令传递到那里——而不是在参数向量上——确保它将被解析为参数逃脱它的同一个 shell 是 shell 安全的

关于linux - Bash 命令行参数通过 ssh 传递给 sed,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41453540/

相关文章:

linux - 从 Windows 上的 plink.exe 在 Linux 上执行 sudo 命令

linux - 通过 NPM 在 Debian Lenny (5.0) 中安装 Forever - 错误

linux - 如何将cygdrive更改为windows目录结构

linux - 如何正确同时执行多个f90代码?

python - 遍历 .tar.gz 目录并连接文件(不解压缩文件夹)

iphone - 多操作系统与SIngle OS电话和服务器开发

Java URLConnection 适用于 windows,但不适用于 linux

ruby - RVM 不是函数,选择 'rvm use ...' 的 ruby 将不起作用

linux - 几天前显示所有修改文件的Shell脚本

shell - GhostScript 和文件名中的空格