为了获得您在问题中记下的相同输出,所需要做的就是:
PS1='${PS2c##*[$((PS2c=0))-9]}- > '
PS2='$((PS2c=PS2c+1)) > '
您无需扭曲。这两行将在任何伪装成接近POSIX兼容性的外壳程序中完成。
- > cat <<HD
1 > line 1
2 > line $((PS2c-1))
3 > HD
line 1
line 2
- > echo $PS2c
0
但是我喜欢这个。我想展示使这项工作更好一些的基本原理。所以我做了一点编辑。我暂时/tmp
保留了它,但我想我也要自己保留它。它在这里:
cat /tmp/prompt
提示脚本:
ps1() { IFS=/
set -- ${PWD%"${last=${PWD##/*/}}"}
printf "${1+%c/}" "$@"
printf "$last > "
}
PS1='$(ps1)${PS2c##*[$((PS2c=0))-9]}'
PS2='$((PS2c=PS2c+1)) > '
注意:我最近了解了yash,所以昨天就做了。不管出于什么原因,它都不会打印出带有%c
字符串的每个参数的第一个字节-尽管文档专门针对该格式的宽字符扩展名,因此它可能是相关的-但对于%.1s
这就是全部。那里主要有两件事。这是它的样子:
/u/s/m/man3 > cat <<HERE
1 > line 1
2 > line 2
3 > line $((PS2c-1))
4 > HERE
line 1
line 2
line 3
/u/s/m/man3 >
解析 $PWD
每次 $PS1
评估时,它都会分析并打印$PWD
以添加到提示中。但是我不喜欢整个$PWD
屏幕拥挤,因此我只希望当前路径中每个面包屑的第一个字母都可以到达当前目录,我希望完整地看到它。像这样:
/h/mikeserv > cd /etc
/etc > cd /usr/share/man/man3
/u/s/m/man3 > cd /
/ > cd ~
/h/mikeserv >
这里有一些步骤:
IFS=/
我们将不得不拆分当前 $PWD
,而最可靠的方法是使用$IFS
split on /
。此后完全无需理会-从这里开始的所有拆分将由$@
下一个命令中的shell的位置参数数组定义,例如:
set -- ${PWD%"${last=${PWD##/*/}}"}
因此,这一个是有点棘手,但最主要的是,我们正在分裂$PWD
的/
象征。我还使用参数扩展将$last
最左/
斜杠和最右斜杠之间出现的任何值分配给所有内容。这样,我知道,如果我只是/
一个人,只有一个,/
那么它$last
仍将等于整体,$PWD
并且$1
是空的。这很重要。我也剥$last
$PWD
在将其分配给之前,从的末尾$@
。
printf "${1+%c/}" "$@"
因此,在这里-只要${1+is set}
我们printf
是%c
壳的每个参数的第一个讨厌对象-只需将其设置为当前目录中的每个目录$PWD
-减去顶层目录,即可拆分到/
。因此,我们实际上只是在打印$PWD
除顶部目录之外的每个目录的第一个字符。重要的是要意识到这仅$1
在完全设置时才会发生,而根本不会发生/
或从中删除时不会发生/
诸如in中/etc
。
printf "$last > "
$last
是我刚分配给顶层目录的变量。现在这是我们的顶级目录。它打印最后一条语句是否执行。它需要一个整洁的一点>
。
但是增加什么呢?
然后是$PS2
有条件的问题。我之前已经展示了如何做到这一点,您仍然可以在下面找到-从根本上讲,这是范围问题。但是还有更多的东西,除非您想开始做一堆printf \b
ackspace,然后尝试平衡它们的字符数……呃。所以我这样做:
PS1='$(ps1)${PS2c##*[$((PS2c=0))-9]}'
再次,${parameter##expansion}
节省了一天。不过,这有点奇怪-我们实际上在设置变量的同时设置了变量本身。我们使用它的新值-设置中间条-作为我们从中剥离的球体。你看?我们##*
将所有从增量变量的开头剥离到最后一个字符,该字符可以是[$((PS2c=0))-9]
。我们以这种方式保证不会输出该值,但是我们仍将其分配给它。非常酷-我以前从未做过。但是POSIX还向我们保证,这是最便携的方法。
这要归功于POSIX规范${parameter} $((expansion))
,这些定义将这些定义保留在当前的shell中,而不需要我们在单独的子shell中设置它们,而无论我们在何处进行评估。这就是为什么它在dash
和sh
一样好,因为它在bash
和zsh
。我们不使用任何依赖于外壳/终端的转义符,而是让变量进行自我测试。这就是使可移植代码快速的原因。
其余的工作非常简单-每次$PS2
评估时只要增加我们的计数器,直到$PS1
再次将其重置即可。像这样:
PS2='$((PS2c=PS2c+1)) > '
现在,我可以:
DASH DEMO
ENV=/tmp/prompt dash -i
/h/mikeserv > cd /etc
/etc > cd /usr/share/man/man3
/u/s/m/man3 > cat <<HERE
1 > line 1
2 > line 2
3 > line $((PS2c-1))
4 > HERE
line 1
line 2
line 3
/u/s/m/man3 > printf '\t%s\n' "$PS1" "$PS2" "$PS2c"
$(ps1)${PS2c##*[$((PS2c=0))-9]}
$((PS2c=PS2c+1)) >
0
/u/s/m/man3 > cd ~
/h/mikeserv >
SH演示
它在bash
或中的作用相同sh
:
ENV=/tmp/prompt sh -i
/h/mikeserv > cat <<HEREDOC
1 > $( echo $PS2c )
2 > $( echo $PS1 )
3 > $( echo $PS2 )
4 > HEREDOC
4
$(ps1)${PS2c##*[$((PS2c=0))-9]}
$((PS2c=PS2c+1)) >
/h/mikeserv > echo $PS2c ; cd /
0
/ > cd /usr/share
/u/share > cd ~
/h/mikeserv > exit
就像我在上面说的那样,主要的问题是您需要考虑在哪里进行计算。您不会在父shell中获得状态-因此您不会在那里进行计算。您可以在子Shell中获得状态-这样便可以在其中进行计算。但是您可以在父外壳中进行定义。
ENV=/dev/fd/3 sh -i 3<<\PROMPT
ps1() { printf '$((PS2c=0)) > ' ; }
ps2() { printf '$((PS2c=PS2c+1)) > ' ; }
PS1=$(ps1)
PS2=$(ps2)
PROMPT
0 > cat <<MULTI_LINE
1 > $(echo this will be line 1)
2 > $(echo and this line 2)
3 > $(echo here is line 3)
4 > MULTI_LINE
this will be line 1
and this line 2
here is line 3
0 >
man 1 mktemp
。