3

In the xonsh shell how can I receive from a pipe to a python expression? Example with a find command as pipe provider:

find $WORKON_HOME -name pyvenv.cfg -print | for p in <stdin>: $(ls -dl @(p))

The for p in <stdin>: is obviously pseudo code. What do I have to replace it with?

Note: In bash I would use a construct like this:

... | while read p; do ... done
halloleo
  • 9,216
  • 13
  • 64
  • 122

2 Answers2

3

The easiest way to pipe input into a Python expression is to use a function that is a callable alias, which happens to accept a stdin file-like object. For example,

def func(args, stdin=None):
    for line in stdin:
        ls -dl @(line.strip())

find $WORKON_HOME -name pyvenv.cfg -print | @(func)

Of course you could skip the @(func) by putting func in aliases,

aliases['myls'] = func
find $WORKON_HOME -name pyvenv.cfg -print | myls

Or if all you wanted to do was iterate over the output of find, you don't even need to pipe.

for line in !(find $WORKON_HOME -name pyvenv.cfg -print):
    ls -dl @(line.strip())
halloleo
  • 9,216
  • 13
  • 64
  • 122
Anthony Scopatz
  • 3,265
  • 2
  • 15
  • 14
  • Thx. Makes all sense. Just a big shame, that there is no way write python code to receive the pipe on the same line where the pipe is... – halloleo Nov 06 '18 at 13:08
  • 1
    If the expression is suitably small, it can fit in a lambda in the `@(lambda args, stdin: ...)`. Also always happy to have discussions of new syntax at https://github.com/xonsh/xonsh/issues :) – Anthony Scopatz Nov 07 '18 at 16:39
  • Sorry, can't figure out the lambda expression for this case. I tried ...`| @(lambda args, stdin: [ $[ls -dl @(l.strip())] for l in stdin ])])` and I get the first `ls` line printed (so the lambda expression must have been accepted), but then a "TypeError: an integer is required (got type NoneType)". – halloleo Nov 08 '18 at 06:53
  • Something like `lambda args, stdin: ''.join([$(ls -l @(line.strip())) for line in stdin])` should work, but I am getting a similar odd error. Can you please open at issue? Thanks! – Anthony Scopatz Nov 08 '18 at 21:28
  • `@()` executes python or xonsh code? How can a python function `func` use a shell syntax? Sorry I am new to xonch and trying to wrap my head around. – tejasvi88 Feb 08 '21 at 06:12
0

Drawing on the answer from Anthony Scopatz you can do this on one line with a callable alias as a lambda. The function takes the third form, def mycmd2(args, stdin=None). I discarded args with _ because I don't need it and shortened stdin to s for convenience. Here is a command to hash a file:

type image.qcow2 | @(lambda _,s: hashlib.sha256(s.read()).hexdigest())
ChinnoDog
  • 1
  • 1