List comprehension with xonsh

229 Views Asked by At

I am still new to this, but is it possible to execute multiple commands in xonsh using a list-comprehension syntax?

I would expect the following to create five files file00 to file04, but it errors instead:

$ [@(['touch', 'file%02d' % i]) for i in range(5)]
............................ 
xonsh: For full traceback set: $XONSH_SHOW_TRACEBACK = True
  File "<string>", line None
SyntaxError: <xonsh-code>:1:1: ('code: @(',)
[@(['touch', 'file%02d' % i]) for i in range(5)]
 ^

I would expect this to work, because the following works fine:

$ [i for i in range(5)]
[0, 1, 2, 3, 4]

$ @(['touch', 'file%02d' % 3])
$ ls
file03
3

There are 3 best solutions below

2
On BEST ANSWER

The way closest to your original code is to use a subprocess:

[$[touch @('file%02d' % i)] for i in range(5)]

To explain the need for nesting $[ .. @(:

  • The top-level command is a list-comprehension, so we start in Python-mode;
  • We want to execute a bash command (touch) so we need to enter subprocess-mode with $[ (or $( to capture output);
  • But the argument to that command requires string interpolation with Python, hence Python-mode again with @(.
2
On

It looks like you found a way to do this -- sometimes the behavior of the particular subprocess command can influence how you put it all together.

In the case of touch, since it can take multiple arguments, the most straightforward way to wrap this up in a list comprehension (that I can think of) is to do

touch @([f'file_{i}' for i in range(5)])

0
On

I was almost there, it is necessary to wrap the command further:

$ [ $(@(['touch', 'file%02d' % i])) for i in range(5)]

The reason for this is as follows:

  • Given that the top-level command is a list-comprehension, we enter Python-mode
  • We want to execute a bash command (touch) so we need to enter subprocess-mode with $(
  • However, the argument to that command requires string interpolation with Python, so writing the command itself requires Python-mode, hence @(