我有一个shell脚本,在几个目录(fgit)中运行相同的命令.对于每个目录,我希望它显示当前提示+将在那里运行的命令.如何获得与解码(扩展)对应的字符串PS1
?例如,我的默认PS1是
${debian_chroot:+($debian_chroot)}\[\e[1;32m\]\u\[\e[0m\]@\[\e[1;32m\]\h\[\e[0m\]:\[\e[1;34m\]\w\[\e[0m\]$(__git_ps1 ' (%s)')$
Run Code Online (Sandbox Code Playgroud)
我想回应最终的提示username@hostname:/path$
,最好(但不一定)用漂亮的颜色.粗略地看一下Bash手册没有透露任何明确的答案,echo -e $PS1
只评估颜色.
gni*_*urf 18
从Bash 4.4开始,您可以使用@P
扩展:
首先,我将你的提示字符串放在一个变量中myprompt
使用read -r
和引用的here-doc:
read -r myprompt <<'EOF'
${debian_chroot:+($debian_chroot)}\[\e[1;32m\]\u\[\e[0m\]@\[\e[1;32m\]\h\[\e[0m\]:\[\e[1;34m\]\w\[\e[0m\]$(__git_ps1 ' (%s)')$
EOF
Run Code Online (Sandbox Code Playgroud)
要打印提示符(如果它被解释PS1
),请使用扩展${myprompt@P}
:
$ printf '%s\n' "${myprompt@P}"
gniourf@rainbow:~$
$
Run Code Online (Sandbox Code Playgroud)
(实际上有一些\001
和\002
字符,来自\[
和\]
你在这里看不到,但如果你试图编辑这篇文章,你可以看到它们;如果你输入命令,你也会在你的终端中看到它们).
为了摆脱这些,Dennis Williamson在bash邮件列表上发送的技巧是使用read -e -p
这些字符由readline库解释:
read -e -p "${myprompt@P}"
Run Code Online (Sandbox Code Playgroud)
这将提示用户,并myprompt
正确解释.
这个帖子中,Greg Wooledge回答,你可能也只是剥离\001
和\002
从字符串.这可以这样实现:
myprompt=${myprompt@P}
printf '%s\n' "${myprompt//[$'\001'$'\002']}"
Run Code Online (Sandbox Code Playgroud)
对于这篇文章,Chet Ramey回答说你也可以完全关闭行编辑set +o emacs +o vi
.所以这也会这样做:
( set +o emacs +o vi; printf '%s\n' "${myprompt@P}" )
Run Code Online (Sandbox Code Playgroud)
pax*_*blo 11
开源软件的一大优势是源是开放的:-)
Bash本身不提供此功能,但您可以使用各种技巧来提供子集(例如替换\u
为$USER
等等).但是,这需要大量的功能重复,并确保代码与bash
将来的任何内容保持同步.
如果你想获得提示变量的所有功能(并且你不介意用一些编码来弄脏你的手(如果你介意的话,为什么你在这里?)),它很容易添加到壳本身.
如果您下载代码bash
(我正在查看版本4.2),则有一个y.tab.c
包含该decode_prompt_string()
功能的文件:
char *decode_prompt_string (string) char *string; { ... }
Run Code Online (Sandbox Code Playgroud)
这是评估PSx
提示变量的函数.为了允许将此功能提供给shell本身的用户(而不是仅由 shell使用),您可以按照以下步骤添加内部命令evalps1
.
首先,进行更改,support/mkversion.sh
以免您将其与"真实"混淆bash
,以便FSF可以为保修目的拒绝所有知识:-)只需更改一行(我添加了-pax
位):
echo "#define DISTVERSION \"${float_dist}-pax\""
Run Code Online (Sandbox Code Playgroud)
其次,更改builtins/Makefile.in
添加新的源文件.这需要许多步骤.
(a)$(srcdir)/evalps1.def
加到最后DEFSRC
.
(b)添加evalps1.o
到最后OFILES
.
(c)添加所需的依赖项:
evalps1.o: evalps1.def $(topdir)/bashtypes.h $(topdir)/config.h \
$(topdir)/bashintl.h $(topdir)/shell.h common.h
Run Code Online (Sandbox Code Playgroud)
第三,添加builtins/evalps1.def
文件本身,这是运行evalps1
命令时执行的代码:
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;
}
Run Code Online (Sandbox Code Playgroud)
其中exit.def
很大一部分是GPL许可证(因为我修改了它),最后用一个非常简单的函数来获取和解码PS1
.
最后,只需在顶级目录中构建东西:
./configure
make
Run Code Online (Sandbox Code Playgroud)
bash
出现的可执行文件可以重命名为paxsh
,但我怀疑它会变得像它的祖先一样普遍:-)
运行它,你可以看到它在行动:
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: ]
Run Code Online (Sandbox Code Playgroud)
当您将其中一个PSx
变量放入提示符时,echoing $PS1
只会为您提供变量,而evalps1
命令会对其进行求值并输出结果.
现在,授予,对代码进行更改以bash
添加内部命令可能会被一些人认为是过度的,但是,如果你想要一个完美的评估PS1
,那肯定是一个选择.
你为什么不$PS1
亲自处理逃逸换人?一系列的替换如下:
p="${PS1//\\u/$USER}"; p="${p//\\h/$HOSTNAME}"
Run Code Online (Sandbox Code Playgroud)
顺便说一下,zsh有能力解释提示转义.
print -P '%n@%m %d'
Run Code Online (Sandbox Code Playgroud)
要么
p=${(%%)PS1}
Run Code Online (Sandbox Code Playgroud)
我喜欢修复 Bash 以使其更好的想法,我很欣赏 paxdiablo关于如何修补 Bash的详细回答。有时间我去看看
但是,在不修补 Bash 源代码的情况下,我有一个既可移植又不重复功能的单行 hack,因为该解决方法仅使用 Bash 及其内置函数。
x="$(PS1=\"$PS1\" echo -n | bash --norc -i 2>&1)"; echo "'${x%exit}'"
Run Code Online (Sandbox Code Playgroud)
请注意,tty
's发生了一些奇怪的事情,stdio
因为这也有效:
x="$(PS1=\"$PS1\" echo -n | bash --norc -i 2>&1 > /dev/null)"; echo "'${x%exit}'"
Run Code Online (Sandbox Code Playgroud)
因此,虽然我不明白stdio
这里发生了什么,但我的 hack 在 Bash 4.2、NixOS GNU/Linux 上对我有用。修补 Bash 源代码绝对是一个更优雅的解决方案,现在我使用 Nix 应该很容易和安全。
归档时间: |
|
查看次数: |
10160 次 |
最近记录: |