Ble.sh: syntax: 変数展開のパターンとしての感嘆符が履歴展開開始文字として認識される

Created on 27 Jul 2019  ·  8Comments  ·  Source: akinomyoga/ble.sh

ble version: 0.4.0-devel1+362ab05
Bash version: 5.0.3(1)-release

変数展開のパターンとしての感嘆符及び以降の文字列が,履歴展開開始文字としての感嘆符とその対象文字列として認識されてしまいます。
次のようなコマンドラインにおいて,波線部は履歴展開されない筈です(実際,実行結果を見るにそうであるように思えます)が,そうなるかのような挙動を示します。具体的にはsyntax_history_expansionで指定した装飾が施され,さらに改行キーが複数行モード開始キーとして取り扱われます。

$ VAR='abc'
$ echo ${VAR%[!a]}
              ^^^
ab

(ただ,履歴展開に関する手引きに拠れば,一重引用符で囲まれた範囲・逆斜線が前置された場合・二重引用符で囲まれた範囲の終端 _以外_ では履歴展開が適用されるとのことなので,もしかしたら私の勘違いかも知れません……。
一方でパターンマッチに関する手引きに拠れば,開き角括弧の直後の感嘆符は^と同等の意味を持つようなので,どちらが優先されるのか私めには分かりかねます。
〝素〟のBash⦅$ bash --norcで起動⦆でも上掲のコマンドラインにおいて履歴展開されないので,後者の仕様が優先されるようですが……)

NYNewFeat

All 8 comments

ご報告ありがとうございます! これは ${var...} の構文解析が面倒だと思って未実装だったという問題でした。真面目に実装していなくても問題ないと高を括っていたのですが、実際にこういう事が起こるのですね…。実装しました 051222e

[!a] で履歴展開と bracket expression のどちらを優先するかというのは、実は Bash の振る舞いに合わせて既に (echo [!a] 等の場合に) bracket expression を優先する様に実装していたのでした。

ありがとうございます!確認いたしました。

ただの興味本位なんですが…

履歴展開と bracket expression のどちらを優先するかというのは、実は Bash の振る舞いに合わせて

↑ということは,GNU Bashプロジェクトは,このような状況でどちら(の展開)を優先するかを明文化していないということですか?

ありがとうございます!

このような状況でどちら(の展開)を優先するかを明文化していないということですか?

そうですね。実は明文化されていない文法の微妙な解釈は物凄くたくさんあります。
ble.sh は Bash の明文化されていない様々な振る舞いを調べ尽くして実装しています…。

実は今回の対応でも、例えば以下の様なパラメータ展開がどう解釈されるのかというのを実際に実行してみて確かめなければなりませんでした。どういう結果になるか当てられますか? どの解釈が優先されるのかマニュアルは確認していませんが、たぶん載っていませんよね…。

var=a; echo "${var%[a}]}"
var=a; echo "${var%@(a|b})}"
var=a; echo "${var%@(a|b[c}])}"
var=a; echo "${var/[a/b]/c}"
var=a; echo "${var/@(a|b/c)/d}"

他にも今回調べて分かった事は、以下の XXX 及び YYY の両方でグロブパターンが有効なのですが、XXX に含まれるパターンは (パス名展開せず) に var に対するパターンとして使われて、YYY に指定したパターンはパス名展開の対象になる様です。未だまだ試してみないと分からないことだらけです…。

echo ${var/XXX/YYY}
echo ${var#XXX} ${var%XXX} ${var,XXX} ${var^XXX}
echo ${var-YYY} ${var+YYY} ${var?YYY} ${var=YYY}

なるほど……。
しかし,示してくださった結果が予期しにくい構文も,ble.shではきちんと装飾されていて助かります。

私はよく仕様書や手引きを読まずに阿呆な勘違いをしてしまうので,今回も「もしかしたら履歴展開されるのが正しいのかも知れない」と思ってBashの手引きを読み回しました。しかしどちらの文法が優先されるかという記述を遂に見付けることができず,issueを立てた次第です。
私の調査不足ではなさそうで安心しました……と言いたいところですが,文法同士の優先度合いが明記されていないのは問題ですよね。

57b42ba 修正です。var=a; echo "${var/[a/b]/c}" がちゃんと着色されないと思ったらケアレスミスでした…。

文法同士の優先度合いが明記されていないのは問題ですよね。

多分、Bash の動作がぐちゃぐちゃ過ぎて、Bash を書いてる Chet 自身も把握できていないレベルなのでは…という気がします。

例えば、以下の物は ble.sh を書いていて発見したものなのですが、Bash 自身も変な動作をします (Bash は何らかの展開をする度に目的に応じて構文解析し直すのですが、新しい構文解析結果が前の構文解析結果と不整合だったりするのです)。こういう状況だと、どちらの構文解釈で着色したとしても、何らかの意味で嘘になってしまうのが難しいところです。

echo [@(echo|[...])]
# 1. 単語の切り出しでは [ + @(echo|[...]) + ] と解釈されるので ) で構文エラーにはならない。
# 2. パス名展開の際には [ + "@(echo|[..." + ] + ")]" と解釈される。

echo {@(,)}
# 1. 単語の切り出しでは { + @(,) + } と解釈される。
# 2. ブレース展開では { + "@(" + , + ")" + } と解釈されて、
#    "@(" と ")" という二つの単語になる。

echo ${var:-{a,b}{a,b}
# 1. ブレース展開を試みる時は ${} の中身は {} を数えてスキップする。
#   ${var:- "{a,b}" "{a,b}" の様に終端されていない ${} と解釈して、
#   ブレース展開は起こらない。
# 2. 実際にパラメータ展開する時は {} を数えずに最初に現れた } で終わるので、
#   ${var:- "{a,b" } "{a,b}" と解釈される。

echo a[]b]=~
# 1. チルダ展開を試みる時、"a" + [] + "b]=~" と解釈する。
#   変数代入形式の引数でないのでチルダ展開は起こらない。
# 2. パス名展開を試みる時は a[ + "]b" + ] + "=~" と解釈して展開を行う。
Was this page helpful?
0 / 5 - 0 ratings