【发布时间】:2017-10-17 17:44:16
【问题描述】:
我在 RHEL6 下使用 bash shell, 我有一个包含三个条目的文本文件..
{text file}
lel
jts
sld
寻找最短的脚本/单行命令来生成单个 ssh 命令以减少我访问机器的次数
{end result}
ssh id@machine "grep -e lel -e jts -e sld {filename}"
【问题讨论】:
我在 RHEL6 下使用 bash shell, 我有一个包含三个条目的文本文件..
{text file}
lel
jts
sld
寻找最短的脚本/单行命令来生成单个 ssh 命令以减少我访问机器的次数
{end result}
ssh id@machine "grep -e lel -e jts -e sld {filename}"
【问题讨论】:
#!/bin/bash
set -eu
txtFile1="$1"
txtFile2="$2"
grepCmd="grep"
for i in $(cat $txtFile1); do
grepCmd="$grepCmd -e $i"
done
ssh id@machine "$grepCmd $txtFile2"
执行如下:
./script "text file" "filename"
【讨论】:
ssh id@machine egrep '\|lel\|jts\|sld' {filename}
ssh 命令行的参数必须被转义,因为 get 扩展了两次
ssh id@machine egrep "$(readarray -t t<file1; printf "%s" "${t[0]}"; printf -- "\|%s" "${t[@]:1}")" file2
其中 file1 是您的 {text file},而 file2 是远程机器上的另一个 {filename}
【讨论】:
如果远程机器有 Gnu grep(甚至可能有其他 grep),您可以使用 -f - 从标准输入一次读取一个正则表达式模式:
ssh id@machine grep -f - {filename} < {patterns.txt}
(请注意,< {patterns.txt} 是您机器上 ssh 命令的重定向。不要引用它以将其作为命令的一部分传递。)
由ssh 构造用于远程执行的命令总是有点脆弱,因为ssh 实际上将命令(或在每个命令参数之间用单个空格字符连接的命令参数)作为单个字符串传递给用户在远程机器,使用-c 选项。这意味着您需要认真考虑如何引用参数,以防万一。当传递的参数来自其他地方时,这尤其令人讨厌,例如您的情况:如果文件的行包含空格或 shell 元字符,那么您需要安排适当地转义这些行,以便远程 shell 将正确解释它们。
Bash 内置的printf 实用程序包含%q 格式代码,这对于构建此类命令行非常有用。例如,以下内容应该安全地引用文件中包含的模式:
ssh id@machine "grep $(
while IFS= read -r; do
printf -- "-e %q " "$REPLY"
done < {patterns.txt}) {filename}"
或者,作为一个可能更具可读性的两行:
mapfile -t patterns < {patterns.txt}
ssh id@machine "grep $(printf -- "-e %q " "${patterns[@]}") {filename}"
【讨论】:
为了给您一些灵活性,您可以使用以下 awk 解决方案,只需生成命令并打印它:
$ awk -v n="id@machine" -v f="filename" '\
{a=((a)?a:"") " -e" $1}END{printf "ssh %s \"grep %s %s\"\n", n, a, f}' text
ssh id@machine "grep -elel -ejts -esld filename"
但是,如果您对实际执行您的 ssh 并获取输出感兴趣,您将需要这样的东西:
$ cat tst.awk
{a=((a)?a:"") " -e" $1} # build up list of "-e ..."
END{
cmd="ssh " n " \"grep " a " " f "\"" # concatenate cmd with vars "n" and "f"
r=((cmd|getline line) > 0 ?line:"") # execute cmd. check for errors.
print r # print result r
close(cmd) # close the cmd
}
你可以这样称呼:
awk -v n="id@machine" -v f="filename" -f tst.awk text
或作为单行:
$ awk -v n="id@machine" -v f="filename" '{a=((a)?a:"") " -e" $1}END{cmd="ssh " n " \"grep " a " " f "\"";r=((cmd|getline line) > 0 ?line:"");print r;close(cmd)}' text
您可以在 bash 脚本中使用它,循环多个机器和文件。你唯一需要做的就是用你的resp替换n和f变量。 bash 变量。
【讨论】: