如何在不分支子shell的情况下获得shell函数的输出?

时间:2011-09-21 16:03:42

标签: bash shell zsh

我有以下功能。

hello () {
        echo "Hello"
}
func () {
        hello
        echo "world"
}

如果我不希望打印hello函数的输出但想要对它做一些事情,我想在某个变量中捕获输出,唯一可能的方法是分叉子shell,如下所示?这不是一个不必要的新子进程创建吗?这可以优化吗?

func () {
        local Var=$(hello)
        echo "${Var/e/E} world"
}

6 个答案:

答案 0 :(得分:3)

您可以使调用者传递变量名来保存输出值,然后在函数内创建一个具有该名称的全局变量,如下所示:

myfunc() { declare -g $1="hello"; }

然后将其称为:

myfunc mystring
echo "$mystring world" # gives "hello world"

因此,您的功能可以重写为:

hello() {
    declare -g $1="Hello"
}

func() {
    hello Var
    echo "${Var/e/E} world"
}

唯一的限制是用于保存输出值的变量不能是本地的。

关于使用namerefs的相关文章:

答案 1 :(得分:2)

一个丑陋的解决方案是暂时替换echo,以便设置一个全局变量,您可以从函数中访问该变量:

func () {
  echo () {
    result="$@"
  }
  result=
  hello
  unset -f echo
  echo "Result is $result"
}

我同意这是令人讨厌的,但避免使用子贝壳。

答案 2 :(得分:2)

如何使用文件描述符和Bash here字符串?

hello () {
    exec 3<<<"Hello"
}

func () {
    local Var
    exec 3>&-
    hello && read Var <&3
    echo "${Var/e/E} world"
    exec 3>&-
}

func

答案 3 :(得分:2)

不是bash的答案:至少有一个shell, ksh 优化命令替换[trace] ?- isTaughtBy(jack,doe). Call: (8) isTaughtBy(jack, doe) ? creep Call: (9) teaches(doe, _18526) ? creep Exit: (9) teaches(doe, cs01) ? creep Call: (9) student(jack, _18526, _18528, _18530) ? creep Exit: (9) student(jack, 100, 21, m) ? creep Call: (9) takes(100, cs01) ? creep Exit: (9) takes(100, cs01) ? creep Exit: (8) isTaughtBy(jack, doe) ? creep true ; Redo: (9) takes(100, cs01) ? creep Fail: (9) takes(100, cs01) ? creep Fail: (8) isTaughtBy(jack, doe) ? creep false. 而不是为内置命令生成子shell。当您的脚本倾向于执行大量这些操作时,这非常有用。

答案 4 :(得分:1)

您可以选择修改hello()函数吗?如果是这样,那么给它一个选项,将结果存储在变量中:

#!/bin/bash

hello() {
  local text="hello"

  if [ ${#1} -ne 0 ]; then
    eval "${1}='${text}'"
  else
    echo "${text}"
  fi
}

func () {
  local var     # Scope extends to called functions.
  hello var
  echo "${var} world"
}

还有更紧凑的hello()版本:

hello() {
  local text="hello"
  [ ${#1} -ne 0 ]  && eval "${1}='${text}'" || echo "${text}"
}

答案 5 :(得分:0)

这并不能从字面上回答这个问题,但是对于某些用例,这是一种可行的替代方法...

这是@Andrew Vickers的衍生产品,您可以依靠eval

而不是定义一个函数,而是定义一个我称之为“宏”(C语言等效项)的东西:

MACRO="local \$var=\"\$val world\""

func()
{ 
    local var="result"; local val="hello"; eval $MACRO; 
    echo $result; 
}