Какие оболочки поддерживают «подстановку значений», например MirBSD Korn Shell?

Переменная подсказки (t )csh — $prompt[1], поэтому прямой ответ на ваш вопрос —:

printf '%s\n' "$prompt"

В tcsh(, но не в оригинальном csh), вы можете использовать побег %tдля времени в формате 12 часов утра/вечера:

% set prompt = "%t - $prompt"
1:53pm - % _

или %Pдля 24-часового формата с секундами:

% set prompt = "$prompt (%P) "
%  (13:55:31) _

Вы можете увидеть полный список escape-последовательностей на tcsh (1)справочной странице.

[1] tcshтакже имеет $prompt2для циклов foreach/ whileи продолжения строки \и $prompt3для функции исправления орфографии.

2
24.09.2020, 08:29
3 ответа

Форма ${ cmds;}подстановки команд ksh93 работает cmdsв той же оболочке, но в остальном захватывает стандартный вывод, как обычная подстановка команд. Пример:

a=1; echo ${ a=2; echo wtf;}; echo $a
wtf
2

И тот факт, что он захватывает стандартный вывод команд, именно делает его полезным, поскольку вам не нужно сохранять вывод во временный файл, а затем читать его или настраивать именованный канал или перепишите какую-нибудь мохнатую функцию, чтобы она добавляла свой вывод к какой-либо переменной, а не просто записывала ее.

И это очень сильно отличается от функции "подстановки значений" mksh, для которой я не могу найти никакого объяснения. Почему нельзя присвоить переменную REPLYраньше, а затем просто использовать ее как $REPLY?

1
18.03.2021, 23:02

Чтобы ответить на вопрос, который на самом деле задан :Нет. В других оболочках такого нет.

Как сообщает нам журнал изменений оболочки MirBSD Korn, замены значений были добавлены Томасом Гойраном в 2014 году к выпуску 46.

Насколько мне известно, ни одна другая оболочка не копировала эту идею ни тогда, ни после. У некоторых из них есть то, что подстановки значений были получены из , но на самом деле у них нет подстановок значений.

2
18.03.2021, 23:02

Эта функция, называемая подстановкой значений или valsub Торстена Глейзера (, также известного как @mirabilos ), производная от сопровождающего или MirBSD и ее оболочки mksh(. из pdksh ), относится к mksh.

Он был включен в кодовую базу mksh 2 мая 2013 г. и выпущен в версии R46, объявленной на следующий день в списке рассылки mksh.

Это написано на обратной стороне ${ body; }формы подстановки команд (, называемой подстановкой функций или funsub в mksh), скопированной из ksh93 в феврале того же года и также выпущен в R46.

В ksh93 ввод-вывод из встроенных модулей виртуализирован. Ни $(builin-cmd), ни ${ builtin-cmd; }не содержат ответвления или ввода/вывода. Таким образом, $(print foo)или ${ print foo; }расширяются до fooи отвечают вашим требованиям к оператору, не включающему никакого fd.

В обеих формах встроенная команда printничего не записывает в какой-либо fd, но ее -будет -вывод (, обрезанный конечными символами новой строки ), составляющий расширение. Разница между ними заключается в том, что $(...)вводит среду подоболочки (, которая, в отличие от других оболочек, не реализуется путем разветвления дочернего процесса ), а ${...; }— нет.

Теперь, чтобы сделать это, ksh93 (переписать сам ksh (1983 года )почти с нуля ), все операции ввода-вывода в оболочке должны были быть специально переписаны. Когда mksh добавил эту функцию ${...; }в 2013 году, он использовал более простой подход, который просто записывает вывод в удаленный временный файл и считывает содержимое этого файла после того, как код в нем возвращается, чтобы составить расширение.

Однако это означает, что выходные данные в конечном итоге сохраняются на диске, даже если они временно, а ввод-вывод означает более низкую производительность, чем если бы результирующие данные просто передавались в память, как в ksh93.Поэтому я предполагаю, что именно поэтому Торстен добавил эту ${|...; }отдельную форму, которая может передавать значение, используя выделенную переменную ($REPLY), и опять же не требует серьезной переработки внутренних компонентов оболочки.

Однако это означает, что функции, которые используются таким образом, должны быть написаны специально, чтобы возвращать свое значение в $REPLY(, которое может быть только скалярным, а не списком, кроме как через split+glob ), и просто становится немного синтаксический сахар. Пример:

