1

My shell is dash. My problem is the following:

# A="abc\nde fg"
# printf "$A"
abc
de fg#

# B="abc\\nde fg"
# printf "$B"
abc
de fg#

# C="abc\\\nde fg"
# printf "$C"
abc\nde fg# 

The string variable I'm working with has both spaces and \n and possibly other whitespace characters. I would like to access the variable $A without escaping the \n in the string. Using single quotes would not interpret it as a variable and using double quotes interprets those special characters.

Does dash have a way built in to the shell to do so? I know I can send the variable to an external program that will double the backslashes for the escape characters in the string, but that just feels wrong.

EDIT:

I realize my mistake with printf but it's unrelated in this case. Initially I was using echo. This is a better example of what I'm asking. Here are two of the exact same command sequences, only the first is in bash and the second is in dash:

bash

$ cat sample.txt
abc\nde fg

some string

$ A=`cat sample.txt`
$ echo "$A"
abc\nde fg

some string
$ 

dash

$ cat sample.txt
abc\nde fg

some string

$ A=`cat sample.txt`
$ echo "$A"
abc
de fg

some string
$ 

I would like to know if I can have dash not interpret the \n in this sequence of commands. I have already implemented a workaround using an external command. The proper use of printf does what I want, but I'm curious to see if the dash shell itself has some way of doing this its own.

Here's the reason the question came up, for completeness. I need to read a file and CONDITIONALLY comment or uncomment the bottom part. The first part has a literal \n (not newline) that needs to stay that way in the rewritten file.

I split the file into 2 pieces using sed enclosed in backticks and assign those to variables. At the end I concatenate the variables by simply doing something like "$VAR1$VAR2", where $VAR2 has already been conditionally commented, uncommented, or left alone.

  • I don't understand the question. What you posted as “my problem” is just a bunch of text with no explanation. If you have a string in a variable A then you can use "$A" to get the value of that variable. A variable expansion inside double quotes does not interpret special characters. If that doesn't do what you want then the problem is in a part that you haven't told us about. – Gilles Dec 10 '16 at 23:00
  • @Gilles have edited the question with more detail – jmarsh411 Dec 13 '16 at 14:55
  • Your problem is that the two implementations of echo behave differently. If you don't like dash's echo, perhaps /bin/echo is more to your taste? – Toby Speight Dec 13 '16 at 15:36
  • @TobySpeight this is what I was missing. I didn't realize dash had its own implementation of echo. even after doing a "which echo" in both shells they returned the same thing, so I figured they were calling the same program – jmarsh411 Dec 13 '16 at 15:50
  • type echo is what tells you it's a builtin command (though you still have to realise that it's two different builtins). which echo will always search the path and doesn't know about shell builtins. – Toby Speight Dec 13 '16 at 16:12
2

Your problem is that Bash and Dash both have echo as a builtin, but the two implementations do not behave the same when given a string containing \:

echo 'abc\ndef'

This produces different results on the two shells.


You can get consistent output by using printf '%s\n'; although this is also a builtin, it produces the same output on both shells (this is not true of all conversions, e.g. bash provides a %q conversion which dash does not):

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

This produces abc\ndef in both shells.


You could alternatively use an external implementation of echo; on Linux, coreutils gives you GNU echo in /bin/echo:

/bin/echo 'abc\ndef'

Note, however, that this is less portable. The GNU info file has this to say:

POSIX does not require support for any options, and says that the behavior of echo is implementation-defined if any string contains a backslash or if the first argument is -n. Portable programs can use the printf command if they need to omit trailing newlines or output control characters or backslashes.

  • printf is portable to all POSIX systems (an all but some truly ancient Unix systems). /bin/echo is not. – Gilles Dec 13 '16 at 16:27
4

No, there are many variants of echo. echo is not a portable command.

dash's echo is actually one of the few echo implementations that is UNIX compliant (in that regard at least; dash being not multi-byte aware, there are other areas where it's not compliant on systems that support multi-byte locales for instance).

The UNIX specification requires

echo '\n'

to output two newline characters and

echo -e x

to output -e x<newline>.

While some other shells like AT&T ksh, bash, yash or zsh have settings to alter the behaviour of their echo builtin (the behaviour of the GNU echo command can also be affected by the environment), it's currently not the case for dash.

In any case, you don't want to use echo to output arbitrary data. The standard and portable command for that is printf.

You can find more details including how to implement a different echo as a wrapper function around printf at in the answer to Why is printf better than echo?

2

You're using printf with your variable as the formatting string instead of it being a value interpolated by the formatting string.

Either use echo or use printf the way it was intended. Here are some examples:

A="abc\nde fg" B="abc\\nde fg" C="abc\\\nde fg"
echo "$A"
abc\nde fg

echo "$B"
abc\nde fg

echo "$C"
abc\\nde fg

printf "%s\n" "$A"
abc\nde fg

printf "Here is variable B: %s\n" "$B"
Here is variable B: abc\nde fg

printf "> %s <\n" "$C"
> abc\\nde fg <

Incidentally, by using double quoted strings they are parsed and the backslash character \ is processed. If you define the variables with single quoted strings the entire set of \ characters can also be preserved:

A='abc\nde fg' B='abc\\nde fg' C='abc\\\nde fg'

echo "$A"
abc\nde fg

echo "$B"
abc\\nde fg

echo "$C"
abc\\\nde fg
  • Thank you. Proper use of printf does print what I want, but is not related to my true question. Please see my updated question. – jmarsh411 Dec 13 '16 at 14:57
  • 1
    @JoshuaMarshall In dash, the echo builtin also expands backslashes. Whether echo expands backslashes or not depends on the shell (and for some shells on global options or flags passed to echo). Use printf %s "$A" to print the value of a variable literally. – Gilles Dec 13 '16 at 15:26
  • @Gilles this is exactly what I was missing, though it's not in an answer. I'm new to stackexchange and I don't know how I should resolve this. now that I've edited my question, should the answer be edited before I upvote? – jmarsh411 Dec 13 '16 at 15:41
  • @JoshuaMarshall you can always upvote any question or answer that you find helpful. I'm not sure what else you would want from me here, though. – roaima Dec 13 '16 at 17:19

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.