【问题标题】:Iterating array in declared function of bash shell script在 bash shell 脚本的声明函数中迭代数组
【发布时间】:2023-03-09 17:20:01
【问题描述】:

我一直在努力创建一个脚本来将一些文件从本地机器移动到远程服务器。作为该过程的一部分,我有一个可以直接调用或使用“declare -fp”包装并发送到 ssh 命令的函数。到目前为止,我的代码如下所示:

export REMOTE_HOST=myserver
export TMP=eyerep-files

doTest()
{
    echo "Test moving files from $TMP with arg $1"
    declare -A files=(["abc"]="123" ["xyz"]="789")
    echo "Files: ${!files[@]}"
    for key in "${!files[@]}"
    do
        echo "$key => ${files[$key]}"
    done
}

moveTest()
{
    echo "attempting move with wrapped function"    
    ssh -t "$REMOTE_HOST" "$(declare -fp doTest|envsubst); doTest ${1@Q}"
}

moveTest $2

如果我用类似的东西运行脚本

./myscript.sh test dev

我得到了输出

attempting move with wrapped function
Test moving files from eyerep-files with arg dev
Files: abc xyz
bash: line 7:  => ${files[]}: bad substitution

for 循环的字符串扩展似乎无法正常工作。这是预期的行为吗?如果是这样,是否有另一种方法可以通过数组循环来避免这个问题?

【问题讨论】:

  • 你为什么用envsubst
  • @Fravadona 他正在使用它将函数定义复制到远程机器。
  • 你不应该使用envsubst。它依赖于对代码的重新评估。
  • envsubst 正在用空字符串替换 $key
  • 只要写一个脚本,复制到远程机器,然后远程执行。 ssh 并非旨在做你想做的事。

标签: bash shell unix replace declare


【解决方案1】:

如果您确信您的远程帐户的默认 shell 是 bash,则可能如下所示:

moveTest() {
    ssh -t "$REMOTE_HOST" "$(declare -f doTest; declare -p $(compgen -e)); doTest ${1@Q}"
}

如果你不是,它可能是:

moveTest() {
    ssh -t "$REMOTE_HOST" 'exec bash -s' <<EOF
set -- ${@@Q}
$(declare -f doTest; declare -p $(compgen -e))
doTest \"\$@\"
EOF
}

【讨论】:

  • 这行得通。我必须做的唯一更改是添加缺少的结束“)”。应该是 ssh -t "$REMOTE_HOST" "$(declare -f doTest; declare -p $(compgen -e)); doTest ${1@Q}"
【解决方案2】:

我设法在这里找到了答案:https://unix.stackexchange.com/questions/294378/replacing-only-specific-variables-with-envsubst/294400

由于我正在导出全局变量,我可以使用 compgen 获取它们的列表,并将该列表与 envsubst 一起使用来指定要替换的变量。我完成的功能最终看起来像:

moveTest()
{
    echo "attempting move with wrapped function"
    ssh -t "$REMOTE_HOST" "$(declare -fp doTest|envsubst "$(compgen -e | awk '$0="${"$0"}"') '${1}'"); doTest ${1@Q}"
}

【讨论】:

  • 不要使用envsubst完全。你无论如何都不需要它。只需使用 declare -p 复制变量,就像使用 declare -f 复制函数一样。
  • 想想envsubst 在这里做了什么:您将文字数据替换为代码。如果该数据包含无法解析为自身的任何内容,则会带来严重的潜在错误,包括安全风险。
  • ...当被解析为文字时不会返回自身的数据是非常常见的。您在数据中加上与周围数据相匹配的引号,然后您就在那里;数据中的空间,你经常在那里;命令替换等。
  • 有关declare -p 可以安全逃脱但envsubst 不能逃脱的示例,请考虑myVar=$'$(rm -rf ~)\'$(rm -rf ~)\'';当然,该示例是故意恶意的,但我个人遇到的最严重的数据丢失事件是由文件名引起的(该文件名是由于错误指针而被覆盖的内存区域中的内容意外创建的)是处理不安全。
  • @Charles Duffy 使用 -p 是个好主意。如果您愿意,请继续发布完整的答案。如果有效,我会将其标记为正确。
猜你喜欢
  • 2012-11-15
  • 2021-11-05
  • 2014-02-02
  • 2022-10-13
  • 1970-01-01
  • 2020-08-06
  • 2017-05-10
  • 2023-03-17
  • 1970-01-01
相关资源
最近更新 更多