从 bash 脚本函数内将脚本字符串传递到 ssh - 变量求值问题

从 bash 脚本函数内将脚本字符串传递到 ssh - 变量求值问题

我正在尝试编写一个通过 ssh 运行远程脚本的 bash 脚本,如下所示:

#!/bin/bash
logfilepattern="*drupal*.gz php*.gz error*.gz"
function getlogcounts {
    echo "in getlogcounts"
    echo  $1
    echo  $2

    ssh $1 bash -c '  \  #script string starts here
    cd $2
    for file in `ls $logfilepattern`
    do
     ls -l $file
    done
'
}

getlogcounts [email protected] "/var/log/mylogs"

$1并且$2似乎在函数中遇到了 ok,但在脚本字符串内它们似乎没有值...因此cd $2评估为cdls $logfilepattern评估为ls

答案1

这是一个经过简化的版本,更重要的是,引用已得到纠正(变量周围用双引号,需要时非变量文本周围用单引号)

#!/bin/bash
logfilepattern='*drupal*.gz php*.gz error*.gz'

function getlogcounts {
    echo in getlogcounts
    echo "$1"
    echo "$2"

    ssh "$1" "cd $2 ; ls -l $logfilepattern"
}

getlogcounts [email protected] /var/log/mylogs

答案2

您正在远程计算机上执行脚本。该脚本恰好包含$2and $logfilepattern(单引号之间的文本按字面意思作为参数传递给命令ssh,因此它是在另一侧执行的代码片段)。这些指的是在删除端运行的 shell 的变量。

实际上,您在远程端运行两个 shell,但没有什么用处。 SSH 总是调用 shell;您可以向其传递多个参数,但它们之间只是用空格连接。远程端的shell执行

bash -c   \  #script string starts here
cd $2

第一行使用bash两个参数调用:-c和一个空格。这会调用 shell 不执行任何操作。远程命令的其余部分在 SSH 调用的 shell 中执行。

做你想做的事情的简单方法是

ssh "$1" "cd $2 && ls -l $logfilepattern"

笔记:

  • 解析 的输出ls是没有意义的:for file in `ls *`是一种复杂的书写方式,但如果文件名包含特殊字符,则for file in *解析输出会中断。ls
  • $2和都$logfilepattern被解析为在远程端执行的脚本的一部分。如果它们包含类似的内容$(touch foo),那么将执行该代码段。在这个特定的用例中,这不一定是问题,但您需要注意。
  • 使用&&aftercd可确保命令失败ssh时立即返回失败状态cd

如果您想通过 SSH 将未修改的内容传递到远程 shell,单独使用命令行是有问题的,因为您传递的任何内容都会在远程端扩展。一种经常有效的技巧(但并非总是如此,这取决于客户端和服务器上的 SSH 配置)是使用名称以LC_;开头的变量。这些被假定为有关区域设置的信息,并且经常被传输。

LC_DIRECTORY=$2 LC_LOGFILEPATTERN=$logfilepattern ssh "$1" 'cd "$LC_DIRECTORY" && ls -l $LC_LOGFILEPATTERN'

注意引用:

  • 在远程计算机上执行的命令是cd "$LC_DIRECTORY" && ls -l $LC_LOGFILEPATTERN。使用单引号将该文字文本作为参数传递给ssh命令。
  • $LC_DIRECTORY在远程端执行的脚本中用双引号括起来,以便cd对变量的内容调用该命令。
  • LC_LOGFILEPATTERN不是双引号,因为它是一个以空格分隔的通配符模式列表,这正是处理不带引号的变量扩展的方式。

如果您无法传输变量,则需要添加一层引号来保护值包含特殊字符的变量。

q_directory=$(printf %sa "$2" | sed s/\'/\'\\\'\'/g)
q_directory="'${directory%a}'"
q_logfilepattern=$(printf %sa "$logfilepattern" | sed s/\'/\'\\\'\'/g)
q_logfilepattern="'${q_logfilepattern%a}'"
ssh "$1" "logfilepattern=$q_logfilepattern; cd $q_logfilepattern && ls \$logfilepattern"

相关内容