6

Cannot seem to find an answer to this one online...

I have a string variable (externally sourced) with new lines "\n" encoded as strings.

I want to replace those strings with actual new line carriage returns. The code below can achieve this...

echo $EXT_DESCR | sed 's/\\n/\n/g'

But when I try to store the result of this into it's own variable, it converts them back to strings

NEW_DESCR=`echo $EXT_DESCR | sed 's/\\n/\n/g'`

How can this be achieved, or what I'm I doing wrong?

Here's my code I've been testing to try get the right results

EXT_DESCR="This is a text\nWith a new line"
echo $EXT_DESCR | sed 's/\\n/\n/g'

NEW_DESCR=`echo $EXT_DESCR | sed 's/\\n/\n/g'`
echo ""
echo "$NEW_DESCR"
Skytunnel
  • 1,063
  • 2
  • 10
  • 21
  • 3
    How are you inspecting `NEW_DESCR`? – melpomene Aug 28 '18 at 19:31
  • 3
    This works for me: `test=$(echo "testing\nthis" | sed 's/\\n/\n/g') && echo "$test"` consider switch from backticks to `$()` to capture output to a variable. – JNevill Aug 28 '18 at 19:33
  • The comment by @JNevill identifies the problem. See also the answer by @Gunstick to [Backticks vs braces in Bash](https://stackoverflow.com/q/22709371/4154375). In summary: expressions inside backticks (but not `$()`) have a level of quoting removed before they are executed. – pjh Aug 28 '18 at 20:10
  • Is this an XY Question for "how do I turn a JSON string into plaintext?" – that other guy Aug 28 '18 at 21:23

4 Answers4

11

No need for sed, using parameter expansion:

$ foo='1\n2\n3'; echo "${foo//'\n'/$'\n'}"  
1
2
3

With bash 4.4 or newer, you can use the E operator in ${parameter@operator}:

$ foo='1\n2\n3'; echo "${foo@E}"
1
2
3
PesaThe
  • 7,259
  • 1
  • 19
  • 43
  • 2
    Thank you!! Parameter Expansion was originally what I wanted to do when I started yesterday, but could not wrap my head around it! This is awesome! – Skytunnel Aug 28 '18 at 19:41
8

Other answers contain alternative solutions. (I especially like the parameter expansion one.)

Here's what's wrong with your attempt:

In

echo $EXT_DESCR | sed 's/\\n/\n/g'

the sed command is in single quotes, so sed gets s/\\n/\n/g as is.

In

NEW_DESCR=`echo $EXT_DESCR | sed 's/\\n/\n/g'`

the whole command is in backticks, so a round of backslash processing is applied. That leads to sed getting the code s/\n/\n/g, which does nothing.

A possible fix for this code:

NEW_DESCR=`echo $EXT_DESCR | sed 's/\\\\n/\\n/g'`

By doubling up the backslashes, we end up with the right command in sed.

Or (easier):

NEW_DESCR=$(echo $EXT_DESCR | sed 's/\\n/\n/g')

Instead of backticks use $( ), which has less esoteric escaping rules.

Note: Don't use ALL_UPPERCASE for your shell variables. UPPERCASE is (informally) reserved for system variables such as HOME and special built-in variables such as IFS or RANDOM.

melpomene
  • 84,125
  • 8
  • 85
  • 148
2

Depending on what exactly you need it for:

echo -e $EXT_DESCR

might be all you need.

From echo man page:

-e enable interpretation of backslash escapes

mirgleich
  • 23
  • 1
  • 3
2

This printf would do the job by interpreting all escaped constructs:

printf -v NEW_DESCR "%b" "$EXT_DESCR"

-v option will store output in a variable so no need to use command substitution here.

Problem with your approach is use of old back-ticks. You could do:

NEW_DESCR=$(echo "$EXT_DESCR" | sed 's/\\n/\n/g')

Assuming you're using gnu sed as BSD sed won't work with this approach.

anubhava
  • 761,203
  • 64
  • 569
  • 643