问题
Possible Duplicate:
Echo expanded PS1
Is there any way to 'evaluate' PS1
, PS2
, etc from within a bash script?
Although, I can use alternate means to get all elements of my current PS1
, I would really like to be able to reuse its definition instead of using these alternate means.
For example,
=====================================
PS1 element --> Alternate means
=====================================
\u --> $USER
\h --> $HOSTNAME
\w --> $PWD
...
=====================================
I could very well use the 'alternate means' column in my script, but I don't want to. In my PS1
, I, for example, use bold blue color via terminal escape sequences which I'd like to be able to simply reuse by evaluating PS1
.
回答1:
One great advantage of open source software is that the source is, well, open :-)
If you download the code for bash
(I'm looking at version 4.2), there's a y.tab.c
file which contains the decode_prompt_string()
function:
char *decode_prompt_string (string) char *string; { ... }
You can try to extract that (along with any needed support routines and build an executable which did the job for you. Although, from a cursory try, those support routines seem to be a lot, so this may be a hard task.
Other than that, you can probably "trick" bash
into expanding it for you with something like:
expPS1=$(echo xyzzyplughtwisty | bash -i 2>&1
| grep xyzzyplughtwisty
| head -1
| sed 's/xyzzyplughtwisty//g')
Now I've put that across multiple lines for readability but it was done on one line.
What this does is run an interactive instance of bash
, passing (what hopefully is) an invalid command.
Because it's interactive, it prints the prompt so I grab the first line with the command string on it and remove that command string. What's left over should be the prompt.
On my system, this is what I get:
pax> expPS1=$(echo xyzzyplughtwisty | bash -i 2>&1 | grep xyzzyplughtwisty | head -1 | sed 's/xyzzyplughtwisty//g')
pax> echo "[$expPS1]"
[pax> ]
pax>
However, this has problems with multi-line prompts and will actually give you your regular prompt rather than the current shell one.
If you want to do it properly, it may involve adding a little bit to bash
itself. Here are the steps to add an internal command evalps1
.
First, change support/mkversion.sh
so that you won't confuse it with a "real" bash
, and so that the FSF can deny all knowledge for warranty purposes :-) Simply change one line (I added the -pax
bit):
echo "#define DISTVERSION \"${float_dist}-pax\""
Second, change `builtins/Makefile.in to add a new source file. This entails a number of steps.
(a) Add $(srcdir)/evalps1.def
to the end of DEFSRC
.
(b) Add evalps1.o
to the end of OFILES
.
(c) Add the required dependencies:
evalps1.o: evalps1.def $(topdir)/bashtypes.h $(topdir)/config.h \
$(topdir)/bashintl.h $(topdir)/shell.h common.h
Third, add the builtins/evalps1.def
file itself, this is the code that gets executed when you run the evalps1
command:
This file is evalps1.def, from which is created evalps1.c.
It implements the builtin "evalps1" in Bash.
Copyright (C) 1987-2009 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
$PRODUCES evalps1.c
$BUILTIN evalps1
$FUNCTION evalps1_builtin
$SHORT_DOC evalps1
Outputs the fully interpreted PS1 prompt.
Outputs the PS1 prompt, fully evaluated, for whatever nefarious purposes
you require.
$END
#include <config.h>
#include "../bashtypes.h"
#include <stdio.h>
#include "../bashintl.h"
#include "../shell.h"
#include "common.h"
int
evalps1_builtin (list)
WORD_LIST *list;
{
char *ps1 = get_string_value ("PS1");
if (ps1 != 0)
{
ps1 = decode_prompt_string (ps1);
if (ps1 != 0)
{
printf ("%s", ps1);
}
}
return 0;
}
The bulk of that is the GPL licence (since I modified it from exit.def
) with a very simple function at the end to get and decode PS1
.
Lastly, just build the thing in the top level directory:
./configure
make
The bash
that appears can be renamed to paxsh
, though I doubt it will ever become as prevalent as its ancestor :-)
And running it, you can see it in action:
pax> mv bash paxsh
pax> ./paxsh --version
GNU bash, version 4.2-pax.0(1)-release (i686-pc-linux-gnu)
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
pax> ./paxsh
pax> echo $BASH_VERSION
4.2-pax.0(1)-release
pax> echo "[$PS1]"
[pax> ]
pax> echo "[$(evalps1)]"
[pax> ]
pax> PS1="\h: "
paxbox01: echo "[$PS1]"
[\h: ]
paxbox01: echo "[$(evalps1)]"
[paxbox01: ]
Now, granted, making code changes to bash
to add an internal command may be considered overkill by some but, if you want an accurate evaluation of PS1
, it's certainly an option.
来源:https://stackoverflow.com/questions/10060500/bash-how-to-evaluate-ps1-ps2