源 /dev/stdin 未按预期工作

源 /dev/stdin 未按预期工作

让我们从对我有用的简单测试开始,以检查是否source /dev/stdin可以使用。

# echo -ne 'echo a\necho b\n' | source /dev/stdin
a
b

现在我想获取一个实际的函数。

# echo -ne 'f() { echo a; }\n' | source /dev/stdin
# f
-bash: f: command not found

现在让我们尝试使用临时文件。

# echo -ne 'f() { echo a; }\n' > tempf
# source tempf
# f
a

这样临时文件就可以工作了。但就我而言,这非常不方便,而且我没有看到任何有效的理由说明为什么管道不能正常工作。

# bash --version
GNU bash, version 4.2.53(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

为了完整起见,实际用例是仔细选择将包含文件的哪些部分,以便解决 Gentoo portage 中的限制。

post_src_unpack() {
    if type epatch_user > /dev/null 2>&1; then
        epatch_user || die
    else
        awk \
            '/^# @FUNCTION: / { p = 0 } /^# @FUNCTION: epatch(_user)?$/ { p = 1; } p { print  }' \
            /usr/portage/eclass/eutils.eclass | source /dev/stdin || die
        epatch_user || die
        unset epatch
        unset epatch_user
    fi
}

该代码的目的是从包含大量函数的源文件中提取两个所需的函数epatchepatch_user使它们在当前 shell 中可用,运行其中一个(反过来使用另一个),然后删除它们。最终目标是解决 Gentoo 的限制,即只有继承的 ebuildeutils才能访问epatch_user.

答案1

您可以使用流程替代

source /dev/stdin < <(echo -ne 'f() { echo a; }\n')

或者

source <(echo -ne 'f() { echo a; }\n')

这在 bash 4.1.5 中有效,但由于某种原因在 3.2.48 中不起作用。

答案2

各部分管道跑进独立的进程,或自己的子shell。因此,当您的管道完成时,您当前的 shell 对 function 一无所知f

使用bash( kshpdkshzshmkshshell 来支持这里的字符串),你可以使用:

$ source /dev/stdin <<<'f() { echo a; }'
$ f
a

POSIXly,你应该使用此处文档:

$ . /dev/stdin <<'EOF'
> f() { echo a; }
> EOF

$ f
a

答案3

/dev/stdin管道中的命令是单独的进程,因此一旦管道完成,源自的函数定义就会丢失。这就是为什么管道显示与临时文件的使用不同的结果。

在您的用例中,evalPM 2Ring 建议的方法将是最佳选择。

相关内容