Android(mksh
MirBSD Korn Shellを使用)には、特別な文字列置換構文(「値置換」と呼ばれる)があります。
${|commands}
コマンドの出力(``
sumなど)を収集する代わりに、代替結果は区切り文字内に割り当てられた変数から取得されます$()
。$REPLY
それを特別にするのは命令です欲しくないサブシェルで実行 - 同じシェルで実行され、現在のシェルセッションが所有しているすべてにアクセスできます。
mksh
Debianには、Androidと同じように動作するMirBSD Korn Shell用のパッケージがあります。
同様の構文をサポートするシェルは次のとおりです。
- コマンドは親シェルと同じシェルで実行されます。
- 置換の結果は、ファイル記述子以外のものから得られます。
- 出力または配管を読み取ることがFDとして計算されることが容易にわかります。
答え1
この関数は価値の代替または発散著者:Thorsten Glaser(aka@ミラビロス)、管理者またはMirBSDとそのシェルmksh
(pdkshから派生)、mksh
。
それ2013年5月2日、mkshコードベースに参加する予定そして、翌日、mkshメーリングリストにR46バージョンをリリースしました。
${ body; }
コマンド代替フォーム( 'と呼ばれる)の裏側に書かれています。機能的置換または興味深い潜水艦(中央mksh
)は同年2月にksh93でコピーされ、R46にリリースされました。
ksh93では、組み込みI/Oが仮想化されます。分岐やI / O$(builin-cmd)
は含まれていません。${ builtin-cmd; }
したがって、fd を含まない演算子の要件を満たすように$(print foo)
まだ${ print foo; }
拡張されます。foo
どちらの形式もprint
組み込み関数はfdに何も書きませんが、可能な出力(末尾の改行を削除)は拡張を構成します。 2つの違いは、$(...)
サブシェル環境が導入されるのに対して(他のシェルとは異なり、サブプロセスをフォークして達成されない)、サブシェル環境は${ ...; }
導入されないことです。
これで、ksh93(1983年からkshをほぼ最初から書き直しました)でこれを行うには、シェルのすべてのI / Oを具体的に書き換える必要がありました。 mkshが${ ...; }
2013年にこの機能を追加したときに、削除された一時ファイルに出力を記録し、拡張を補うためにコードが返された後、そのファイルの内容を読み取るより簡単なアプローチをとりました。
ただし、これは一時的に出力がディスクに保存されることを意味し、I / Oは結果データがksh93のようにメモリから転送される場合よりもパフォーマンスが低下することを意味します。そのため、Thorstenが専用変数()を使用して値を渡すことができ、シェル内に大きな変更を必要としない別${| ...; }
のフォームを追加した理由ではないでしょうか。$REPLY
しかし、これはこの方法で使用される関数がその値を返すために特別に書かれなければならないことを意味します$REPLY
(リストではなくスカラーしかできないスプリット+グローブを介している場合を除く)、これは構文上の砂糖になるだけです。例:
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 ))"
$(...)
と比較して1つの利点は、末尾の${ ...; }
改行文字を削除しないことです。たとえば、改行文字で終わると機能しないため、間違っていますが、$(basename -- "$file")
whileには問題はありません(関数からデフォルト名を返す関数としてオーバーライドされたと仮定します)。$file
${|basename -- "$file"}
basename
$REPLY
I / Oを含まずに値を返すことができる構造を持つ他のシェル:
扱いにくい
実際、2019年にmkshのvalsubの単純化されたバージョンを実装するという提案があります。結局進化したこの提案しかし、私が知っている限り、まだ成功していませんzsh
。
2024年編集 mksh${|...}
と ksh93 は${...;}
zsh で実装されます。6.0 または 5.9 以降の次のリリースで利用できると予想されます。${|var|...}
以外の変数に値を返すことができるバリアントもあります$REPLY
。
ただし、zshには、サブシェルやI / Oを含まずに任意のコードの結果に拡張できるいくつかの選択肢があります。
数学関数
算数には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
と同じ:
func() REPLY=foo$1
echo "${|func bar}" "${|func baz}"
動的に名前が付けられたディレクトリ
zsh
I / Oなしでシェルコードを使用して計算できる別の拡張機能があります。チルダ拡張というカスタムフレームワークを使用しています。動的に名前が付けられたディレクトリ(望むより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 ))'])
20文字より長いtxtファイル名を選択したい場合は、拡張結果の変更にも使用できます。
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
Byron RakitzisのResearch Unix V10 / Plan9シェルrc
のパブリックドメインレプリカの派生物です。
rc
この関数は終了ステータスのリスト(信号名または正の整数のいずれか)を返し、リスト変数で$status
呼び出し元が使用できるようにすることができます。
es
リストを返すためにこれを拡張してから利用可能にするのではなく、構文を使用して終了ステータス$status
(または関数の戻り値)を取得します<={...}
。
だからあなたはこれを行うことができます:
fn foo { return foo$1 }
echo <={foo bar}
例えば。
ただし、空のリストまたはすべての要素が空またはゼロのリストで構成される戻り値のみが次のように解釈されることに注意してください。成功。たとえば、ここでは常に次のように解釈されない値を返すため、出力されfoo anything && echo bar
ません。bar
foo
成功。
クッシュ 93
$(...)
すでに説明したこの機能に加えて、${ ...; }
I / Oを使用せずに拡張が動的コンテンツを持つことを可能にする機能があります。
トピック
変数が設定または拡張されるたびに呼び出される関数を定義できます。連想配列変数の場合、これらの関数は下付き文字にアクセスできるため、これを使用して関数に任意の引数を渡すことができます。
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) ))"
答え2
実際の質問に答えるには:いいえ。他のシェルにはこれはありません。
MirBSD Korn シェル変更ログによると、価値の代替Thomas Goirandが2014年バージョン46に追加しました。
私が知っている限り、当時またはそれ以来このアイデアを複製した他のシェルはありません。それらのいくつかは選択肢を大切にしている~からしかし、実際には価値代替品ではありません。
答え3
${ cmds;}
ksh93 のコマンド置換形式は同じシェルで実行されますが、通常のコマンド置換cmds
と同様に標準出力をキャプチャします。例:
a=1; echo ${ a=2; echo wtf;}; echo $a
wtf
2
コマンドの標準出力をキャプチャするという事実は次のとおりです。正確に出力を一時ファイルに保存してから再度読み取る必要がなく、名前付きパイプを設定したり、いくつかの毛深い関数をオーバーライドして、出力を単に変数ではなく一部の変数に追加する必要がないので、これは何の役に立ちますか?ちょうど書いてください。
これは「値置換」mksh機能とは大きく異なり、その理由が見つかりません。なぜREPLY
最初に変数を割り当ててからそれを使用できないのですか$REPLY
?