这是我对What platform independent way to find directory of shell executable in shell script? 的回答的摘录,除了小写部分之外,它本身就完全回答了您的问题,在我看来,小写部分已在此处的其他答案中适当地解决了很多次。
我的回答的独特之处在于,当我尝试为另一个问题编写它时,我遇到了您的确切问题 - 如何将函数的结果存储在变量中? strong> 好吧,正如你所看到的,在一些帮助下,我找到了一个非常简单且非常强大的解决方案:
我可以向函数传递一种 messenger 变量,并在必要时用eval 取消对结果函数参数的$1 名称的任何显式使用,并且在函数例程完成后,我使用 eval 和反斜杠引用技巧为我的 messenger 变量分配我想要的值,而无需知道它的名称。
完全公开,虽然这是我的问题的解决方案,但它不是无论如何我的解决方案。以前去过那里几次,但他的一些描述虽然可能很精彩,但有点超出我的范围,所以我认为如果在上一段中包含我自己的版本,其他人可能会受益。当然,一旦我理解了它就很容易理解,尤其是对于这个,我不得不长时间地思考它是如何工作的。无论如何,您可以在Rich's sh tricks 找到更多信息,我还在我自己的答案摘录下方摘录了他页面的相关部分。
...
摘录:
...
虽然还不是严格意义上的 POSIX,但 realpath 自 2012 年以来就是一个 GNU 核心应用程序。完全披露:在我在 info coreutils TOC 中注意到它并立即想到 [the linked] 问题之前从未听说过它,但使用如下所示的功能应该可靠,(很快POSIXLY?),并且,我希望,有效
为其调用者提供绝对来源的$0:
% _abs_0() {
> o1="${1%%/*}"; ${o1:="${1}"}; ${o1:=`realpath "${1}"`}; eval "$1=\${o1}";
> }
% _abs_0 ${abs0:="${0}"} ; printf %s\\n "${abs0}"
/no/more/dots/in/your/path2.sh
编辑: 值得强调的是,此解决方案使用POSIX parameter expansion 首先检查路径是否真的需要扩展和解析,然后再尝试这样做。这应该通过信使变量返回一个绝对来源的$0 (值得注意的例外是它将保留symlinks)作为有效我可以想象它可以做到无论路径是否已经是绝对的。
...
(小修改:在文档中找到realpath 之前,我至少已经缩减了我的 [the version below] 版本,而不是依赖于时间字段 [就像在第一个 ps 命令中所做的那样],但是,公平的警告,在测试了一些之后,我不太相信 ps 在其命令路径扩展能力方面是完全可靠的)
另一方面,你可以这样做:
ps ww -fp $$ | grep -Eo '/[^:]*'"${0#*/}"
eval "abs0=${`ps ww -fp $$ | grep -Eo ' /'`#?}"
...
来自Rich's sh tricks:
...
从 shell 函数返回字符串
从上面的命令替换陷阱可以看出,stdout 不是 shell 函数将字符串返回给调用者的好途径,除非输出采用尾随换行符不重要的格式。当然,对于旨在处理任意字符串的函数,这种做法是不可接受的。那么,有什么办法呢?
试试这个:
func () {
body here
eval "$1=\${foo}"
}
当然${foo} 可以用任何形式的替换来替换。这里的关键技巧是 eval 行和转义的使用。当主命令解析器构造 eval 的参数时,“$1” 被扩展。但是“${foo}” 在这个阶段没有展开,因为“$” 已经被引用了。相反,它在 eval 评估它的参数时被扩展。如果不清楚为什么这很重要,请考虑以下情况:
foo='hello ; rm -rf /'
dest=bar
eval "$dest=$foo"
当然,以下版本是完全安全的:
foo='hello ; rm -rf /'
dest=bar
eval "$dest=\$foo"
请注意,在原始示例中,“$1” 用于允许调用者将目标变量名称作为参数传递给函数。如果您的函数需要使用 shift 命令,例如将剩余参数处理为 “$@”,那么将 “$1” 的值保存在函数开头的临时变量中可能会很有用。