4

I'm trying to store the headers (from stderr) of a curl response in a variable and pipe the body (from stdout) to grep.

Here's my current attempt:

{
  HEADERS=$(curl -vs $URL 2>&1 1>&3-)
  echo "$HEADERS"
} 3>&1 | grep "regex" >> filename
echo "$HEADERS"

When I run the script with bash -x script.sh I see + HEADERS='...' with the expected output, but I can't access them with either $HEADERS nor "$HEADERS" inside and outside the inline group.

The body get's piped through as expected.

André Rüdiger
  • 91
  • 1
  • 11
  • So you want the `grep` output to be on terminal or somewhere else? – anishsane Apr 21 '16 at 09:42
  • 2
    `curl -vs -$URL 2>&1 1>&3-` to `curl -vs $URL 2>&1 1>&3-` – han058 Apr 21 '16 at 09:46
  • Any reason not to just set header as a variable, then grep the variable instead of this complicated pipe ? – 123 Apr 21 '16 at 09:51
  • @anishsane the `grep` output should in this case be appended to `filename`. This part works. – André Rüdiger Apr 21 '16 at 09:59
  • @123 The variable contains the headers from stderr. The `grep` processes the body from stdout. – André Rüdiger Apr 21 '16 at 10:03
  • Does [Store/capture stdout and stderr in different variables](https://stackoverflow.com/questions/11027679/store-capture-stdout-and-stderr-in-different-variables-bash) actually cover what you need to know? It's one level more complex because it has both streams caught in variables, but it is otherwise covering very similar territory. – Jonathan Leffler Apr 21 '16 at 20:45

2 Answers2

2

You lose HEADERS variable due to use of pipes which forks and runs your piped commands in a sub shell and parent shell doesn't see variable created in child shells.

You can do this via a temporary file:

{ f=$(mktemp /tmp/curl.XXXXXX); curl -vs "$URL" 2>"$f" |
grep 'regex' >> filename; HEADERS="$(<$f)"; trap 'rm -f "$f"' EXIT;}

Now HEADERS variable will be populated in parent shell itself by reading temporary file created using mktemp.

anubhava
  • 761,203
  • 64
  • 569
  • 643
2

As anubhava correctly diagnosed, the problem is that you're setting HEADERS in a sub-process, not in the main process of your shell.

You can use Bash's process substitution to avoid the problem, without using temporary files which have to be cleaned up in the event of the shell being interrupted:

HEADERS=""
{ HEADERS=$(curl -vs "$URL" 2>&1 1>&3-); } 3> >(grep "regex" > file)
echo "$HEADERS"

The grep sub-process is hidden by the process substitution. The space between 3> and >(…) is necessary.

Community
  • 1
  • 1
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278