如何将一个Here文档通过一个命令管道并将结果捕获到变量中?

19

现在这个命令输出了我需要的值。如何将其捕获到一个变量中,以便我可以在脚本的其余部分使用它?

要求:

  • 脚本需要全部在一个文件中。
  • 如果可能的话,最好不要编写任何临时文件。

.

#!/bin/bash

cat << EOF | xsltproc - ../pom.xml | tail -1
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/"><xsl:value-of select="/project/version"/></xsl:template>
</xsl:stylesheet>
EOF
5个回答

14

cat ... | 不是必需的。

foo=$(sed 's/-/_/g' << EOF
1-2
3-4
EOF
)

我只需要输出的最后一行。如何在其中仍包含一个“| tail -1”呢? - Mark Renouf
6
sed 's/-/_/g' << EOF | tail -1 翻译成中文:使用 sed 's/-/_/g' << EOF | tail -1 命令将输入的所有破折号(-)替换为下划线(_),然后只返回最后一行的结果。 - glenn jackman

14

看起来这个方法可行(基于Ignacio的回答)。通过使用子shell,here-document正确地通过管道传递给xsltproc,同时仍然通过tail进行传递。

VERSION=$((xsltproc - ../pom.xml | tail -1) << EOF
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/"><xsl:value-of select="/project/version"/></xsl:template>
</xsl:stylesheet>
EOF
)

2
我已经玩了一个星期左右的here-docs。这是我在Unix Stack Exchange上回答Is there a way to get actual (uninterpreted) shell arguments in a function or script? 的一部分,可能有助于为您的情况说明它们的用法:

... 摘录: ...

也许你注意到了第二个示例中两个here-doc之间的差异。函数内的here-doc终止符未被引用,而传递给read的终止符则用单引号引用。通过这种方式,shell被指示对带有未引用终止符的here-doc执行扩展,但在其终止符被引用时不要这样做。它在函数中扩展未引用的here-doc时不会出错,因为它要扩展的变量值已经设置为引用字符串,并且它不会解析它两次。

也许你想做的事情涉及将Windows路径从一个命令的输出管道传递到另一个命令的输入中。在here-doc中使用命令替换可以实现这一点:

% _stupid_mspath_fix() { 
> sed -e 's@\\@/@g' -e 's@\(.\):\(.*\)@/drive/\1\2@' <<_EOF_
>> ${1}
>> _EOF_
> }
% read -r _stupid_mspath_arg <<'_EOF_'                    
> c:\some\stupid\windows\place
> _EOF_
% _stupid_mspath_fix ${_stupid_mspath_arg}
/drive/c/some/stupid/windows/place    
% read -r _second_stupid_mspath_arg <<_EOF_                    
> $(printf ${_stupid_mspath_arg})
> _EOF_
% _stupid_mspath_fix ${_second_stupid_mspath_arg}
/drive/c/some/stupid/windows/place

基本上,如果您可以可靠地从某个应用程序输出反斜杠(我在上面使用了printf),那么在$(...)中运行该命令,并将其包含在传递给另一个可以可靠地接受反斜杠作为输入的未引用的heredoc中(例如上面的read和sed),将完全绕过shell对反斜杠的解析。无论这些应用程序是否能够处理反斜杠作为输入/输出,都是您自己需要找出来的事情。 -Mike

0

您无需通过添加 omit-xml-declaration="yes" 来使用 tail -1

VERSION=$(xsltproc - pom.xml << EOF
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:mvn="http://maven.apache.org/POM/4.0.0">
<xsl:output method="text" omit-xml-declaration="yes"/>
<xsl:template match="/"><xsl:value-of select="mvn:project/mvn:version"/></xsl:template>
</xsl:stylesheet>
EOF
)

0
类似于Mark的回答,使用子shell和here文档将所有内容放在管道之前也可以起作用。
VERSION=$((xsltproc - ../pom.xml << EOF
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/"><xsl:value-of select="/project/version"/> 
</xsl:template>
</xsl:stylesheet>
EOF
) | tail -1)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接