Чтобы получить тот же результат, который вы отметили в своем вопросе, все, что нужно, это:
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)) > '
Примечание: недавно узнав о яше , я построил его вчера. По какой-то причине он не печатает первый байт каждого аргумента со %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
разделением на /
. После этого вообще не нужно беспокоиться об этом - все расщепление будет определяться $@
массивом позиционных параметров оболочки в следующей команде, например:
set -- ${PWD%"${last=${PWD##/*/}}"}
Так что это немного сложно, но главное, что мы разбиваемся $PWD
на /
символы. Я также использую расширение параметра, чтобы назначить $last
все после любого значения, встречающегося между самой левой и самой правой /
косой чертой. Таким образом, я знаю, что если я только на /
и только один, /
то $last
все равно будет равен целому $PWD
и $1
будет пустым. Это имеет значение Я также раздеваюсь $last
от конца хвоста, $PWD
прежде чем назначить его $@
.
printf "${1+%c/}" "$@"
Таким образом, здесь - пока ${1+is set}
мы printf
первый %c
признак каждого аргумента нашей оболочки - который мы только что установили для каждого каталога в нашем текущем $PWD
- за исключением верхнего каталога - разделить на /
. Таким образом, мы по сути просто печатаем первый символ каждого каталога, $PWD
кроме верхнего. Однако важно понимать, что это происходит только в том случае, если вообще $1
настроено, что не произойдет в корне /
или в том случае, если оно удалено от, /
например, в /etc
.
printf "$last > "
$last
переменная, которую я только что присвоил нашему верхнему каталогу. Так что теперь это наш главный каталог. Он печатает, действительно ли последний оператор сделал. И это требует аккуратного немного >
для хорошей меры.
НО ЧТО О ВКЛАДЕ?
И затем есть вопрос $PS2
условного. Ранее я показал, как это можно сделать, что вы все еще можете найти ниже - это принципиально вопрос объема. Но есть printf \b
кое- что еще, если только вы не хотите начать делать кучу пробелов, а затем пытаться сбалансировать их количество символов ... тьфу. Итак, я делаю это:
PS1='$(ps1)${PS2c##*[$((PS2c=0))-9]}'
Опять ${parameter##expansion}
спасает день. Здесь это немного странно - мы на самом деле устанавливаем переменную, а сами отбрасываем ее. Мы используем его новое значение - set mid-strip - как шар, из которого мы раздеваемся. Вы видите? Мы ##*
удаляем все от начала нашей переменной приращения до последнего символа, который может быть чем угодно [$((PS2c=0))-9]
. Таким образом, мы гарантируем, что значение не будет выводиться, и все же мы его присвоим. Это довольно круто - я никогда не делал этого раньше. Но POSIX также гарантирует нам, что это самый переносимый способ сделать это.
И именно благодаря POSIX-спецификациям ${parameter} $((expansion))
эти определения хранятся в текущей оболочке, не требуя, чтобы мы устанавливали их в отдельном подоболочке, независимо от того, где мы их оцениваем. И именно поэтому она работает в 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 DEMO
Работает так же в 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
Как я уже говорил выше, основная проблема заключается в том, что вам нужно учитывать, где вы делаете свои вычисления. Вы не получаете состояние в родительской оболочке - поэтому вы не вычисляете там. Вы получаете состояние в подоболочке - вот где вы вычисляете. Но вы делаете определение в родительской оболочке.
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
.