1

I used many times [``] to capture output of command to a variable. but with following code i am not getting right output.

#!/bin/bash
export XLINE='($ZWP_SCRIP_NAME),$ZWP_LT_RSI_TRIGGER)R),$ZWP_RTIMER'
echo 'Original XLINE'
echo $XLINE 
echo '------------------'
echo 'Extract all word with $ZWP'
#works fine
echo $XLINE  | sed -e 's/\$/\n/g' | sed -e 's/.*\(ZWP[_A-Z]*\).*/\1/g'  | grep ZWP
echo '------------------'
echo 'Assign all word with $ZWP to XVAR'
#XVAR doesn't get all the values
export XVAR=`echo $XLINE  | sed -e 's/\$/\n/g' | sed -e 's/.*\(ZWP[_A-Z]*\).*/\1/g' | grep ZWP` #fails
echo "$XVAR"

and i get:

Original XLINE
($ZWP_SCRIP_NAME),$ZWP_LT_RSI_TRIGGER)R),$ZWP_RTIMER
------------------
Extract all word with $ZWP
ZWP_SCRIP_NAME
ZWP_LT_RSI_TRIGGER
ZWP_RTIMER
------------------
Assign all word with $ZWP to XVAR
ZWP_RTIMER

why XVAR doesn't get all the values?

however if i use $() to capture the out instead of ``, it works fine. but why `` is not working?

7
  • 2
    ...and you don't need export either, unless you want your subprocesses to have access to your variables. And using all-caps names for your own variables contravenes POSIX convention (see fourth paragraph of pubs.opengroup.org/onlinepubs/009695399/basedefs/…) Commented Dec 18, 2015 at 18:05
  • 1
    BTW, sed -e 's/\$/\n/g' doesn't do what you think it does. Frankly, tr '$' '\n' would be a better alternative. Commented Dec 18, 2015 at 18:08
  • 1
    Several of the mistakes here are covered in the bash tag wiki. I suggest you review it. Commented Dec 18, 2015 at 18:10
  • 1
    Please take a look: shellcheck.net Commented Dec 18, 2015 at 18:22
  • 2
    The backticks should work the same as $(), but in strange ways they don't. Here is a simpler example showing a case where backticks don't work as expected: ubuntuforums.org/showthread.php?t=1293395 Commented Dec 18, 2015 at 19:37

2 Answers 2

4

Having GNU grep you can use this command:

XVAR=$(grep -oP '\$\KZWP[A-Z_]+' <<< "$XLINE")

If you pass -P grep is using Perl compatible regular expressions. The key here is the \K escape sequence. Basically the regex matches $ZWP followed by one or more uppercase characters or underscores. The \K after the $ removes the $ itself from the match, while its presence is still required to match the whole pattern. Call it poor man's lookbehind if you want, I like it! :)

Btw, grep -o outputs every match on a single line instead of just printing the lines which match the pattern.

If you don't have GNU grep or you care about portability you can use awk, like this:

XVAR=$(awk -F'$' '{sub(/[^A-Z_].*/, "", $2); print $2}' RS=',' <<< "$XLINE")
Sign up to request clarification or add additional context in comments.

7 Comments

What are you doing here that depends on -P? Strikes me as completely needless reliance on a newer version of GNU grep than otherwise would be necessary. (OTOH, if you used a negative lookbehind to exclude the $, that would make sense).
You're still using -o and -P, both of those GNUisms, in the latter form. Might at least change the latter to -E to support older GNU grep.
@CharlesDuffy Oh, sorry. I just missed that.
Being able to backslash-escape ERE syntax (ie. \+) to use them in BREs is actually a nonportable extension too; better to use -E.
Oh, never knew. But \{1,\} should be portable, isn't it?
|
1

First, the smallest change that makes your code "work":

echo "$XLINE" | tr '$' '\n' | sed -e 's/.*\(ZWP[_A-Z]*\).*/\1/g' | grep ZWP_

The use of tr replaces a sed expression that didn't actually do what you thought it did -- try looking at its output to see.


One sane alternative would be to rely on GNU grep's -o option. If you can't do that...

zwpvars=( )                                     # create a shell array
zwp_assignment_re='[$](ZWP_[[:alnum:]_]+)(.*)'  # ...and a regex
content="$XLINE"
while [[ $content =~ $zwp_assignment_re ]]; do
  zwpvars+=( "${BASH_REMATCH[1]}" )             # found a reference
  content=${BASH_REMATCH[2]}                    # stuff the remaining content aside
done

printf 'Found variable: %s\n' "${zwpvars[@]}"

3 Comments

echo "$XLINE" | sed -e 's/\$/\n/g' seems to work OK for me ...replaces the '$' characters with newlines.
@MarkkuK., doesn't work for me -- maybe we were testing against different implementations of sed.
Excellent call about the backticks impacting backslash interpretation, btw.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.