12

I'm using m4 to create some basic macros and I realize that when using esyscmd there's a trailing new line added to a string when the command is run.

Example:

define(MY_HOSTNAME, esyscmd(`hostname'))
MY_HOSTNAME
Some other text...

Renders:

> my.host.name
>
> Some other text...

(complete with a trailing new line)

By adding dnl at the end of the define (or esyscmd) nothing appears to happen and there's still a trailing newline.

What's the best way to drop the trailing newline when calling esyscmd in m4?

Dan
  • 3,389
  • 5
  • 34
  • 44

4 Answers4

5

devnull's example is good but, M4 has a builtin tr as well. Here's what I'm doing:

define(CMD_OUTPUT, esyscmd(`sass --style=compressed foo.sass'))
define(NL,`
')
translit(CMD_OUTPUT, NL)

Someone a little better with M4 could tighten that into a single macro.

jdeseno
  • 7,753
  • 1
  • 36
  • 34
  • I can't nest backticks, but here's a tighter version that includes the translit call in the body of CMD_OUTPUT: `define([chomp], [translit([$1],NL,[])])` and `define([CMD_OUTPUT], [chomp(esyscmd([$1]))])` **NOTE** if you directly quote the `esyscmd` call like so `chomp([esyscmd(...)])` the chomp won't work, at least not under m4 v1.4.18 – Alexej Magura Dec 21 '18 at 03:48
3

*nix systems have tr by default. Make use of that:

define(MY_HOSTNAME, esyscmd(sh -c "hostname | tr -d '\n'"))

and you'd get rid of the trailing newline!

devnull
  • 118,548
  • 33
  • 236
  • 227
2

An alternative would be

echo -n `hostname`

No pipe, but backticks, whatevers suits your fancy.

Wrikken
  • 69,272
  • 8
  • 97
  • 136
  • The newer syntax (e.g. `$(...)`) would be better, if only because the user wouldn't need to configure `m4` to use something other than the backtick as the open-quote symbol. – Alexej Magura Dec 21 '18 at 03:56
1

You can use the translit macro. If no third argument is passed, the list of characters passed in the second argument are deleted from the first argument. So in your case, your first argument to translit would be esyscmd(`hostname'), the second argument would be the newline character, and you would not pass a third argument. Note: the literal newline character below causes the macro definition to be on two lines:

define(`MY_HOSTNAME', translit(esyscmd(`hostname'), `
'))dnl

foo MY_HOSTNAME bar  # -> foo Dans-Macbook-Pro.local bar
Shammel Lee
  • 4,092
  • 1
  • 17
  • 20