-1

NOTE: This question has arisen due to asynchronous processing of 'Process Substitution'. The script responses were deceptive, causing many lost hours. A previously related post is here: cat in process substitution hangs: what is it waiting for?

Bash 4.4.19(1)-release

Using this code because I cannot use pipes.

func() { 
    in=$(cat)
    echo "'this is it: $in'"    
}

echo "a string" > >(func)

This Process Substitution unfortunately is printing the prompt along with my string.

user@srv:~$ ./test.sh
user@srv:~$ 'this is it: a string'

This is undesirable for my usage! to say the least!!!

What is desirable is normal behavior like so:

user@srv:~$ ./test.sh
'this is it: a string'

Can I force Process Substitution not to print a shell prompt?

NOTE: I cannot use pipes... it creates other problems for me. These are the problems it creates: Can I process command output just before sending it to a file (one liner)?

conanDrum
  • 457
  • Your code does not capture your prompt, it captures input. Your prompt is already stored in an environment variable named PS1 though. – jesse_b Jun 12 '19 at 21:51
  • when I run echo "'${PS1}'" in the shell, I get '[\e]0;\u@\h: \w\a]${debian_chroot:+($debian_chroot)}\u@\h:\w$ ' – conanDrum Jun 12 '19 at 21:56
  • when I run echo "'${PS1}'" in the script, i get '' – conanDrum Jun 12 '19 at 21:57
  • I noticed that. however I would still like to accomplish this undertaking. – conanDrum Jun 12 '19 at 22:55
  • 1
    Could you say a bit more how the actual value of the prompt ends up in your variable? The prompt is written to the shell's standard error output stream. You would have to actually hop through some hoops to capture it... – Kusalananda Jun 12 '19 at 23:04
  • @Theophrastus I need to use PS1 in a function. The function is in a separate file. This file can be included in any script. I do not control who runs my function and I cannot ask them to include a -i in their script. – conanDrum Jun 12 '19 at 23:08
  • @Kusalananda I do not think hoops are a welcome choice. I think I will have to use some perl to remove what's there. Unless you have some other ideas. – conanDrum Jun 12 '19 at 23:10
  • @all can you check my Alternative Solution? just updated the question – conanDrum Jun 12 '19 at 23:17
  • @conanDrum Sorry, that was a silly choice of words on my part. What I meant was that to have captured the prompts value in the variable, something other than just a simple command substitution with cat must have been used. How was the variable's value actually assigned? It's actually quite difficult to accidentally capture the shell's prompt. – Kusalananda Jun 12 '19 at 23:19
  • @Kusalananda thanks for your time.. nothing silly about it. The answer is in the last section of my question 'Alternative Solution?' – conanDrum Jun 12 '19 at 23:22
  • @Kusalananda actually it seems that it is not in the string. seems like it is output with the string when I do echo... but how can I avoid this? – conanDrum Jun 12 '19 at 23:28
  • The prompts value is not in the value of $in, the output from your code gets intermingled with the shell displaying the prompt. It's an artefact of asynchronous output of the shell and the process substitution. – Kusalananda Jun 12 '19 at 23:28
  • @Kusalananda exactly... how to I get rid of this thing ??? doing my head in. – conanDrum Jun 12 '19 at 23:30
  • Just pipe your data to the function instead, echo hello | func. That's even portable. – Kusalananda Jun 12 '19 at 23:30
  • @all I cannot use pipes... it creates other problems for me. – conanDrum Jun 12 '19 at 23:31
  • Update the question with a description of those problems and any other restrictions you may be working under. I'm off to bed (past midnight here). – Kusalananda Jun 12 '19 at 23:32
  • @Kusalananda thanks mate.. done. – conanDrum Jun 12 '19 at 23:33

1 Answers1

1

That happens because your script returns before the subprocess from the >(...) process substitution, which runs asynchronously (ie in the background) and will only come to print its stuff after the shell you called your script from already printed its prompt.

The solution is to wait for it; unfortunately, processes run in subshells, etc. are not managed as part of jobs and do not appear in bash's job table, so you'll have to made do with pgrep -P (find-by-parent):

func() {
    in=$(cat)
    sleep .2
    echo "'this is it: $in'"
}

echo "a string" > >(func)
wait $(pgrep -P $$)

(I've added the sleep .2 just to prevent the symptom from spuriously disappearing -- the extra time the pgrep and wait take to run may be enough for the asynchronous process to terminate, too).

The assumption that processes running inside > >(...) are children of the main script only holds true when they're used with builtins, functions and group commands, see here for more details.

  • Thanks, please give me a moment to check this... Also, Kusalananda mentioned this: "...The prompt is written to the shell's standard error output stream.... – Kusalananda♦ 1 hour ago" Is it an idea maybe to disable the STDERR so that the prompt does not display before the ECHO and then enable it again? – conanDrum Jun 13 '19 at 00:30
  • Don't hurry ;-) It's not a good idea to disable the stderr because you may miss error messages written to it. –  Jun 13 '19 at 00:35
  • and of course it is related to my previous question 3 hours ago, but people are too quick to provide unhelpful answers. Thanks for making this clear to me mosvy. here: https://unix.stackexchange.com/questions/524534/cat-in-process-substitution-hangs-what-is-it-waiting-for?noredirect=1#comment970093_524534 – conanDrum Jun 13 '19 at 00:39
  • Thank you mosvy for pointing in the right direction. – conanDrum Jun 13 '19 at 00:55
  • is it really necessary to sleep .2? it seems enough to just wait $(pgrep -P $$) – conanDrum Jun 13 '19 at 00:57
  • No it's absolutely not necessary! As already written, it's only for demonstration purposes, to prevent the >(...) subprocess from exiting before the script, which will hide the symptom rather than curing the condition. –  Jun 13 '19 at 01:06
  • Gotcha. To make sure that wait $(pgrep -P $$) really does wait.... Maybe you should increase that to an actual 3s and put a comment next to that line for posterity. – conanDrum Jun 13 '19 at 01:11