Я хотел бы реализовать функцию в Bash, которая увеличивает (и возвращает) счетчик при каждом вызове. К сожалению, это кажется нетривиальным, так как я вызываю функцию внутри подоболочки и, следовательно, она не может изменять переменные родительской оболочки.
Вот моя попытка:
PS_COUNT=0
ps_count_inc() {
let PS_COUNT=PS_COUNT+1
echo $PS_COUNT
}
ps_count_reset() {
let PS_COUNT=0
}
Это будет использоваться следующим образом (и, следовательно, мне нужно вызывать функции из подоболочки):
PS1='$(ps_count_reset)> '
PS2='$(ps_count_inc) '
Таким образом, у меня будет пронумерованная многострочная подсказка:
> echo 'this
1 is
2 a
3 test'
Милый. Но из-за вышеупомянутого ограничения не работает.
Нерабочим решением было бы записать счетчик в файл вместо переменной. Однако это может привести к конфликту между несколькими одновременно запущенными сеансами. Конечно, я мог бы добавить идентификатор процесса оболочки к имени файла. Но я надеюсь, что есть лучшее решение, которое не загромождает мою систему большим количеством файлов.
man 1 mktemp
.Ответы:
Чтобы получить тот же результат, который вы отметили в своем вопросе, все, что нужно, это:
Вам не нужно искажать. Эти две строки сделают все это в любой оболочке, которая претендует на что-либо близкое к POSIX-совместимости.
Но мне понравилось это. И я хотел продемонстрировать основы того, что делает эту работу немного лучше. Поэтому я немного отредактировал это. Я застрял это
/tmp
сейчас, но я думаю, что я собираюсь оставить это для себя тоже. Это здесь:ПОДСКАЗАТЬ СЦЕНАРИЙ:
Примечание: недавно узнав о яше , я построил его вчера. По какой-то причине он не печатает первый байт каждого аргумента со
%c
строкой - хотя документы были специфическими для расширений с широкими символами для этого формата и поэтому могут быть связаны - но это просто отлично%.1s
Вот и все. Там происходят две основные вещи. И вот как это выглядит:
анализ
$PWD
НО ЧТО О ВКЛАДЕ?
И именно благодаря POSIX-спецификациям
${parameter} $((expansion))
эти определения хранятся в текущей оболочке, не требуя, чтобы мы устанавливали их в отдельном подоболочке, независимо от того, где мы их оцениваем. И именно поэтому она работает вdash
иsh
так же , как это делает вbash
иzsh
. Мы не используем экранированные зависимости от оболочки / терминала и позволяем переменным самим себя проверять. Вот что делает переносимый код быстрым.Все остальное довольно просто - просто увеличивайте наш счетчик на каждый раз,
$PS2
пока$PS1
он не будет сброшен. Как это:Так что теперь я могу:
DASH DEMO
SH DEMO
Работает так же в
bash
илиsh
:Как я уже говорил выше, основная проблема заключается в том, что вам нужно учитывать, где вы делаете свои вычисления. Вы не получаете состояние в родительской оболочке - поэтому вы не вычисляете там. Вы получаете состояние в подоболочке - вот где вы вычисляете. Но вы делаете определение в родительской оболочке.
источник
PS2
? Это сложная часть. Я не думаю, что ваше решение может быть применено здесь. Если вы думаете иначе, пожалуйста, покажите мне, как.PS1
иPS2
являются специальными переменными в оболочке, которые печатаются как командная строка (попробуйте установитьPS1
другое значение в новом окне оболочки), поэтому они используются совершенно иначе, чем ваш код. Вот еще немного информации об их использовании: linuxconfig.org/bash-prompt-basicsecho 'this
подсказку, затем объясните, как обновить значение,PS2
прежде чем вводить заключительную одинарную кавычку.При таком подходе (функция, запущенная в подоболочке) вы не сможете обновить состояние процесса основной оболочки, не пройдя искажения. Вместо этого организуйте запуск функции в главном процессе.
Значение
PROMPT_COMMAND
переменной интерпретируется как команда, которая выполняется перед печатьюPS1
приглашения.Ибо
PS2
нет ничего похожего. Но вместо этого вы можете использовать хитрость: поскольку все, что вы хотите сделать, это арифметическая операция, вы можете использовать арифметическое расширение, которое не включает в себя подоболочку.Результат арифметического вычисления заканчивается в приглашении. Если вы хотите скрыть это, вы можете передать его как индекс массива, который не существует.
источник
Это немного интенсивно вводит / выводит, но вам нужно будет использовать временный файл для хранения значения счетчика.
Если вас беспокоит необходимость отдельного файла для каждой сессии оболочки (что кажется незначительной проблемой; вы действительно будете вводить многострочные команды в двух разных оболочках одновременно?), Вам следует использовать
mktemp
для создания нового файла для каждого использовать.источник
Вы не можете использовать переменную оболочки таким образом, и вы уже понимаете, почему. Подобная оболочка наследует переменные точно так же, как процесс наследует свое окружение: любые сделанные изменения применяются только к нему и его дочерним элементам, а не к любому процессу-предку.
Как и в других ответах, самое простое, что нужно сделать - это спрятать эти данные в файл.
И т.п.
источник
mktemp
).PS2
расширяется оболочкой. В то время у вас нет возможности обновить значение переменной в родительской оболочке.Для справки, вот мое решение, использующее временные файлы, которые уникальны для каждого процесса оболочки и удалены как можно скорее (чтобы избежать беспорядка, как упоминалось в вопросе):
источник