Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hello all,

The code below is intended to change the prompt color in bash to red.
#!/usr/bin/perl use warnings; use strict; use IPC::Open3; $|=1; # set \*ERR to 0 to send STDERR to STDOUT my $pid=open3 (\*IN, \*OUT , 0, '/bin/bash' ); my $cmd = qq( export PS1="\e[0;31m[\u@\h \W]$ \e[m " ); print IN "$cmd\n"; # Send cmd to bash. my $result = <OUT>; print $result;
Below is the output of the script.
Unrecognized escape \h passed through at 11.pl line 12. Unrecognized escape \W passed through at 11.pl line 12. Use of uninitialized value in concatenation (.) or string at 11.pl lin +e 12.
Line 12 is the bash command to change the prompt to red. Also, it is hanging after I ran the script. What am I doing wrong here??

Replies are listed 'Best First'.
Re: Send Bash Command
by sauoq (Abbot) on Mar 03, 2010 at 01:01 UTC
    What am I doing wrong here??

    Well, the big thing you are doing wrong is trying to get a subprocess to change a parent process's environment. You cannot do what you are trying to do.

    -sauoq
    "My two cents aren't worth a dime.";
      So, there is no workaround for what I am attempting to do?

        There are two workarounds for what you are trying to do, but neither work the way you are trying. The only way* for a program to affect its calling shell is by help from the calling shell.

        You can make a make your program emit the prompt string, and then export the value in your shell. Or you can make your program emit the complete export command and then use eval in the shell.

        1) emit the prompt string

        in .profile or .bashrc, or manually at a prompt:

        export PS1=$( make_a_red_prompt.pl )

        make_a_red_prompt.pl

        #!/usr/bin/perl use strict; use warnings; my $cmd = q( \e[0;31m[\u@\h \W]$ \e[m ); print $cmd , "\n";

        2: return the full shell command and use eval.

        manually at a prompt, or within a dotfile:

        eval $( export_a_red_prompt.pl )
        export_a_red_prompt.pl
        #!/usr/bin/perl use strict; use warnings; my $cmd = q( export PS1="\e[0;31m[\u@\h \W]$ \e[m " ); print $cmd , "\n";

        Here I'm using $( command ) in the shell to return the STDOUT of a command into the current prompt. Equivalent to using backticks: `command`.

        Why use a perl subprocess to essentially just echo a string? The advantage would come in from using something like Term::ANSIColor

        #!/usr/bin/perl use warnings; use strict; use Term::ANSIColor; my $prompt = colored ("Prompt", 'bold red on_white'); print "export PS1=$prompt\n";

        *ok, technically, yes it is possible for a subprocess to affect the caller. But since it involves finding the parent process and directly inserting into its memory space, I really don't think you want to do that.

        It does make for a fun answer to that interview question, though.

        ps. zsh.org is awesome.

Re: Send Bash Command
by Anonymous Monk on Mar 03, 2010 at 01:00 UTC
    You need to learn how double quotes work
    print "\t hello \n";
    \t expands to tab, \n expands to newline, \\ expands to \
Re: Send Bash Command
by Khen1950fx (Canon) on Mar 03, 2010 at 06:57 UTC
    For some reason or other, I've never thought about changing my prompt's color, but I have changed my CPAN prompt(see: Trick or Treat). Here's the easiest way that I know to change the bash prompt color using perl:
    #!/usr/bin/perl use strict; use warnings; use ExtUtils::MakeMaker qw(prompt); prompt("export PS1=\e[0;31m\][\\u@\\H\\W\]\$\\e]m");
    When you run it, it'll change the color to red, then it'll appear to hang. Actually, as with any command, bash is waiting for <enter>. To get back to your former color, just exit the terminal and start another one.
      Out of curiosity, I tried your script in Linux OS and it seems to work. But if you do a 'ls', the red prompt turns back to black. Anyway, I think it is a good attempt.
        That's interesting. If you do a 'man ls', the man page turns to black. But when you 'q', it goes back to red:). I think that "prompt" is basically good for the first command. Then you need to switch to something like 'system' as in this work-around:
        #!/usr/bin/perl use strict; use warnings; use ExtUtils::MakeMaker qw(prompt); prompt("export PS1=\e[0;31m\][\\u@\\H\\W\]\$\\e]m"); system("ls");
        However, I like the idea of using 'ls' to return to the former color. It's quicker than restarting the terminal:).
Re: Send Bash Command
by Anonymous Monk on Mar 03, 2010 at 01:04 UTC
    That is why I put it in qq(). I thought this should take care of the double inside the qq();
      Um, no, qq is double quotes, they both interpolate. Read perlintro.
        I changed the qq() to q() and I do not get the warnings anymore. But still the script is hanging.