【问题标题】:BASH: How to echo output from function that edits global variableBASH:如何从编辑全局变量的函数中回显输出
【发布时间】:2019-08-12 08:31:21
【问题描述】:

一般来说,当函数正在编辑全局变量时,如何回显函数的输出?这里的最佳做法是什么?

我尝试在子shell 中调用该函数作为echo 的参数。但是没有为父环境编辑全局变量。

declare -a ARR
f () {
  ARR+=("$1")
  echo "added $1"
}
echo $(f a)
f b
f c
echo "${ARR[@]}"

我期望输出:

added a
added b
added c
a b c

但我得到了

added a
added b
added c
b c

【问题讨论】:

  • echo $(f a) 更改子 shell 中的数组变量,而该更改在父 shell 中不可用。
  • subshell as an argument to echo. But then the global variable is not edited - 这正是 subshel​​l 的工作原理。
  • 不要使用全局变量。可能是g() { printf "%s " "$1" >> g.all; echo "added $1"; } 之类的东西,完成后检查g.all

标签: bash


【解决方案1】:

如何在函数编辑全局变量时回显该函数的输出?

您可以使用临时文件:

tmp=$(mktemp)
f > "$tmp"
output="$(<"$tmp")"
rm "$output"
echo "$output"

这里的最佳做法是什么?

这是主观的和基于意见的。不要抓取函数的输出。如果你有一个修改全局状态的函数,为什么不也使用一些全局变量来传递输出呢?

f() {
   declare -g -a ARR
   ARR+=("$1")
   declare -g f_log
   f_log+="added $1"
}
f
echo "$f_log"

留下函数的stdout 用于一些日志记录和错误报告。没有理由去抓取函数输出,它已经是一个函数了,它可以以任何方式修改程序的状态。

旁注:

我最近尝试将一个函数的标准输出交错用于数据和输出,我这样做了:

f() {
    source /dev/stdin <<<"$1"
    shift 1
    ARR+=("$1")
    declare -p ARR
    echo
    echo "added $1"
}
tmp=$(f "$(declare -p ARR)" a)
source /dev/stdin < <(<<<"$tmp" sed -n '0,/^$/p')
echo "$(<<<"$tmp" sed '0,/^$/d')"

这实际上增加了更多的麻烦,这是值得的。

【讨论】:

  • 谢谢!那么 Bash 中的函数不接受输入并产生输出的想法?函数的想法是只通过全局变量来编辑程序状态吗?
  • 看起来过于简单化了。函数的“理念”是让程序员在设计他们的程序流程时具有灵活性。所以你可以做你想做的事。问题仍然是“你想要什么”。我的观点是,最好的函数根本不涉及全局变量,只转换 stdin + arguments -&gt; stdout 基础。我的第二个代码 sn-ps 尝试在单个标准输出混合中混合变量和数据,方法是用空换行符分隔它们,然后过滤标准输出。在 bash 中设计面向对象的原则很难,变量没有范围,很难传递状态
  • 在 bash 中设计 OOP 时使用全局变量更容易,您可以在网上找到很多示例。我通常使用带有一些字符串后缀的文本名称来传递对象状态,并将该全局变量用于状态,例如 obj_do() { declare -g "$1"_state; # use and update "$1"_state; }; 并使用 obj_do 'obj1' 'some arg' 调用它。
猜你喜欢
  • 1970-01-01
  • 2018-02-04
  • 1970-01-01
  • 2013-10-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-27
  • 1970-01-01
相关资源
最近更新 更多