Reputation: 5412
I'm writing a bash script that needs to let npm run server
finish running which will output an ID number that I need
npm run server
outputs
running server...
....
...
...
Server version is /id/1345
I need to parse out the 1345
after the command finishes running.
I've attempted the following but without success:
idd=$(npm run server "$domain" &> >(sed -E -e 's:(^.*)(id/)(.*$):\3:g'))
echo $idd
which throws:
run.sh: command substitution: line 27: syntax error near unexpected token `>'
I've also tried:
bundle_counter=$(npm run server "$domain" | sed -E -e 's:(^.*)(/b/)(.*$):\3:g')
which fails.
Upvotes: 1
Views: 787
Reputation: 437803
The error message indicates that you're invoking Bash as sh
(or at least in POSIX-compatibility mode), in which case process substitutions (<(...)
and >(...)
) aren't supported, because they're not part of POSIX.
If your sed
command worked in principle, it would suffice to ensure that your command is run by bash
- invoked by that name, using shebang line #!/bin/bash
.
That said, using an output process substitution is needlessly complicated.
sed
command:Your sed
command doesn't work as intended, because, in the absence of option -n
, sed
still prints all (potentially modified) input lines, not just the (modified) line of interest.
Thus, any line that your s
(substitution) command's regular expression doesn't match, is still printed, as-is.
See Ewan Mellor's helpful answer for a working solution.
Upvotes: 1
Reputation: 402
idd=$(npm run server "$domain" | sed -n -E '$s+id/(.*)$+\1+p')
I piped npm's output to sed, like you did in your second snippet. The -E
flag, which you also used, enables extended regexes. Those aren't even needed here now that I think of it, but it's kind of standard because EREs are more useful.
-n
tells sed to by default not print its buffer when going to the next line. It does more or less the same as when you'd use d
on every input line after all other commands. When using -n
you have to explicitly ask sed to print certain lines, with the p
command – but that's actually not used here, as we'll shortly see!
The $
will make sure that the command is only executed on the last line of the input.
The s
command is the replacement command. You can use any character right after it and that will be s
's delimiter. The classic is /
but here I've used +
since we are using a /
in the needle and this way we don't have to escape the /
. id/(.*)$
is the needle and \1
is the replacement. You don't have to anchor your strings like you do, so a needle of ^(.*)id/(.*)$
and corresponding replacement \2
is equivalent but redundant (and will most likely impose a slight performance overhead).
Because there's no semicolon after s
, p
is actually not a separate command here, but a flag to s
. It will print the buffer iff the s
command was successful in finding something to replace.
Upvotes: 2
Reputation: 6847
idd=$(npm run server "$domain" 2>&1 | sed -E -ne 's:(^.*)(id/)(.*$):\3:p')
2>&1
to merge stderr onto stdout.-n
on the sed command to not print any non-matching lines.p
at the end of the regex to print the match.Upvotes: 2