6

I use a very simple makefile with TeX:

test-makefile:
    echo '\newcommand{\seance}{seance1}' > seances/seance.tex

I run it:

$ make test-makefile 
echo '\newcommand{\seance}{seance1}' > seances/seance.tex

My problem is that the file created in the folder named "seances" does not contain the two first characters it should contain:

 
ewcommand{\seance}{seance1}

The first line of it being empty.

Of course I can protect the first antislash: echo '\\newcommand{\seance}{seance1}, etc. But in the real world it does not work: my real makefiles (I have posted an ECM) don't work.

What happens? How can bash/debian misunderstand the beginning of the command?



By the way:

$ bash --version
GNU bash, version 4.4.19(1)-release (x86_64-pc-linux-gnu)
 
$ cat /etc/debian_version
buster/sid
 
$ uname -a
Linux giljourdan 4.16.0-1-amd64 #1 SMP Debian 4.16.5-1 (2018-04-29) x86_64 GNU/Linux
Pathe
  • 61
  • Thank you for your replies. Do you think this makefile would work flawlessly with zsh? This because it comes from a zsh user. – Pathe Jun 06 '18 at 17:20
  • Since zsh is less compatible to a standard shell, you would introduce a higher portential for failures. If you configure your Makefile tu use zsh and you try to run it in a system where zsh is not installed, it will fail completely. – schily Jun 06 '18 at 17:52
  • \n means "new line" – JacobIRR Jun 06 '18 at 23:12

2 Answers2

12

Your echo is one of those that interprets backslash-escapes. A \n means a newline, so you get exactly that. The latter backslash comes as-is, since \s isn't a valid escape code.

Make runs the commands through a shell, using /bin/sh by default, and on Debian that's dash. Dash's builtin echo does process backslashes. Bash's doesn't. (And neither does the external /bin/echo on Debian, not that it matters unless you explicitly run /bin/echo).

Your best bet is to use printf explicitly, it's at least safe in that it always processes backslash-escapes. The below should always do the same thing, the \\n at the start produces a real backslash and an n, the \n later produces a newline to end the line.

foo:
        printf '\\newcommand\n' > foo

(or, if you want to avoid processing backslashes, then use printf "%s" '\newcommand')

See the question Why is printf better than echo? for more details about echo gotchas.

ilkkachu
  • 138,973
-5

Your echo is POSIX compliant and expands C backslash escapes. This is most likely because /bin/sh is dash instead of bash.

There is a simple fix: add another backslash to quote the backslash:

 test-makefile:
        echo '\\newcommand{\\seance}{seance1}' > seances/seance.tex

Note that the POSIX standard marks the C backslash escapes for echo an XSI extension but the author of the POSIX compliance test suite claims that it is required to be XSI compliant in order to be POSIX compliant except when you like to certify only a small system for embedded use.

Since it does not seem that the original question has been asked for a small embedded system, that system would need to implement XSI extensions in order to be compliant.

Note that bash on POSIX certified platforms like Solaris and Mac OS is compiled in a way that it comes with a compliant echo by default. So the problem that bash is nor POSIX XSI compliant by default is Linux specific.

schily
  • 19,173
  • Actually, that would be XSI conformant. POSIX conformance makes the behaviour when there are backslashes present anywhere implementation-defined. Stéphane Chazelas wrote a lengthy explanation of the behaviours here, hyperlinked to in another answer, referencing a further explanation by Sven Mascheck that goes into the details of XSI conformance. And on the topic of POSIX conformance, a simple fix following the POSIX standard would use printf instead, as it recommends new scripts do. – JdeBP Jun 06 '18 at 23:43
  • Stéphane Chazelas explanation is mostly correct. It just misses the fact that XSI extensions are required for most platforms. – schily Jun 07 '18 at 07:21