我有一个函数可以打印几行,我想将它们用作另一个函数的参数:
lsx() {
echo 1 is one
echo 2 are two
}
somefun() {
for arg in "$@"; do
echo "arg='$arg'"
done
}
我怎样才能“优雅地”somefun()
使用来自的行lsx()
作为参数进行调用?
我现在所做的是使用循环遍历行(编辑:由于 while+subshell,这不起作用)。我认为应该有一种简单的(甚至是便携式的?)方法,但无法想出一种方法。while
,将行存储在数组中,但这看起来很丑陋而且太有效了。
(如果somefun
是外部命令那么我就使用参数但事实并非如此。)
答案1
没有 xargs
$ ( IFS=$'\n'; somefun $(lsx) )
arg='1 is one'
arg='2 are two'
使用子 shell 是为了使更改IFS
是本地的,而不是全局的。
局限性:这会使 的输出受到lsx
路径名扩展的影响,这可能是也可能不是问题。
与 xargs
要使用 xargs 访问 shell 函数,我们需要运行 shell。要访问somefun
子 shell,我们首先需要导出它。因此:
$ export -f somefun
$ lsx | xargs -d'\n' bash -c 'somefun "$@"' SomeFun
arg='1 is one'
arg='2 are two'
第一个参数bash
被分配给$0
并用作错误消息中的程序名称。这可以是任意单词。在这里,我们使用SomeFun
.
路径名扩展问题的示例
$ lsx() { echo '1 is one*'; echo '2 are two*'; }
$ touch '1 is one'{1..3} two{a..c}
$ ( IFS=$'\n'; somefun $(lsx) )
arg='1 is one1'
arg='1 is one2'
arg='1 is one3'
arg='2 are two*'
正如您所看到的,输出的第一行被扩展为三行。
shell 首先执行分词在 的输出上$(lsx)
。由于 IFS 设置为换行符,因此输出被分成几行。然后 shell 执行路径名扩展。由于存在与 glob 匹配的文件1 is one*
,因此该 glob 会扩展为这些名称的列表。在我们的示例中,没有与 glob 匹配的文件2 is two*
,因此该 glob 不会扩展。 (在默认的 IFS 下,2 is two*
将被分成三个单词,第三个单词将匹配文件twoa
、twob
和twoc
。)
该xargs
方法避免了路径名扩展:
$ export -f somefun
$ lsx | xargs -d'\n' bash -c 'somefun "$@"' SomeFun
arg='1 is one*'
arg='2 are two*'
答案2
简单的解决方案:
IFS="
"
somefun $(lsx)