Basically, I want to achieve something like the inverse of echo -e.
I have a variable which stores a command output, but I want to print newlines as \n.
Here's my solution:
sed 's/$/\\n/' | tr -d '\n' If your input is already in a (Bash) shell variable, say $varWithNewlines:
echo "${varWithNewlines//$'\n'/\\n}" It simply uses Bash parameter expansion to replace all newline ($'\n') instances with literal '\n' each.
If your input comes from a file, use AWK:
awk -v ORS='\\n' 1 In action, with sample input:
# Sample input with actual newlines created with ANSI C quoting ($'...'), # which turns `\n` literals into actual newlines. varWithNewlines=$'line 1\nline 2\nline 3' # Translate newlines to '\n' literals. # Note the use of `printf %s` to avoid adding an additional newline. # By contrast, a here-string - <<<"$varWithNewlines" _always appends a newline_. printf %s "$varWithNewlines" | awk -v ORS='\\n' 1 awk reads input line by lineORS- the output record separator to literal '\n' (escaped with an additional \ so that awk doesn't interpret it as an escape sequence), the input lines are output with that separator1 is just shorthand for {print}, i.e., all input lines are printed, terminated by ORS.Note: The output will always end in literal '\n', even if your input does not end in a newline.
This is because AWK terminates every output line with ORS, whether the input line ended with a newline (separator specified in FS) or not.
Here's how to unconditionally strip the terminating literal '\n' from your output.
# Translate newlines to '\n' literals and capture in variable. varEncoded=$(printf %s "$varWithNewlines" | awk -v ORS='\\n' 1) # Strip terminating '\n' literal from the variable value # using Bash parameter expansion. echo "${varEncoded%\\n}" By contrast, more work is needed if you want to make the presence of a terminating literal '\n' dependent on whether the input ends with a newline or not.
# Translate newlines to '\n' literals and capture in variable. varEncoded=$(printf %s "$varWithNewlines" | awk -v ORS='\\n' 1) # If the input does not end with a newline, strip the terminating '\n' literal. if [[ $varWithNewlines != *$'\n' ]]; then # Strip terminating '\n' literal from the variable value # using Bash parameter expansion. echo "${varEncoded%\\n}" else echo "$varEncoded" fi You can use printf "%q":
eol=$'\n' printf "%q\n" "$eol" $'\n' $' and ' around the string?printf %q will EITHER output an overall unquoted strings with individual shell metacharacters \ -escaped, OR - if control characters such as newlines and others too (e.g., tabs) are present - an ANSI C-quoted string ($'...'), as in the answer. The purpose of printf % is to get a representation of a string that you can safely use as command arguments or variable values in source code - i.e., the output is usually NOT meant to be used literally.A Bash solution
x=$'abcd\ne fg\nghi' printf "%s\n" "$x" abcd e fg ghi y=$(IFS=$'\n'; set -f; printf '%s\\n' $x) y=${y%??} printf "%s\n" "$y" abcd\ne fg\nghi $x makes its value subject to pathname expansion, so that an input line such as * would yield unexpected results - you could include set -f; at the start of your subshell to suppress pathname expansion.
\ns or actual newlines that you want to convert to\ns?echo -ewould also involve translating additional control chars. into their escape sequences, such as tabs to'\t'. Based on the accepted answer, however, it seems that handling newlines is sufficient in this case.