3

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
Jonathan H
  • 7,591
  • 5
  • 47
  • 80

3 Answers3

2

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)])

Gil Forsyth
  • 398
  • 1
  • 7
  • Thanks; what does the `f` prefix mean in `f'file_{i}'`? – Jonathan H May 19 '18 at 00:05
  • 1
    f-strings (formatted string literals) were introduced in Python 3.6 [link](https://docs.python.org/3/whatsnew/3.6.html#whatsnew36-pep498). They're great. In the above, it would be equivalent to `'file_{}'.format(i)` – Gil Forsyth May 20 '18 at 09:49
2

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 @(.
Jonathan H
  • 7,591
  • 5
  • 47
  • 80
Anthony Scopatz
  • 3,265
  • 2
  • 15
  • 14
1

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 @(
Jonathan H
  • 7,591
  • 5
  • 47
  • 80