5

The output from an executable (cURL) contains \n. How can such output be displayed with line breaks?

Say the output from an executable is tCL\n1523 memo\n, piping to printf does not show line breaks.

$ echo "tCL\n1523 memo\n"
tCL\n1523 memo\n
$
$ printf "tCL\n1523 memo\n"
tCL
1523 memo
$
$ echo "tCL\n1523 memo\n" | xargs -0 printf '%s'
tCL\n1523 memo\n
$
$ echo "tCL\n1523 memo\n" | awk '{ printf "%s", $0 }
tCL\n1523 memo\n
  • 1
    That is because echo does only interpret sequences as \n if you use the switch -e. – Janka Aug 10 at 14:15
  • 1
    @Janka: In this case OP actually wants echo to not interpret the newlines as they are using echo to simulate the curl output that needs to be interpreted. – Jesse_b Aug 10 at 14:22
5

%s does not interpret escape sequences. You need %b for that:

% echo 'tCL\n1523 memo\n' | xargs -0 printf "%b"
tCL
1523 memo

%
  • 2
    Nice one! I still think command substitution would be better than xargs though, no? – Jesse_b Aug 10 at 14:32
  • 1
    Possibly. In either case the entire output ends up as an argument, and with command substitution the extra xargs step is avoided. – muru Aug 10 at 14:34
  • 1
    You'll probably have to use the input as the format string, after replacing all % with %% – muru Aug 10 at 14:58
  • 1
    @muru printf $0 wouldn't work because escape characters are expanded where the format string is defined, not where it's used, so the 2-char string \n in $0 will remain as such even in the context of a printf format string. You could do gsub()s but then you might run afoul of \\ns. There simply is no equivalent functionality in awk and any workaround would be clunky at best. – Ed Morton Aug 11 at 0:44
  • 2
    I just added said clunky workaround - unix.stackexchange.com/a/534944/133219. – Ed Morton Aug 11 at 1:16
4

You probably need to transform double-backslash to backslash as well, otherwise the input format would be ambiguous.

You can write a sed script to translate backslash-letter escapes. This script only translates the escape sequences that it recognizes and otherwise removes the backslash. I've put in support for newline and tab.

… | sed 's/\\n/\n/g; s/\\t/ /; s/\\\(.\)/\1/g'

The whitespace in s/\\t/ / is a tab character. GNU sed lets you write s/\\t/\t/.

If you also want octal escapes, use a more advanced tool such as Perl. You can make it parse all the escape sequences that it supports.

… | perl -pe 's/\\([0-7]{1,3}|c.|[oxN]\{[^{}]+\}|.)/"\"\\${1}\""/eeg'
3

Here's what it'd take to do what you want with awk. Given this input:

$ printf '%s\n' 'abc\\ndef\nghi'
abc\\ndef\nghi

Note that the first \n is itself escaped and so should be treated literally as \\n. Here's how to get the expected output:

$ printf '%s\n' 'abc\\ndef\nghi' |
    awk '{gsub(/@/,"@A"); gsub(/\\\\/,"@B"); gsub(/\\n/,"\n"); gsub(/@B/,"\\\\"); gsub(/@A/,"@")}1'
abc\\ndef
ghi

If you want other escape sequences interpreted too, e.g. \t, you'd add a separate gsub() for each of those right after the one for \n, e.g.:

awk '{
    gsub(/@/,"@A"); gsub(/\\\\/,"@B")
    gsub(/\\n/,"\n")
    gsub(/\\t/,"\t")
    gsub(/@B/,"\\\\"); gsub(/@A/,"@")
}1'

Those first 2 and last 2 gsub()s are creating a unique string @B, mapping \\ pairs to it to get them out of the way, and then mapping them back after the intended conversions are done.

0

Easy enough: echo -e "tCL\n1523 memo\n"

From man echo:

-e enable interpretation of backslash escapes

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.