Why can lstlisting not be saved in a command?

The listings package provides some experimental features that allows you to capture it in a macro/command. However, as stated in the package documentation, this is not advised (section 5.1 Listings inside arguments, p 46):

There are some things to consider if you want to use \lstinline or the lstlisting environment inside arguments. Since TeX reads the argument before the lst-macro is executed, this package can't do anything to preserve the input: spaces shrink to one space, the tabulator and the end of line are converted to spaces, TeX's comment character is not printable, and so on. Hence, you must work a bit more. You have to put a backslash in front of each of the following four characters: \{}%. Moreover you must protect spaces in the same manner if: (i) there are two or more spaces following each other or (ii) the space is the first character in the line. That's not enough: Each line must be terminated with a "line feed" ^^J. And you can’t escape to LaTeX inside such listings! ... You might wonder that this feature is still experimental. The reason: You shouldn't use listings inside arguments; it’s not always safe!

As such, the following works:

\documentclass{scrbook}
\usepackage{listings}
\newcommand{\demo}{%
\begin{lstlisting}^^J
foobar^^J
\end{lstlisting}
}

\begin{document}
\demo

Some text

\demo
\end{document}

lstlisting via a macro


This does not answer your question, but instead provides a different work-around, if you're interested. Not sure how effective this is in general, but you can store an lstlisting in a box (using the lrbox environment). That is, I'm not sure whether there are some limitation that may stem from options passed to a lstlisting environment. It works for this minimal case.:

\documentclass{scrbook}
\usepackage{listings}% http://ctan.org/pkg/listings
\begin{document}
\newsavebox{\mylisting}
\begin{lrbox}{\mylisting}
  \begin{lstlisting}
    foobar
  \end{lstlisting}%
\end{lrbox}

\usebox{\mylisting}% Print box mylisting

Some text.

\usebox{\mylisting}% Print box mylisting
\end{document}

In your code the whole lstlisting code is read as a macro argument before the code is executed. When (La)TeX reads some code it does some processing like it strips comments, combines multiple spaces to one, converts line breaks to spaces and two line breaks in a row to \par etc.

However, the lstlisting environment and all other verbatim environments or macros want to have all of these characters (space, line break, comment characters) in their unchanged, verbatim form. For this the change the internal configuration of them by alter the so called category codes (catcodes), so that e.g. % is now a normal character and doesn't start a comment any longer, the \ doesn't start a macro any longer etc.

Now, when the code is already read as part of a macro argument all catcodes have already be assigned to the characters and some have already be transformed as mentioned above, so that the changes made by the verbatim environment afterwards when it is executed do not have any effects any longer.

In general there is the rule that verbatim material can't be used inside a macro argument or pseudo-environment (an environment which reads its whole content, see e.g. the environ package, but also tabularx does it). Luckily boxes are read and processed like normal text, so you can use e.g. the lrbox environment to store the lstlisting in a savebox and use it later using \usebox. However, you can't use the \sbox or \savebox macro because they read the content also as macro argument. I wrote the realboxes package just to provide alternatives which read the content as box, so you could use \Sbox and \Savebox instead after loading that package.