How to pipe a here-document through a command and capture the result into a variable?
Asked Answered
P

5

20

Right now this outputs the value I need on stdout. How can I capture it into a variable so I can use it in the rest of the script?

Requirements:

  • The script needs to be all in one file.
  • I'd prefer not to write any temp files, if possible.

.

#!/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
Philomenaphiloo answered 24/1, 2010 at 21:30 Comment(0)
P
14

This seems to work (based on Ignacio's answer). By using a subshell the here-document is correctly piped into xsltproc while still being passed through tail after.

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
)
Philomenaphiloo answered 24/1, 2010 at 21:57 Comment(0)
A
15

The cat ... | isn't necessary.

foo=$(sed 's/-/_/g' << EOF
1-2
3-4
EOF
)
Abana answered 24/1, 2010 at 21:39 Comment(2)
Well I need the last line of that output only. How do still include a "| tail -1" to that?Philomenaphiloo
sed 's/-/_/g' << EOF | tail -1Car
P
14

This seems to work (based on Ignacio's answer). By using a subshell the here-document is correctly piped into xsltproc while still being passed through tail after.

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
)
Philomenaphiloo answered 24/1, 2010 at 21:57 Comment(0)
E
2

I've been playing around with heredocs for a week or two. Here's an excerpt from my answer to Is there a way to get actual (uninterpreted) shell arguments in a function or script? at Unix Stack Exchange that might help illustrate their use a little for your case:

... EXCERPT: ...

Probably you noticed the difference between the two heredocs in the second example. The heredoc EOF terminator within the function is unquoted, while the one fed to read is quoted with single quotes. In this way the shell is instructed to perform expansion on the heredoc with an unquoted terminator, but not to do so when its terminator is quoted. It doesn't break when expanding the unquoted heredoc in the function because the value of the variable it expands is already set as a quoted string and it doesn't parse it twice.

Probably what you want to do involves piping your Windows path from the output of one command into the input of another dynamically. Command substitution within a heredoc makes this possible:

% _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

So basically if you can reliably output the backslashes from some application (I used printf above), then running that command within $(...) and enclosing that within an unquoted heredoc passed to another application that can reliably accept the backslashes as input (such as read and sed above) will bypass the shell's parsing of your backslashes altogether. Whether or not the applications can handle the backslashes as input/output is something you'll have to find out for yourself.

-Mike

Exuberant answered 26/11, 2013 at 19:10 Comment(0)
T
0

You don't need the tail -1 by adding omit-xml-declaration="yes":

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
)
Tradein answered 11/2, 2022 at 23:57 Comment(0)
W
0

Similar to Mark's answer, with the sub-shell, here document placing all before pipe will also work:

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)
Wizen answered 20/7, 2023 at 5:51 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.