6

It seems that using

\immediate\write18{echo "\string#!/bin/bash (version 1)"  > \jobname.command}%

outside of a \newcommand works great. However, I want to invoke within a \newcommand:

\newcommand{\CreateBashScript}{%
   \immediate\write18{echo "\string#!/bin/bash (version 2)"  > \jobname.command}%
}%

but this has an issue with the # (hash / pound symbol).

Notes:

  • To reproduce the problem you need to uncomment the line in the definition of \CreateBashScript.

Code:

\documentclass{article}
\immediate\write18{echo "\string#!/bin/bash (version 1)"  > \jobname.command}%

\newcommand{\CreateBashScript}{% % \immediate\write18{echo "\string#!/bin/bash (version 2)" > \jobname.command}% }%

\begin{document} \CreateBashScript \end{document}

Peter Grill
  • 223,288
  • 4
    It's the usual 'you need to double # symbols inside macro definitions' (see e.g. http://tex.stackexchange.com/questions/42463/) – Joseph Wright May 18 '15 at 22:20
  • 1
    @JosephWright: Yep that works great. Thanks. I though that since I was using \string the double ## issue did not occur to me. Also, even though it is the same answer as the linked question, in this case I am not trying to define a macro via a macro which is where the usual doubling of the # comes up. Or at least that was my understanding. – Peter Grill May 18 '15 at 22:25
  • 1
    see this related question somebody once asked http://tex.stackexchange.com/questions/71632/why-do-paramaters-of-renewcommand-need-to-double-up-the-within-a-foreach/71633#71633 :-) – David Carlisle May 18 '15 at 22:26
  • 1
    @PeterGrill the \string isn't executed while the command is being defined, and you need ## to put a # into the replacement text. – David Carlisle May 18 '15 at 22:27
  • @DavidCarlisle: Wow, that is a brilliant question you linked to, oh and the answer is good too :-). – Peter Grill May 18 '15 at 22:28
  • 3
    \edef\writehash{\string#} in the preamble and \writehash where you want to print a hash mark. – egreg May 18 '15 at 22:35
  • @egreg: Excellent solution. With that I don't need to do anything different within a macro. Thanks. – Peter Grill May 18 '15 at 22:49

2 Answers2

6

Since macros are expanded in a \write, I'd have

\edef\shebang{\string#!/bin/bash}

in the preamble so that you can use

\newcommand{\CreateBashScript}{%
    \immediate\write18{echo "\shebang" > \jobname.command}%
}

in the command.

As told in the comment, you could also double the # in the replacement text

\newcommand{\CreateBashScript}{%
    \immediate\write18{echo "\string##!/bin/bash"  > \jobname.command}%
}

but I believe that \shebang is clearer.

egreg
  • 1,121,712
2

I fought with this problem for two days now and came across this great answer a thousand times before I understood its relevance. Therefore I attempt to reformulate it, stripped to its essence:

If you want to write out a literal # into some file, you can do something like

\newcommand{\writeouthash}{%
  \immediate\write\myfile{\string##}%
}
Au101
  • 10,278
kregkob
  • 101