1

If I want to set a value like:

key="some"
value=$(cat ${filename} | grep ${key}"string" | cut -d 'string' -f2)

What do I do to get the ${key}"string" to work? It doesn't handle the ${key} variable to concatenate it with string. I want to do:

cat $filename | grep "somestring" | cut...
DavidA
  • 21
  • 4
  • `key=some; echo 'somestring' | grep -o "${key}s"` outputs `somes` – Ruslan Osmanov Oct 29 '16 at 12:34
  • What you are doing should work. – mkj Oct 29 '16 at 12:36
  • yeah, thanks, something must be wrong with the cut piece – DavidA Oct 29 '16 at 12:48
  • Use one call to `awk`: `awk -v k="$key" '$0 ~ k"string" {print $2}' "$filename"` – chepner Oct 29 '16 at 12:59
  • @chepner: It looks like the desired logic is: output what comes _after_ the match, so you can't use the default `FS`; `awk -F "${key}string" 'NF >= 2 { print $2 }'` may work (assuming just 1 match per line and escaping of regex metacharacters in the field-separator string, if needed). – mklement0 Oct 29 '16 at 13:27
  • 1
    Note that you should avoid the [Useless Use of `cat` — UUoC](https://stackoverflow.com/questions/11710552/useless-use-of-cat/11710888#11710888). – Jonathan Leffler Oct 30 '16 at 03:13

1 Answers1

3

To properly concatenate variable reference ${key} with literal "string", embed the variable reference inside the double-quoted string:

key="some"
... | grep "${key}string" | ...

Note how enclosing the variable name in {...} is actually required now, to tell the shell where the variable name ends. chepner points out in a comment elsewhere:
"${key} is the canonical way to perform parameter expansion. The braces can optionally be dropped when they aren't necessary to enclose an expansion operator or to disambiguate the parameter name. "

With the specific sample value "some", your concatenation (${key}"string") would have worked the same, but not generally, because using ${key} unquoted makes it subject to shell expansions, notably word splitting, which will break the grep command if the value of variable ${key} happens to contain whitespace.


The main problem with your code, however, is that you're passing a multi-character string to cut -d in order to specify a delimiter, whereas only a single character is supported.

If you have GNU grep, you can try the following:

key="some"
value=$(grep -Po "${key}string"'\K.*$' "${filename}") 

This will return everything after "${key}string" from matching lines, which is what I presume your intent was.
The assumption is that "${key}string" matches at most once per line.

The small caveat is that you now may have to escape regular-expression metacharacters such as . in the value of ${key} and also the literal part ("string") to make it work as a regular expression.

With the same assumption and caveat, you can try this POSIX-compliant awk solution:

key="some"
value=$(awk -F "${key}string" 'NF >= 2 { print $2 }')

That said, if there could be multiple matches, and you needed the strings between the matches on each line, it is possible to adapt this solution.

Community
  • 1
  • 1
mklement0
  • 382,024
  • 64
  • 607
  • 775