这个问题很简单。我想在我的Bash脚本中评估PS1
的当前值。
谷歌上的所有材料都是关于升级它的教程,但是我想要评估看看它在我的当前终端或者至少是某个终端中是如何展示的。
有没有任何软件/函数可以帮助我实现这一点?当然,我希望将所有转义字符都计算在内,因此echo $PS1
在我的情况下并不太有用。
这个问题很简单。我想在我的Bash脚本中评估PS1
的当前值。
谷歌上的所有材料都是关于升级它的教程,但是我想要评估看看它在我的当前终端或者至少是某个终端中是如何展示的。
有没有任何软件/函数可以帮助我实现这一点?当然,我希望将所有转义字符都计算在内,因此echo $PS1
在我的情况下并不太有用。
echo "${PS1@P}"
[adamhotep@tabasco ~]$ echo "the prompt is '${PS1@P}'"
the prompt is '[adamhotep@tabasco ~]$'
[adamhotep@tabasco ~]$ TEST_STRING='\u is dining at \t using \s \V'
[adamhotep@tabasco ~]$ echo "${TEST_STRING}"
\u is dining at \t using \s \V
[adamhotep@tabasco ~]$ echo "${TEST_STRING@P}"
adamhotep is dining at 21:45:10 using bash 5.0.3
[adamhotep@tabasco ~]$
(另请参阅此答案来自重复问题Echo expanded PS1。)
${parameter@operator}
Parameter transformation. The expansion is either a transformation of the value of parameter or information about parameter itself, depending on the value of operator.
Each operator is a single letter:Q The expansion is a string that is the value of parameter quoted in a format that can be reused as input. E The expansion is a string that is the value of parameter with backslash escape sequences expanded as with the $'…' quoting mechanism. P The expansion is a string that is the result of expanding the value of parameter as if it were a prompt string (see PROMPTING below). A The expansion is a string in the form of an assignment statement or declare command that, if evaluated, will recreate parameter with its attributes and value. a The expansion is a string consisting of flag values representing parameter's attributes.
If parameter is
@
or*
, the operation is applied to each positional parameter in turn, and the expansion is the resultant list. If parameter is an array variable subscripted with@
or*
, the operation is applied to each member of the array in turn, and the expansion is the resultant list.
Z Shell(zsh
)可以使用${(%%)PS1}
或其内置的print
命令的-P
标志来实现此功能:
[adamhotep@tabasco ~]% echo "the prompt is '${(%%)PS1}'"
the prompt is '[adamhotep@tabasco ~]%'
[adamhotep@tabasco ~]% print -P "the prompt is '$PS1'"
the prompt is '[adamhotep@tabasco ~]%'
[adamhotep@tabasco ~]% TEST_STRING="%n is dining at %* using %N $ZSH_VERSION"
[adamhotep@tabasco ~]% echo "$TEST_STRING"
%n is dining at %* using %N 5.7.1
[adamhotep@tabasco ~]% echo "${(%%)TEST_STRING}"
adamhotep is dining at 11:49:01 using zsh 5.7.1
[adamhotep@tabasco ~]% print -P "$TEST_STRING"
adamhotep is dining at 11:49:07 using zsh 5.7.1
[adamhotep@tabasco ~]%
Zsh扩展和替换手册告诉我们:
参数扩展标志。如果大括号后面直接跟着开括号,那么一直到匹配的闭括号的字符串将被视为标志列表。在重复标志有意义的情况下,重复不必连续;例如,
(q%q%q)
的含义与更易读的(%%qqq)
相同。支持以下标志:
…
%
以与提示符(请参见提示符扩展)相同的方式扩展结果单词中的所有%
转义。如果给出了两次此标志,则根据PROMPT_PERCENT
、PROMPT_SUBST
和PROMPT_BANG
选项的设置,在结果单词上执行完整的提示符扩展。
-P
执行提示扩展(参见Prompt Expansion)。与-f
结合使用,提示转义序列仅在插入的参数中解析,而不在格式字符串中解析。
echo $PS1
然后使用编辑器进行编辑。之后为了测试(这是在会话期间设置的):
PS1='\[\033[1m\]\[\033[34m\]\u\[\033[90m\]@\[\033[01;35m\]\h:\[\033[01;32m\]\W\[\033[0m\]$ '
(\u 代表用户,\h 代表主机,\w 代表完整路径,\W 代表短路径)
如果我喜欢这个设置,我会通过更改 ~/.bashrc 中的 PS1 的值来使其成为永久设置。
附言:
要查看所有全局变量:
printenv
或者:
printenv <name_of_var_to_see>
还有一种可能性,使用script
实用程序(Ubuntu上的bsdutils
软件包的一部分):
$ TEST_PS1="\e[31;1m\u@\h:\n\e[0;1m\$ \e[0m"
$ RANDOM_STRING=some_random_string_here_that_is_not_part_of_PS1
$ script /dev/null <<-EOF | awk 'NR==2' RS=$RANDOM_STRING
PS1="$TEST_PS1"; HISTFILE=/dev/null
echo -n $RANDOM_STRING
echo -n $RANDOM_STRING
exit
EOF
<prints the formatted prompt properly here>
script
命令可以生成指定的文件,并在stdout上显示输出。如果省略文件名,则会生成一个名为typescript的文件。
由于在这种情况下我们不关心日志文件,因此将文件名指定为/dev/null
。相反,将script命令的stdout传递给awk进行进一步处理。
PROMPT_COMMAND
...编辑:
看起来新版本的script
会在typescript中回显管道的stdin
。为了处理这个问题,可以更改上述机制为:
$ TEST_PS1="\e[31;1m\u@\h:\n\e[0;1m\$ \e[0m"
$ RANDOM_STRING=some_random_string_here_that_is_not_part_of_PS1
$ script /dev/null <<-EOF | awk '{old=current; current=$0;} END{print old}' RS=$RANDOM_STRING
PS1="$TEST_PS1"; HISTFILE=/dev/null
alias $RANDOM_STRING=true
$RANDOM_STRING
$RANDOM_STRING
EOF
<prints the formatted prompt properly here>
说明:
尝试手动在终端上输入这些命令。将这些命令复制到 heredoc
下,并使用鼠标中键粘贴。脚本命令的标准输出会包含非常相似的内容。
例如,对于上面的示例,脚本命令的输出如下:
PS1="\e[31;1m\u@\h:\n\e[0;1m$ \e[0m"; HISTFILE=/dev/null
alias some_random_string_here_that_is_not_part_of_PS1=true
some_random_string_here_that_is_not_part_of_PS1
some_random_string_here_that_is_not_part_of_PS1
\e[0m"; HISTFILE=/dev/nullhsane-dev : ~/Desktop $ PS1="\e[31;1m\u@\h:\n\e[0;1m$
anishsane@anishsane-dev:
$ alias some_random_string_here_that_is_not_part_of_PS1=true
anishsane@anishsane-dev:
$ some_random_string_here_that_is_not_part_of_PS1
anishsane@anishsane-dev:
$ some_random_string_here_that_is_not_part_of_PS1
anishsane@anishsane-dev:
$ exit
使用“some_random_string_here_that_is_not_part_of_PS1”作为分隔符(awk的记录分隔符)来拆分stdout,并打印倒数第二条记录。
编辑2:
另一种机制(使用bash源代码和gdb):
$ gdb -batch -p $$ -ex 'call bind_variable("expanded_PS1", decode_prompt_string (get_string_value ("PS1")), 0)'
$ echo "$expanded_PS1"
<prints the formatted prompt properly here>
PS1
中的\[
或\]
字符串将被打印为\1
/\2
。您可以使用tr -d '\1\2' <<< "$expanded_PS1"
来删除它们。gdb
无法附加到进程的错误(在Ubuntu中似乎经常发生),请使用sudo
运行gdb
。colcrt
的工具部分清除转义码。它是为 man
页面而设计的,不适用于 script
输出,因此并不完美,但这是一个开始。 - tripleeeecho -n $RANDOM_STRING
是什么意思?它是必需的吗?为什么要执行两次?awk
对随机字符串做了什么?更详细地解释上述命令的工作原理将会很有帮助。 - Nathan Craikeeval
,通过打印提示来处理任何扩展(不确定为什么括号还在)。这种方法可能比@anishsane的方法更简单,但可能不够健壮。show-prompt() {
eval 'echo -en "'$PS1'"' | sed -e 's#\\\[##g' -e 's#\\\]##g'
}
# To show it in a function registered with `complete -F` on
# a single tab, and keep the user's input:
show-prompt
echo -n "${COMP_WORDS[@]}"
我曾经在GitHub问题上探索过这个问题。
complete -F
” 的确切含义是什么?我正在尝试从Octave中使用它,以便显示常规提示,然后将用户的输入存储为命令,但提示不会显示;就像这样:octave --eval "system('./showprompt'); usercommand = input('', 's')"
。 - nightcod3rcomplete -F
是用于 Bash 的一个命令补全习语;要了解更多信息,请参见 bash -c 'help complete'
。我的上面的评论很简洁,但我的意思是你可以将这两行代码注入到传递给 Bash 的 complete -F <function>
函数中。通过这种方式,您可以创建一个具有长时间运行更新(例如 bazel
构建系统的 CLI 初始化)的完成方法,但您至少可以向用户显示它正在工作而不是冻结。不幸的是,我没有关于 Octave 的特定应用程序的建议 :( - Eric Cousineau\u
、\h
和\W
却不行(我碰巧在我的PS1
变量中有这些序列;也许还有更多类似的序列)。 - HelloGoodbye请尝试以下命令
echo $PS1 |
sed -e s/'\\d'/"$(date +'%a %b %_d')"/g |
sed -e s/'\\t'/"$(date +'%T')"/g |
sed -e s/'\\@'/"$(date +'%r')"/g |
sed -e s/'\\T'/"$(date +'%r'| awk {'print $1'})"/g |
sed -e s/'\\e'//g | sed -e s/'\\h'/"$HOSTNAME"/g |
sed -e s/'\\h'/"$HOSTNAME"/g |
sed -e s/'\\H'/"$HOSTNAME"/g |
sed -e s/'\\u'/"$USER"/g |
sed -e s@'\\W'@"$(pwd)"@g |
sed -e s/'\\w'/"$(pwd | sed -e s@$HOME@'~'@g )"/g |
sed -e s/"\\\\"//g |
sed -e s/"\\["//g |
sed -e s/"\\]"/*/g |
cut -d'*' -f2 |
cut -d';' -f2 |
sed s/\ //g |
sed -e s/[a-z]$/"$([ "$USER" != "root" ] && echo \$ || echo \#)"/g
编辑 /etc/bashrc 文件
您可以使用此作为示例并检查输出
# If id command returns zero, you’ve root access.
if [ $(id -u) -eq 0 ];
then # you are root, set red colour prompt
PS1="\\[$(tput setaf 1)\\]\\u@\\h:\\w #\\[$(tput sgr0)\\]"
else # normal
PS1="[\\u@\\h:\\w] $"
fi