Search code examples
pythonshellxonsh

How to run a shell command in a for loop in xonsh?


I would like to use xonsh to execute pandoc on all the md files in a directory. I could use subprocess, but that seems like the kind of thing that would be unnecessary in xonsh. Here's what I've tried so far:

from glob import glob
import os
for fn in glob('*.md'):
    bname, _ = os.path.splitext(fn)
    pandoc $fn > ${bname}.html

With this I get a SyntaxError:

SyntaxError: :3:11: ('code: $fn',) pandoc $fn > ${bname}.html

If I change the last line to: pandoc $fn > $bname.html, I get:

pandoc: $fn: openBinaryFile: does not exist (No such file or directory)

I assume that the problem is that inside the for loop is Python mode, but the pandoc call has to be in subprocess mode. How is this supposed to be done?


Solution

  • If you want Python variables to be available to subprocesses (in the implicit xonsh sense) you can wrap them in @(). Also, there's a built-in globber syntax so you could write the process as follows:

    import os.path
    
    for fn in g`*.md`:
        _, bname = os.path.split(fn)
        pandoc @(fn) > @('{}.html'.format(bname))
    

    Note that both the fn and the '{}.html'.format() should be wrapped in @() because they are python variables in a subproc (because you've called a command line function to start the line).

    Also, you don't need to make them environment variables unless you want them available to other programs that explicitly need envvars set.

    Hope that helps!