9

I've a bash script invoking a python script I want to feed the content of file via stdin. Calling the bash script like:

./script.sh < file

And the contents of script.sh:

#! /usr/bin/env bash
pushd /some/python/virtual/environment/working/dir
source venv/bin/activate
python main.py ??????
deactivate
popd

I've no idea what to fill in for ?????? to pass the contents of file given to the bash script as stdin to the python script main.py.

Note that file can be a substantial text file and using bash's read is not desirable.

Using stdin when invoking the bash script is a requirement. I'm flexible to pass whatever to main.py.

Any ideas out there how to tackle this conundrum?

addition

The answer by @cas made it clear to me that I also need to explain in which context I try to use script.sh.

I want to use script.sh as a forwarding script in ~/.forward, with the contents:

|/path/to/script.sh

Which postfix does call as /path/to/script.sh; the log is clear about that. A simple test using a dressed down version of the python script, like:

|/path/to/simple/main.py

Demonstrates that postfix does call main.py with the content of the mail on the stdin. But the combination doesn't seem to work.

  • are you using postfix's own local LDA or something else, like procmail or deliver? is there anything in your ~/.bashrc which might disturb the environment as seen by main.py when run from within script.sh? maybe log the environment by running something like { typeset -p ; echo } >> "/tmp/forward.log" inside script.sh. – cas Sep 11 at 9:50
14

Assuming that your main.py script is correctly written to read from stdin and that nothing in venv/bin/activate reads from stdin(*), ?????? should be "nothing at all".

There are no previous commands in the bash script that will consume stdin before python, so python will just start consuming it.

#/bin/bash
pushd /some/python/virtual/environment/working/dir
source venv/bin/activate
python main.py
deactivate

Or make main.py executable and run it directly as ./main.py...works the same, either way.

(*) if there was, you probably wouldn't be able to do this at all, without something ugly like capturing all of stdin to a variable and then piping or <<< redirecting the variable into first venv/bin/activate and then main.py.


For a very obvious example of what is happening here and why this works, consider the following sh script kitten.sh:

#!/bin/sh
cat

It just runs cat, which begins reading from stdin and printing its input to stdout.

  • 5
    awww...the kitty's so cute, it has its own shebang line. – cas Sep 11 at 4:47
  • HI @cas Thanks for the extensive answer. And, yes it works as it should. I've extended my question to make clear in which context I'm trying to use it and where it doesn't work. May be then this SE is the wrong forum to ask the question. – nanitous Sep 11 at 9:30
  • The edit took me more than 6 min ;-) – nanitous Sep 11 at 9:40
  • If other commands earlier in the script need to consume stdin (future edits to the script, etcetera), some operating systems have pseudo-filenames that can be passed around as placeholders. Under many flavors of Linux, for example, /dev/stdin is a device file (or a symlink to such) that will Do The Right Thing when read from. The tradeoff, of course, is that portability is limited to the operating systems whose special names you know, e.g., assigning a local variable to the appropriate fake filename and then using the variable as argument to python main.py. – Ti Strga Sep 11 at 18:16
  • the entire purpose of the OP's script is to set up the environment for python and then pass stdin to main.py, so anything that did that would be breaking it. – cas Sep 12 at 1:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.