sanitize() {
  REPLY=${1//[!0123456789-]}
  local sign=
  case $REPLY in
    (-*) REPLY=${REPLY#-}; sign=-
  esac
  REPLY=$sign${REPLY//-}
}

print "$(( ${|sanitize "$1"} + ${|sanitize "$2"} ))"

Без него пришлось бы писать:

sanitize "$1"; a=$REPLY
sanitize "$2"; b=$REPLY
print "$(( a + b ))"

Одним из преимуществ по сравнению с $(...)и ${...; }является то, что он не удаляет завершающие символы новой строки. Например, $(basename -- "$file")неверен, так как не работает, если $fileзаканчивается символами новой строки, в то время как ${|basename -- "$file"}(, предполагая, что basenameбыла переписана как функция, возвращающая базовое имя из $REPLY), не имела бы проблема.

Другие оболочки с конструкциями, которые могут возвращать значения без участия ввода-вывода:

зш

Кто-то предложил реализовать упрощенную версию mksh valsub в 2019 году , которая в конечном итоге превратилась в это предложение , но, насколько мне известно, оно еще не дошло до zsh.

Однако у zsh есть несколько альтернативных способов расширения, являющихся результатом произвольного кода, без участия подоболочки или ввода-вывода.

Математические функции

Для арифметики zshимеет понятие математических функций:

square() (( $1 * $1))
functions -M square 1

echo $(( square(5) + square(12) ))

Это ограничено числами, хотя (целым числом или числом с плавающей запятой )и может использоваться только в арифметических выражениях. Однако сами математические функции могут принимать числа, отличные от -, в качестве аргументов с functions -sM), поэтому, хотя это и очень запутанно, вы можете сделать:

func() REPLY=foo$1; functions -sM func

echo ${$((func(bar)))+$REPLY} ${$((func(baz)))+$REPLY}

как эквивалент mksh's:

func() REPLY=foo$1

echo "${|func bar}" "${|func baz}"

Каталоги с динамическими именами

zshимеет другую форму расширения, чем может быть вычислено с помощью шелл-кода без ввода-вывода.Это использует структуру настройки для расширения тильды под названием Динамические именованные каталоги(см.info zsh dynamic).

Если вы определяете:

autoload -Uz add-zsh-hook

valsub() {
  [[ $1 = n && $2 = '!'* ]] && eval "${2#?}" && reply=("$REPLY")
}
add-zsh-hook -Uz zsh_directory_name valsub

Тогда тильда расширения формы ~[!'REPLY=something']расширится до something.

Расширение тильды выполняется не во всех контекстах, но вы также можете использовать эту функцию динамических именованных каталогов как часть расширения параметра, используя прием , описанный в упомянутом выше обсуждении поддержки valsub. .

квалификаторы e и + glob

Подстановочные знаки также могут расширяться до результата произвольного кода с помощьюe(для оценки)или +подстановочных знаков.

Они обычно используются для фильтрации файлов на основе результата выполнения некоторого кода.

Нравится:

ls -ld -- *.txt(e['(( $#REPLY > 20 ))'])

Чтобы выбрать имена файлов txt, длина которых превышает 20 символов. Но также может использоваться для изменения результата расширения:

ls -ld -- *.txt(e['REPLY=$REPLY:r.html'])

(расширить до txtфайлов с заменой расширения наhtml). Или даже:

ls -ld -- *.txt(e['reply+=($REPLY:r.html)'])

Возвращает перевод txtи html.

Так что вы действительно можете:

echo /(e['REPLY=foobar'])

Чтобы расширить результат произвольного кода, здесь применяется квалификатор /, который, как мы знаем, всегда существует. Или даже список:

printf '<%s>\n' /(e['reply=(foo bar)'])

Квалификатор +— это вариант, который просто принимает имя функции, поэтому вы можете использовать echo /(+func), где func— это функция, которая генерирует расширение.

Опять же, как и для расширения ~, подстановка выполняется не в каждом контексте.

э

esявляется производным от Байрона Ракитзиса общедоступного клона оболочки Research Unix V10/Plan9 rc.

Функции

rcмогут возвращать список статусов выхода. (может быть именем сигнала или положительными целыми числами. )и предоставляется вызывающей стороне в переменной списка $status.

esрасширил его, чтобы он мог возвращать любой список чего угодно, и вместо того, чтобы делать его доступным в $status, статус выхода (или возвращаемое значение функции )получают с синтаксисом <={...}.

Так что можно сделать:

fn foo { return foo$1 }
echo <={foo bar}

например.

Однако обратите внимание, что только возвращаемое значение из пустого списка или списка, все элементы которого пусты или равны 0, интерпретируется как успешное . Так, например, здесь foo anything && echo barникогда не будет выводить bar, поскольку fooвсегда возвращает значение, которое никогда не интерпретируется как успех .

кш93

Помимо уже рассмотренных $(...), ${...; }, существуют функции, которые позволяют расширениям иметь динамическое содержимое без участия ввода-вывода:

дисциплины

Вы можете определить функцию, которая вызывается каждый раз при установке или расширении переменной. Для переменных ассоциативного массива эти функции будут иметь доступ к нижнему индексу, поэтому вы можете использовать его для передачи одного произвольного аргумента в функцию:

typeset -A valsub
function valsub.get {
 .sh.value=foo${.sh.subscript}
}
echo "${valsub[bar]}"

будет выводить foobar.

математические функции

ksh93 также имеет математические функции, хотя и с другим синтаксисом, чемzsh:

function.sh.math.square x {((.sh.value = x*x))}
echo "$(( square(5) + square(12) ))"
0
18.03.2021, 23:02

Теги

Похожие вопросы