不自然な例...与えられた
FOO="/foo/bar/baz"
これは機能します(bashで)
BAR=$(basename $FOO) # result is BAR="baz"
BAZ=${BAR:0:1} # result is BAZ="b"
これはしません
BAZ=${$(basename $FOO):0:1} # result is bad substitution
私の質問は、この[サブシェル置換]が誤って評価される原因となるルールは何ですか?そして、もしあれば、これを1ホップで行う正しい方法は何ですか?
まず、これを言うときは、次のことに注意してください。
_BAR=$(basename $FOO) # result is BAR="baz"
BAZ=${BAR:0:1} # result is BAZ="b"
_
BAZ
の構成の最初のビットはBAR
であり、最初の文字を取得するvalueではありません。したがって、bashで変数名に任意の文字を含めることが許可されている場合でも、2番目の式の結果は希望どおりではありません。
ただし、これを妨げているルールについては、bashのmanページから引用できるようにします。
_DEFINITIONS
The following definitions are used throughout the rest of this docu‐
ment.
blank A space or tab.
Word A sequence of characters considered as a single unit by the
Shell. Also known as a token.
name A Word consisting only of alphanumeric characters and under‐
scores, and beginning with an alphabetic character or an under‐
score. Also referred to as an identifier.
_
その後少し後で:
_PARAMETERS
A parameter is an entity that stores values. It can be a name, a num‐
ber, or one of the special characters listed below under Special Param‐
eters. A variable is a parameter denoted by a name. A variable has a
value and zero or more attributes. Attributes are assigned using the
declare builtin command (see declare below in Shell BUILTIN COMMANDS).
_
そして後でそれがあなたが求めている構文を定義するとき:
_ ${parameter:offset:length}
Substring Expansion. Expands to up to length characters of
parameter starting at the character specified by offset.
_
そのため、マンページに明記されているルールでは、_${foo:x:y}
_構文には最初の部分としてパラメーターが必要であり、パラメーターは名前、数字、またはいくつかの特殊パラメーター文字の1つのみにすることができます。 $(basename $FOO)
は、パラメーターに許可される可能性の1つではありません。
1つの割り当てでこれを行う方法については、他の応答で言及されているように、他のコマンドへのパイプを使用します。
${parameter#Word}
などの変更された形式のパラメータ置換では、任意のWordではなく、パラメータのみを変更できます。
この場合、次のようにbasename
の出力をddコマンドにパイプすることができます。
BAR=$(basename -- "$FOO" | dd bs=1 count=1 2>/dev/null)
(より多くのカウントが必要な場合は、count
ではなくbs
を増やしてください。そうしないと、要求されたよりも少ないバイトを取得する可能性があります。)
一般的なケースでは、このようなことを1つの割り当てで行う方法はありません。
${BAR:0:1}
は変数展開であるため、失敗します。 Bashは、値ではなく${
の後に変数名が表示されることを期待しています。
単一の式でそれを行う方法を知りません。
他の人が言ったように、$ {}の最初のパラメーターは変数名である必要があります。しかし、別のサブシェルを使用して、実行しようとしていることを概算できます。
の代わりに:
BAZ=${$(basename $FOO):0:1} # result is bad substitution
使用する:
BAZ=$(_TMP=$(basename $FOO); echo ${_TMP:0:1}) # this works
考案された例のための考案されたソリューション:
BAZ=$(expr $(basename $FOO) : '\(.\)')
のように
$ FOO=/abc/def/ghi/jkl
$ BAZ=$(expr $(basename $FOO) : '\(.\)')
$ echo $BAZ
j
$ {string:0:1}、stringは変数名でなければなりません
例えば:
FOO = "/ foo/bar/baz"
baz = "foo"
BAZ = eval echo '${'"$(basename $FOO)"':0:1}'
$ BAZをエコー
結果は「f」です